diff --git a/.eslintrc.json b/.eslintrc.json index fce32798fc..cddf306229 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -125,7 +125,6 @@ "files": ["static/js/**"], "globals": { "$": false, - "activity": false, "admin": false, "avatar": false, "blueslip": false, diff --git a/frontend_tests/node_tests/activity.js b/frontend_tests/node_tests/activity.js index 5819d0f850..b1f56f08bd 100644 --- a/frontend_tests/node_tests/activity.js +++ b/frontend_tests/node_tests/activity.js @@ -689,7 +689,7 @@ test_ui("initialize", (override) => { scroll_handler_started = true; }; - activity.client_is_active = false; + activity.__Rewire__("client_is_active", false); $(window).off("focus"); activity.initialize(); @@ -734,25 +734,25 @@ run_test("away_status", () => { }); test_ui("electron_bridge", () => { - activity.client_is_active = false; + activity.__Rewire__("client_is_active", false); window.electron_bridge = undefined; assert.equal(activity.compute_active_status(), activity.IDLE); - activity.client_is_active = true; + activity.__Rewire__("client_is_active", true); assert.equal(activity.compute_active_status(), activity.ACTIVE); window.electron_bridge = { get_idle_on_system: () => true, }; assert.equal(activity.compute_active_status(), activity.IDLE); - activity.client_is_active = false; + activity.__Rewire__("client_is_active", false); assert.equal(activity.compute_active_status(), activity.IDLE); window.electron_bridge = { get_idle_on_system: () => false, }; assert.equal(activity.compute_active_status(), activity.ACTIVE); - activity.client_is_active = true; + activity.__Rewire__("client_is_active", true); assert.equal(activity.compute_active_status(), activity.ACTIVE); }); diff --git a/frontend_tests/node_tests/dispatch.js b/frontend_tests/node_tests/dispatch.js index 76fadea1f7..5148d41663 100644 --- a/frontend_tests/node_tests/dispatch.js +++ b/frontend_tests/node_tests/dispatch.js @@ -20,7 +20,8 @@ const typing_person1 = events.typing_person1; set_global("setTimeout", (func) => func()); -const activity = set_global("activity", {}); +const activity = {__esModule: true}; +rewiremock("../../static/js/activity").with(activity); const alert_words_ui = {__esModule: true}; rewiremock("../../static/js/alert_words_ui").with(alert_words_ui); const attachments_ui = {__esModule: true}; diff --git a/frontend_tests/node_tests/tutorial.js b/frontend_tests/node_tests/tutorial.js index 5acba99bbb..d44d5afb0c 100644 --- a/frontend_tests/node_tests/tutorial.js +++ b/frontend_tests/node_tests/tutorial.js @@ -21,7 +21,8 @@ const {run_test} = require("../zjsunit/test"); set_global("page_params", {}); -const activity = set_global("activity", {}); +const activity = {__esModule: true}; +rewiremock("../../static/js/activity").with(activity); const message_live_update = {__esModule: true}; rewiremock("../../static/js/message_live_update").with(message_live_update); const pm_list = {__esModule: true}; diff --git a/frontend_tests/node_tests/ui_init.js b/frontend_tests/node_tests/ui_init.js index f5d63ffad9..0903b1503a 100644 --- a/frontend_tests/node_tests/ui_init.js +++ b/frontend_tests/node_tests/ui_init.js @@ -67,7 +67,7 @@ page_params.realm_filters = []; page_params.starred_messages = []; page_params.presences = []; -set_global("activity", {initialize() {}}); +rewiremock("../../static/js/activity").with({initialize() {}}); rewiremock("../../static/js/click_handlers").with({initialize() {}}); rewiremock("../../static/js/compose_pm_pill").with({initialize() {}}); rewiremock("../../static/js/drafts").with({initialize() {}}); diff --git a/frontend_tests/node_tests/user_events.js b/frontend_tests/node_tests/user_events.js index 5e2183a4ef..b5759b0dc7 100644 --- a/frontend_tests/node_tests/user_events.js +++ b/frontend_tests/node_tests/user_events.js @@ -7,7 +7,7 @@ const rewiremock = require("rewiremock/node"); const {set_global, zrequire} = require("../zjsunit/namespace"); const {run_test} = require("../zjsunit/test"); -set_global("activity", { +rewiremock("../../static/js/activity").with({ redraw() {}, }); diff --git a/static/js/activity.js b/static/js/activity.js index 8b234697be..cd293db257 100644 --- a/static/js/activity.js +++ b/static/js/activity.js @@ -1,19 +1,20 @@ -"use strict"; +import _ from "lodash"; -const _ = require("lodash"); +import * as buddy_data from "./buddy_data"; +import {buddy_list} from "./buddy_list"; +import * as channel from "./channel"; +import * as keydown_util from "./keydown_util"; +import {ListCursor} from "./list_cursor"; +import * as people from "./people"; +import * as pm_list from "./pm_list"; +import * as popovers from "./popovers"; +import * as presence from "./presence"; +import * as server_events from "./server_events"; +import {UserSearch} from "./user_search"; +import * as user_status from "./user_status"; -const buddy_data = require("./buddy_data"); -const {buddy_list} = require("./buddy_list"); -const channel = require("./channel"); -const keydown_util = require("./keydown_util"); -const {ListCursor} = require("./list_cursor"); -const people = require("./people"); -const pm_list = require("./pm_list"); -const popovers = require("./popovers"); -const presence = require("./presence"); -const server_events = require("./server_events"); -const {UserSearch} = require("./user_search"); -const user_status = require("./user_status"); +export let user_cursor; +export let user_filter; /* Helpers for detecting user activity and managing user idle states @@ -25,24 +26,26 @@ const DEFAULT_IDLE_TIMEOUT_MS = 5 * 60 * 1000; const ACTIVE_PING_INTERVAL_MS = 50 * 1000; /* Keep in sync with views.py:update_active_status_backend() */ -exports.ACTIVE = "active"; -exports.IDLE = "idle"; +export const ACTIVE = "active"; + +export const IDLE = "idle"; // When you open Zulip in a new browser window, client_is_active // should be true. When a server-initiated reload happens, however, // it should be initialized to false. We handle this with a check for // whether the window is focused at initialization time. -exports.client_is_active = document.hasFocus && document.hasFocus(); +export let client_is_active = document.hasFocus && document.hasFocus(); // new_user_input is a more strict version of client_is_active used // primarily for analytics. We initialize this to true, to count new // page loads, but set it to false in the onload function in reload.js // if this was a server-initiated-reload to avoid counting a // server-initiated reload as user activity. -exports.new_user_input = true; -exports.set_new_user_input = function (value) { - exports.new_user_input = value; -}; +export let new_user_input = true; + +export function set_new_user_input(value) { + new_user_input = value; +} function update_pm_count_in_dom(count_span, value_span, count) { const li = count_span.parents("li"); @@ -71,7 +74,7 @@ function set_pm_count(user_ids_string, count) { update_pm_count_in_dom(count_span, value_span, count); } -exports.update_dom_with_unread_counts = function (counts) { +export function update_dom_with_unread_counts(counts) { // counts is just a data object that gets calculated elsewhere // Our job is to update some DOM elements. @@ -82,21 +85,21 @@ exports.update_dom_with_unread_counts = function (counts) { set_pm_count(user_ids_string, count); } } -}; +} function mark_client_idle() { // When we become idle, we don't immediately send anything to the // server; instead, we wait for our next periodic update, since // this data is fundamentally not timely. - exports.client_is_active = false; + client_is_active = false; } -exports.redraw_user = function (user_id) { +export function redraw_user(user_id) { if (page_params.realm_presence_disabled) { return; } - const filter_text = exports.get_filter_text(); + const filter_text = get_filter_text(); if (!buddy_data.matches_filter(filter_text, user_id)) { return; @@ -108,18 +111,18 @@ exports.redraw_user = function (user_id) { key: user_id, item: info, }); -}; +} -exports.searching = function () { - return exports.user_filter && exports.user_filter.searching(); -}; +export function searching() { + return user_filter && user_filter.searching(); +} -exports.build_user_sidebar = function () { +export function build_user_sidebar() { if (page_params.realm_presence_disabled) { return undefined; } - const filter_text = exports.get_filter_text(); + const filter_text = get_filter_text(); const user_ids = buddy_data.get_filtered_and_sorted_user_ids(filter_text); @@ -128,19 +131,19 @@ exports.build_user_sidebar = function () { }); return user_ids; // for testing -}; +} function do_update_users_for_search() { // Hide all the popovers but not userlist sidebar // when the user is searching. popovers.hide_all_except_sidebars(); - exports.build_user_sidebar(); - exports.user_cursor.reset(); + build_user_sidebar(); + user_cursor.reset(); } const update_users_for_search = _.throttle(do_update_users_for_search, 50); -exports.compute_active_status = function () { +export function compute_active_status() { // The overall algorithm intent for the `status` field is to send // `ACTIVE` (aka green circle) if we know the user is at their // computer, and IDLE (aka orange circle) if the user might not @@ -157,18 +160,18 @@ exports.compute_active_status = function () { window.electron_bridge.get_idle_on_system !== undefined ) { if (window.electron_bridge.get_idle_on_system()) { - return exports.IDLE; + return IDLE; } - return exports.ACTIVE; + return ACTIVE; } - if (exports.client_is_active) { - return exports.ACTIVE; + if (client_is_active) { + return ACTIVE; } - return exports.IDLE; -}; + return IDLE; +} -exports.send_presence_to_server = function (want_redraw) { +export function send_presence_to_server(want_redraw) { // Zulip has 2 data feeds coming from the server to the client: // The server_events data, and this presence feed. Data from // server_events is nicely serialized, but if we've been offline @@ -194,9 +197,9 @@ exports.send_presence_to_server = function (want_redraw) { channel.post({ url: "/json/users/me/presence", data: { - status: exports.compute_active_status(), + status: compute_active_status(), ping_only: !want_redraw, - new_user_input: exports.new_user_input, + new_user_input, slim_presence: true, }, idempotent: true, @@ -208,26 +211,26 @@ exports.send_presence_to_server = function (want_redraw) { $("#zephyr-mirror-error").removeClass("show"); } - exports.new_user_input = false; + new_user_input = false; if (want_redraw) { presence.set_info(data.presences, data.server_timestamp); - exports.redraw(); + redraw(); } }, }); -}; +} function mark_client_active() { - if (!exports.client_is_active) { - exports.client_is_active = true; - exports.send_presence_to_server(false); + if (!client_is_active) { + client_is_active = true; + send_presence_to_server(false); } } -exports.initialize = function () { +export function initialize() { $("html").on("mousemove", () => { - exports.new_user_input = true; + new_user_input = true; }); $(window).on("focus", mark_client_active); @@ -238,91 +241,91 @@ exports.initialize = function () { keepTracking: true, }); - exports.set_cursor_and_filter(); + set_cursor_and_filter(); - exports.build_user_sidebar(); + build_user_sidebar(); buddy_list.start_scroll_handler(); // Let the server know we're here, but pass "false" for // want_redraw, since we just got all this info in page_params. - exports.send_presence_to_server(false); + send_presence_to_server(false); function get_full_presence_list_update() { - exports.send_presence_to_server(true); + send_presence_to_server(true); } setInterval(get_full_presence_list_update, ACTIVE_PING_INTERVAL_MS); -}; +} -exports.update_presence_info = function (user_id, info, server_time) { +export function update_presence_info(user_id, info, server_time) { presence.update_info_from_event(user_id, info, server_time); - exports.redraw_user(user_id); + redraw_user(user_id); pm_list.update_private_messages(); -}; +} -exports.on_set_away = function (user_id) { +export function on_set_away(user_id) { user_status.set_away(user_id); - exports.redraw_user(user_id); + redraw_user(user_id); pm_list.update_private_messages(); -}; +} -exports.on_revoke_away = function (user_id) { +export function on_revoke_away(user_id) { user_status.revoke_away(user_id); - exports.redraw_user(user_id); + redraw_user(user_id); pm_list.update_private_messages(); -}; +} -exports.redraw = function () { - exports.build_user_sidebar(); - exports.user_cursor.redraw(); +export function redraw() { + build_user_sidebar(); + user_cursor.redraw(); pm_list.update_private_messages(); -}; +} -exports.reset_users = function () { +export function reset_users() { // Call this when we're leaving the search widget. - exports.build_user_sidebar(); - exports.user_cursor.clear(); -}; + build_user_sidebar(); + user_cursor.clear(); +} -exports.narrow_for_user = function (opts) { +export function narrow_for_user(opts) { const user_id = buddy_list.get_key_from_li({li: opts.li}); - return exports.narrow_for_user_id({user_id}); -}; + return narrow_for_user_id({user_id}); +} -exports.narrow_for_user_id = function (opts) { +export function narrow_for_user_id(opts) { const person = people.get_by_user_id(opts.user_id); const email = person.email; narrow.by("pm-with", email, {trigger: "sidebar"}); - exports.user_filter.clear_and_hide_search(); -}; + user_filter.clear_and_hide_search(); +} function keydown_enter_key() { - const user_id = exports.user_cursor.get_key(); + const user_id = user_cursor.get_key(); if (user_id === undefined) { return; } - exports.narrow_for_user_id({user_id}); + narrow_for_user_id({user_id}); popovers.hide_all(); } -exports.set_cursor_and_filter = function () { - exports.user_cursor = new ListCursor({ +export function set_cursor_and_filter() { + user_cursor = new ListCursor({ list: buddy_list, highlight_class: "highlighted_user", }); - exports.user_filter = new UserSearch({ + user_filter = new UserSearch({ update_list: update_users_for_search, - reset_items: exports.reset_users, - on_focus: () => exports.user_cursor.reset(), + reset_items: reset_users, + on_focus: () => user_cursor.reset(), }); - const $input = exports.user_filter.input_field(); + const $input = user_filter.input_field(); - $input.on("blur", () => exports.user_cursor.clear()); + $input.on("blur", () => user_cursor.clear()); keydown_util.handle({ elem: $input, @@ -332,31 +335,31 @@ exports.set_cursor_and_filter = function () { return true; }, up_arrow() { - exports.user_cursor.prev(); + user_cursor.prev(); return true; }, down_arrow() { - exports.user_cursor.next(); + user_cursor.next(); return true; }, }, }); -}; +} -exports.initiate_search = function () { - if (exports.user_filter) { - exports.user_filter.initiate_search(); +export function initiate_search() { + if (user_filter) { + user_filter.initiate_search(); } -}; +} -exports.escape_search = function () { - if (exports.user_filter) { - exports.user_filter.escape_search(); +export function escape_search() { + if (user_filter) { + user_filter.escape_search(); } -}; +} -exports.get_filter_text = function () { - if (!exports.user_filter) { +export function get_filter_text() { + if (!user_filter) { // This may be overly defensive, but there may be // situations where get called before everything is // fully initialized. The empty string is a fine @@ -365,7 +368,5 @@ exports.get_filter_text = function () { return ""; } - return exports.user_filter.text(); -}; - -window.activity = exports; + return user_filter.text(); +} diff --git a/static/js/bundles/app.js b/static/js/bundles/app.js index b293a42bd8..83fbabff45 100644 --- a/static/js/bundles/app.js +++ b/static/js/bundles/app.js @@ -33,7 +33,6 @@ import "../notifications"; import "../message_events"; import "../server_events"; import "../zulip"; -import "../activity"; import "../user_events"; import "../timerender"; import "../hotspots"; diff --git a/static/js/click_handlers.js b/static/js/click_handlers.js index 05dd94775d..b0e44dbf15 100644 --- a/static/js/click_handlers.js +++ b/static/js/click_handlers.js @@ -6,6 +6,7 @@ import WinChan from "winchan"; import render_buddy_list_tooltip from "../templates/buddy_list_tooltip.hbs"; import render_buddy_list_tooltip_content from "../templates/buddy_list_tooltip_content.hbs"; +import * as activity from "./activity"; import * as buddy_data from "./buddy_data"; import * as channel from "./channel"; import * as compose from "./compose"; diff --git a/static/js/global.d.ts b/static/js/global.d.ts index 916a23542c..8a21ba1e77 100644 --- a/static/js/global.d.ts +++ b/static/js/global.d.ts @@ -3,7 +3,6 @@ // remove each declaration when the corresponding module is migrated // to TS. -declare let activity: any; declare let admin: any; declare let avatar: any; declare let blueslip: any; diff --git a/static/js/hotkey.js b/static/js/hotkey.js index 605caa6638..14a0af3e36 100644 --- a/static/js/hotkey.js +++ b/static/js/hotkey.js @@ -1,5 +1,6 @@ import * as emoji from "../shared/js/emoji"; +import * as activity from "./activity"; import * as common from "./common"; import * as compose from "./compose"; import * as compose_state from "./compose_state"; diff --git a/static/js/message_list_view.js b/static/js/message_list_view.js index ace2bf9a2b..fc518739e7 100644 --- a/static/js/message_list_view.js +++ b/static/js/message_list_view.js @@ -6,6 +6,7 @@ import render_message_group from "../templates/message_group.hbs"; import render_recipient_row from "../templates/recipient_row.hbs"; import render_single_message from "../templates/single_message.hbs"; +import * as activity from "./activity"; import * as compose from "./compose"; import * as compose_fade from "./compose_fade"; import * as condense from "./condense"; diff --git a/static/js/reload.js b/static/js/reload.js index 7ddd2144f3..ea9d4fff4e 100644 --- a/static/js/reload.js +++ b/static/js/reload.js @@ -1,3 +1,4 @@ +import * as activity from "./activity"; import * as compose from "./compose"; import * as compose_state from "./compose_state"; import * as hashchange from "./hashchange"; diff --git a/static/js/server_events_dispatch.js b/static/js/server_events_dispatch.js index d8b09384c6..5ad84836de 100644 --- a/static/js/server_events_dispatch.js +++ b/static/js/server_events_dispatch.js @@ -1,5 +1,6 @@ import * as emoji from "../shared/js/emoji"; +import * as activity from "./activity"; import * as alert_words from "./alert_words"; import * as alert_words_ui from "./alert_words_ui"; import * as attachments_ui from "./attachments_ui"; diff --git a/static/js/ui_init.js b/static/js/ui_init.js index d242005213..932739035e 100644 --- a/static/js/ui_init.js +++ b/static/js/ui_init.js @@ -8,6 +8,7 @@ const emoji = require("../shared/js/emoji"); const fenced_code = require("../shared/js/fenced_code"); const render_edit_content_button = require("../templates/edit_content_button.hbs"); +const activity = require("./activity"); const alert_words = require("./alert_words"); const click_handlers = require("./click_handlers"); const compose = require("./compose"); diff --git a/static/js/unread_ui.js b/static/js/unread_ui.js index ed95b85d56..62f0be22b6 100644 --- a/static/js/unread_ui.js +++ b/static/js/unread_ui.js @@ -1,3 +1,4 @@ +import * as activity from "./activity"; import * as notifications from "./notifications"; import * as pm_list from "./pm_list"; import * as top_left_corner from "./top_left_corner"; diff --git a/static/js/user_events.js b/static/js/user_events.js index d3b5569af0..bec827753b 100644 --- a/static/js/user_events.js +++ b/static/js/user_events.js @@ -4,6 +4,7 @@ // server_events.js simple while breaking some circular // dependencies that existed when this code was in people.js. // (We should do bot updates here too.) +const activity = require("./activity"); const compose = require("./compose"); const gear_menu = require("./gear_menu"); const message_live_update = require("./message_live_update");