diff --git a/static/js/ui.js b/static/js/ui.js
index 3a408035c0..9d3be1d0e3 100644
--- a/static/js/ui.js
+++ b/static/js/ui.js
@@ -90,50 +90,6 @@ exports.replace_emoji_with_text = function (element) {
});
};
-/* We use 'visibility' rather than 'display' and jQuery's show() / hide(),
- because we want to reserve space for the email address. This avoids
- things jumping around slightly when the email address is shown. */
-
-var current_message_hover;
-function message_unhover() {
- if (current_message_hover === undefined) {
- return;
- }
- current_message_hover.find('span.edit_content').html("");
- current_message_hover.removeClass('message_hovered');
- current_message_hover = undefined;
-}
-
-function message_hover(message_row) {
- var message;
-
- var id = parseInt(message_row.attr("zid"), 10);
- if (current_message_hover && message_row && current_message_hover.attr("zid") === message_row.attr("zid")) {
- return;
- }
- // Don't allow on-hover editing for local-only messages
- if (message_row.hasClass('local')) {
- return;
- }
- message = current_msg_list.get(rows.id(message_row));
- message_unhover();
- message_row.addClass('message_hovered');
- current_message_hover = message_row;
-
- if (!message.sent_by_me) {
- // The actions and reactions icon hover logic is handled entirely by CSS
- return;
- }
-
- // But the message edit hover icon is determined by whether the message is still editablex
- if ((message_edit.get_editability(message) === message_edit.editability_types.FULL) &&
- !message.status_message) {
- message_row.find(".edit_content").html('');
- } else {
- message_row.find(".edit_content").html('');
- }
-}
-
/* Arguments used in the report_* functions are,
response- response that we want to display
status_box- element being used to display the response
@@ -327,198 +283,6 @@ exports.switchToFullWidth = function () {
/* END OF EXPERIMENTS */
-$(function () {
- var throttled_mousewheelhandler = $.throttle(50, function (e, delta) {
- // Most of the mouse wheel's work will be handled by the
- // scroll handler, but when we're at the top or bottom of the
- // page, the pointer may still need to move.
-
- if (delta > 0) {
- if (message_viewport.at_top()) {
- navigate.up();
- }
- } else if (delta < 0) {
- if (message_viewport.at_bottom()) {
- navigate.down();
- }
- }
-
- message_viewport.last_movement_direction = delta;
- });
-
- message_viewport.message_pane.mousewheel(function (e, delta) {
- if (!exports.home_tab_obscured()) {
- // In the message view, we use a throttled mousewheel handler.
- throttled_mousewheelhandler(e, delta);
- }
- // If in a modal, we neither handle the event nor
- // preventDefault, allowing the modal to scroll normally.
- });
-
- $(window).resize($.throttle(50, resize.handler));
-
- // Scrolling in modals, input boxes, and other elements that
- // explicitly scroll should not scroll the main view. Stop
- // propagation in all cases. Also, ignore the event if the
- // element is already at the top or bottom. Otherwise we get a
- // new scroll event on the parent (?).
- $('.modal-body, .scrolling_list, input, textarea').mousewheel(function (e, delta) {
- var self = $(this);
- var scroll = self.scrollTop();
-
- // The -1 fudge factor is important here due to rounding errors. Better
- // to err on the side of not scrolling.
- var max_scroll = this.scrollHeight - self.innerHeight() - 1;
-
- e.stopPropagation();
- if ( ((delta > 0) && (scroll <= 0))
- || ((delta < 0) && (scroll >= max_scroll))) {
- e.preventDefault();
- }
- });
-
- // Override the #compose mousewheel prevention below just for the emoji box
- $('.emoji_popover').mousewheel(function (e) {
- e.stopPropagation();
- });
-
- // Ignore wheel events in the compose area which weren't already handled above.
- $('#compose').mousewheel(function (e) {
- e.stopPropagation();
- e.preventDefault();
- });
-
- // A little hackish, because it doesn't seem to totally get us the
- // exact right width for the floating_recipient_bar and compose
- // box, but, close enough for now.
- resize.handler();
-
- if (!page_params.left_side_userlist) {
- $("#navbar-buttons").addClass("right-userlist");
- }
-
- $("#main_div").on("mouseover", ".message_row", function () {
- var row = $(this).closest(".message_row");
- message_hover(row);
- });
-
- $("#main_div").on("mouseleave", ".message_row", function () {
- message_unhover();
- });
-
- $("#main_div").on("mouseover", ".message_sender", function () {
- var row = $(this).closest(".message_row");
- row.addClass("sender_name_hovered");
- });
-
- $("#main_div").on("mouseout", ".message_sender", function () {
- var row = $(this).closest(".message_row");
- row.removeClass("sender_name_hovered");
- });
-
- $("#subscriptions_table").on("mouseover", ".subscription_header", function () {
- $(this).addClass("active");
- });
-
- $("#subscriptions_table").on("mouseout", ".subscription_header", function () {
- $(this).removeClass("active");
- });
-
- $("#stream").on('blur', function () { compose.decorate_stream_bar(this.value); });
-
- $(window).on('blur', function () {
- $(document.body).addClass('window_blurred');
- });
-
- $(window).on('focus', function () {
- $(document.body).removeClass('window_blurred');
- });
-
- $(document).on('message_selected.zulip', function (event) {
- if (current_msg_list !== event.msg_list) {
- return;
- }
- if (event.id === -1) {
- // If the message list is empty, don't do anything
- return;
- }
- var row = event.msg_list.get_row(event.id);
- $('.selected_message').removeClass('selected_message');
- row.addClass('selected_message');
-
- if (event.then_scroll) {
- if (row.length === 0) {
- var row_from_dom = current_msg_list.get_row(event.id);
- blueslip.debug("message_selected missing selected row", {
- previously_selected: event.previously_selected,
- selected_id: event.id,
- selected_idx: event.msg_list.selected_idx(),
- selected_idx_exact: event.msg_list._items.indexOf(event.msg_list.get(event.id)),
- render_start: event.msg_list.view._render_win_start,
- render_end: event.msg_list.view._render_win_end,
- selected_id_from_idx: event.msg_list._items[event.msg_list.selected_idx()].id,
- msg_list_sorted: _.isEqual(
- _.pluck(event.msg_list._items, 'id'),
- _.chain(current_msg_list._items).pluck('id').clone().value().sort()
- ),
- found_in_dom: row_from_dom.length,
- });
- }
- if (event.target_scroll_offset !== undefined) {
- message_viewport.set_message_offset(event.target_scroll_offset);
- } else {
- // Scroll to place the message within the current view;
- // but if this is the initial placement of the pointer,
- // just place it in the very center
- message_viewport.recenter_view(row, {from_scroll: event.from_scroll,
- force_center: event.previously_selected === -1});
- }
- }
- });
-
- $("#main_div").on("mouseenter", ".message_time", function (e) {
- var time_elem = $(e.target);
- var row = time_elem.closest(".message_row");
- var message = current_msg_list.get(rows.id(row));
- timerender.set_full_datetime(message, time_elem);
- });
-
- $('#streams_header h4').tooltip({ placement: 'right',
- animation: false });
-
- $('#streams_header i[data-toggle="tooltip"]').tooltip({ placement: 'left',
- animation: false });
-
- $('.message_failed i[data-toggle="tooltip"]').tooltip();
-
- if (!page_params.realm_allow_message_editing) {
- $("#edit-message-hotkey-help").hide();
- }
-
- if (page_params.realm_presence_disabled) {
- $("#user-list").hide();
- $("#group-pm-list").hide();
- }
-
- if (feature_flags.full_width) {
- exports.switchToFullWidth();
- }
-
- // initialize other stuff
- reload.initialize();
- composebox_typeahead.initialize();
- search.initialize();
- tutorial.initialize();
- notifications.initialize();
- gear_menu.initialize();
- hashchange.initialize();
- pointer.initialize();
- unread_ui.initialize();
- activity.initialize();
- emoji.initialize();
-});
-
-
function scroll_finished() {
actively_scrolling = false;
diff --git a/static/js/ui_init.js b/static/js/ui_init.js
new file mode 100644
index 0000000000..1f400d2667
--- /dev/null
+++ b/static/js/ui_init.js
@@ -0,0 +1,243 @@
+(function () {
+
+// This is where most of our initialization takes place.
+// TODO: Organize it a lot better. In particular, move bigger
+// functions to other modules.
+
+/* We use 'visibility' rather than 'display' and jQuery's show() / hide(),
+ because we want to reserve space for the email address. This avoids
+ things jumping around slightly when the email address is shown. */
+
+var current_message_hover;
+function message_unhover() {
+ if (current_message_hover === undefined) {
+ return;
+ }
+ current_message_hover.find('span.edit_content').html("");
+ current_message_hover.removeClass('message_hovered');
+ current_message_hover = undefined;
+}
+
+function message_hover(message_row) {
+ var message;
+
+ var id = parseInt(message_row.attr("zid"), 10);
+ if (current_message_hover && message_row && current_message_hover.attr("zid") === message_row.attr("zid")) {
+ return;
+ }
+ // Don't allow on-hover editing for local-only messages
+ if (message_row.hasClass('local')) {
+ return;
+ }
+ message = current_msg_list.get(rows.id(message_row));
+ message_unhover();
+ message_row.addClass('message_hovered');
+ current_message_hover = message_row;
+
+ if (!message.sent_by_me) {
+ // The actions and reactions icon hover logic is handled entirely by CSS
+ return;
+ }
+
+ // But the message edit hover icon is determined by whether the message is still editablex
+ if ((message_edit.get_editability(message) === message_edit.editability_types.FULL) &&
+ !message.status_message) {
+ message_row.find(".edit_content").html('');
+ } else {
+ message_row.find(".edit_content").html('');
+ }
+}
+
+$(function () {
+ var throttled_mousewheelhandler = $.throttle(50, function (e, delta) {
+ // Most of the mouse wheel's work will be handled by the
+ // scroll handler, but when we're at the top or bottom of the
+ // page, the pointer may still need to move.
+
+ if (delta > 0) {
+ if (message_viewport.at_top()) {
+ navigate.up();
+ }
+ } else if (delta < 0) {
+ if (message_viewport.at_bottom()) {
+ navigate.down();
+ }
+ }
+
+ message_viewport.last_movement_direction = delta;
+ });
+
+ message_viewport.message_pane.mousewheel(function (e, delta) {
+ if (!ui.home_tab_obscured()) {
+ // In the message view, we use a throttled mousewheel handler.
+ throttled_mousewheelhandler(e, delta);
+ }
+ // If in a modal, we neither handle the event nor
+ // preventDefault, allowing the modal to scroll normally.
+ });
+
+ $(window).resize($.throttle(50, resize.handler));
+
+ // Scrolling in modals, input boxes, and other elements that
+ // explicitly scroll should not scroll the main view. Stop
+ // propagation in all cases. Also, ignore the event if the
+ // element is already at the top or bottom. Otherwise we get a
+ // new scroll event on the parent (?).
+ $('.modal-body, .scrolling_list, input, textarea').mousewheel(function (e, delta) {
+ var self = $(this);
+ var scroll = self.scrollTop();
+
+ // The -1 fudge factor is important here due to rounding errors. Better
+ // to err on the side of not scrolling.
+ var max_scroll = this.scrollHeight - self.innerHeight() - 1;
+
+ e.stopPropagation();
+ if ( ((delta > 0) && (scroll <= 0))
+ || ((delta < 0) && (scroll >= max_scroll))) {
+ e.preventDefault();
+ }
+ });
+
+ // Override the #compose mousewheel prevention below just for the emoji box
+ $('.emoji_popover').mousewheel(function (e) {
+ e.stopPropagation();
+ });
+
+ // Ignore wheel events in the compose area which weren't already handled above.
+ $('#compose').mousewheel(function (e) {
+ e.stopPropagation();
+ e.preventDefault();
+ });
+
+ // A little hackish, because it doesn't seem to totally get us the
+ // exact right width for the floating_recipient_bar and compose
+ // box, but, close enough for now.
+ resize.handler();
+
+ if (!page_params.left_side_userlist) {
+ $("#navbar-buttons").addClass("right-userlist");
+ }
+
+ $("#main_div").on("mouseover", ".message_row", function () {
+ var row = $(this).closest(".message_row");
+ message_hover(row);
+ });
+
+ $("#main_div").on("mouseleave", ".message_row", function () {
+ message_unhover();
+ });
+
+ $("#main_div").on("mouseover", ".message_sender", function () {
+ var row = $(this).closest(".message_row");
+ row.addClass("sender_name_hovered");
+ });
+
+ $("#main_div").on("mouseout", ".message_sender", function () {
+ var row = $(this).closest(".message_row");
+ row.removeClass("sender_name_hovered");
+ });
+
+ $("#subscriptions_table").on("mouseover", ".subscription_header", function () {
+ $(this).addClass("active");
+ });
+
+ $("#subscriptions_table").on("mouseout", ".subscription_header", function () {
+ $(this).removeClass("active");
+ });
+
+ $("#stream").on('blur', function () { compose.decorate_stream_bar(this.value); });
+
+ $(window).on('blur', function () {
+ $(document.body).addClass('window_blurred');
+ });
+
+ $(window).on('focus', function () {
+ $(document.body).removeClass('window_blurred');
+ });
+
+ $(document).on('message_selected.zulip', function (event) {
+ if (current_msg_list !== event.msg_list) {
+ return;
+ }
+ if (event.id === -1) {
+ // If the message list is empty, don't do anything
+ return;
+ }
+ var row = event.msg_list.get_row(event.id);
+ $('.selected_message').removeClass('selected_message');
+ row.addClass('selected_message');
+
+ if (event.then_scroll) {
+ if (row.length === 0) {
+ var row_from_dom = current_msg_list.get_row(event.id);
+ blueslip.debug("message_selected missing selected row", {
+ previously_selected: event.previously_selected,
+ selected_id: event.id,
+ selected_idx: event.msg_list.selected_idx(),
+ selected_idx_exact: event.msg_list._items.indexOf(event.msg_list.get(event.id)),
+ render_start: event.msg_list.view._render_win_start,
+ render_end: event.msg_list.view._render_win_end,
+ selected_id_from_idx: event.msg_list._items[event.msg_list.selected_idx()].id,
+ msg_list_sorted: _.isEqual(
+ _.pluck(event.msg_list._items, 'id'),
+ _.chain(current_msg_list._items).pluck('id').clone().value().sort()
+ ),
+ found_in_dom: row_from_dom.length,
+ });
+ }
+ if (event.target_scroll_offset !== undefined) {
+ message_viewport.set_message_offset(event.target_scroll_offset);
+ } else {
+ // Scroll to place the message within the current view;
+ // but if this is the initial placement of the pointer,
+ // just place it in the very center
+ message_viewport.recenter_view(row, {from_scroll: event.from_scroll,
+ force_center: event.previously_selected === -1});
+ }
+ }
+ });
+
+ $("#main_div").on("mouseenter", ".message_time", function (e) {
+ var time_elem = $(e.target);
+ var row = time_elem.closest(".message_row");
+ var message = current_msg_list.get(rows.id(row));
+ timerender.set_full_datetime(message, time_elem);
+ });
+
+ $('#streams_header h4').tooltip({ placement: 'right',
+ animation: false });
+
+ $('#streams_header i[data-toggle="tooltip"]').tooltip({ placement: 'left',
+ animation: false });
+
+ $('.message_failed i[data-toggle="tooltip"]').tooltip();
+
+ if (!page_params.realm_allow_message_editing) {
+ $("#edit-message-hotkey-help").hide();
+ }
+
+ if (page_params.realm_presence_disabled) {
+ $("#user-list").hide();
+ $("#group-pm-list").hide();
+ }
+
+ if (feature_flags.full_width) {
+ ui.switchToFullWidth();
+ }
+
+ // initialize other stuff
+ reload.initialize();
+ composebox_typeahead.initialize();
+ search.initialize();
+ tutorial.initialize();
+ notifications.initialize();
+ gear_menu.initialize();
+ hashchange.initialize();
+ pointer.initialize();
+ unread_ui.initialize();
+ activity.initialize();
+ emoji.initialize();
+});
+
+
+}());
diff --git a/zproject/settings.py b/zproject/settings.py
index 508670c68c..b38c0b1f28 100644
--- a/zproject/settings.py
+++ b/zproject/settings.py
@@ -894,6 +894,7 @@ JS_SPECS = {
'js/bot_data.js',
'js/reactions.js',
'js/typing.js',
+ 'js/ui_init.js',
'js/shim.js',
# JS bundled by webpack is also included here if PIPELINE_ENABLED setting is true
],