diff --git a/static/js/pointer.js b/static/js/pointer.js index c3a0cb6e6c..2f5f299ab5 100644 --- a/static/js/pointer.js +++ b/static/js/pointer.js @@ -74,6 +74,79 @@ exports.fast_forward_pointer = function () { } }); }; + +exports.keep_pointer_in_view = function () { + // See recenter_view() for related logic to keep the pointer onscreen. + // This function mostly comes into place for mouse scrollers, and it + // keeps the pointer in view. For people who purely scroll with the + // mouse, the pointer is kind of meaningless to them, but keyboard + // users will occasionally do big mouse scrolls, so this gives them + // a pointer reasonably close to the middle of the screen. + var candidate; + var next_row = current_msg_list.selected_row(); + + if (next_row.length === 0) { + return; + } + + var info = viewport.message_viewport_info(); + var top_threshold = info.visible_top + (1/10 * info.visible_height); + var bottom_threshold = info.visible_top + (9/10 * info.visible_height); + + function message_is_far_enough_down() { + if (viewport.at_top()) { + return true; + } + + var message_top = next_row.offset().top; + + // If the message starts after the very top of the screen, we just + // leave it alone. This avoids bugs like #1608, where overzealousness + // about repositioning the pointer can cause users to miss messages. + if (message_top >= info.visible_top) { + return true; + } + + + // If at least part of the message is below top_threshold (10% from + // the top), then we also leave it alone. + var bottom_offset = message_top + next_row.outerHeight(true); + if (bottom_offset >= top_threshold) { + return true; + } + + // If we got this far, the message is not "in view." + return false; + } + + function message_is_far_enough_up() { + return viewport.at_bottom() || + (next_row.offset().top <= bottom_threshold); + } + + function adjust(in_view, get_next_row) { + // return true only if we make an actual adjustment, so + // that we know to short circuit the other direction + if (in_view(next_row)) { + return false; // try other side + } + while (!in_view(next_row)) { + candidate = get_next_row(next_row); + if (candidate.length === 0) { + break; + } + next_row = candidate; + } + return true; + } + + if (!adjust(message_is_far_enough_down, rows.next_visible)) { + adjust(message_is_far_enough_up, rows.prev_visible); + } + + current_msg_list.select_id(rows.id(next_row), {from_scroll: true}); +}; + return exports; }()); if (typeof module !== 'undefined') { diff --git a/static/js/ui.js b/static/js/ui.js index 3d7e24bc6e..b7f2faf4b7 100644 --- a/static/js/ui.js +++ b/static/js/ui.js @@ -509,7 +509,7 @@ function scroll_finished() { if ($('#home').hasClass('active')) { if (!pointer.suppress_scroll_pointer_update) { - keep_pointer_in_view(); + pointer.keep_pointer_in_view(); } else { pointer.suppress_scroll_pointer_update = false; } diff --git a/static/js/zulip.js b/static/js/zulip.js index 52e5970239..5f2a6a39fa 100644 --- a/static/js/zulip.js +++ b/static/js/zulip.js @@ -17,84 +17,12 @@ var queued_flag_timer; // positive means scroll down. var last_viewport_movement_direction = 1; -function keep_pointer_in_view() { - // See recenter_view() for related logic to keep the pointer onscreen. - // This function mostly comes into place for mouse scrollers, and it - // keeps the pointer in view. For people who purely scroll with the - // mouse, the pointer is kind of meaningless to them, but keyboard - // users will occasionally do big mouse scrolls, so this gives them - // a pointer reasonably close to the middle of the screen. - var candidate; - var next_row = current_msg_list.selected_row(); - - if (next_row.length === 0) { - return; - } - - var info = viewport.message_viewport_info(); - var top_threshold = info.visible_top + (1/10 * info.visible_height); - var bottom_threshold = info.visible_top + (9/10 * info.visible_height); - - function message_is_far_enough_down() { - if (viewport.at_top()) { - return true; - } - - var message_top = next_row.offset().top; - - // If the message starts after the very top of the screen, we just - // leave it alone. This avoids bugs like #1608, where overzealousness - // about repositioning the pointer can cause users to miss messages. - if (message_top >= info.visible_top) { - return true; - } - - - // If at least part of the message is below top_threshold (10% from - // the top), then we also leave it alone. - var bottom_offset = message_top + next_row.outerHeight(true); - if (bottom_offset >= top_threshold) { - return true; - } - - // If we got this far, the message is not "in view." - return false; - } - - function message_is_far_enough_up() { - return viewport.at_bottom() || - (next_row.offset().top <= bottom_threshold); - } - - function adjust(in_view, get_next_row) { - // return true only if we make an actual adjustment, so - // that we know to short circuit the other direction - if (in_view(next_row)) { - return false; // try other side - } - while (!in_view(next_row)) { - candidate = get_next_row(next_row); - if (candidate.length === 0) { - break; - } - next_row = candidate; - } - return true; - } - - if (!adjust(message_is_far_enough_down, rows.next_visible)) { - adjust(message_is_far_enough_up, rows.prev_visible); - } - - current_msg_list.select_id(rows.id(next_row), {from_scroll: true}); -} - function recenter_view(message, opts) { opts = opts || {}; // Barnowl-style recentering: if the pointer is too high, move it to // the 1/2 marks. If the pointer is too low, move it to the 1/7 mark. - // See keep_pointer_in_view() for related logic to keep the pointer onscreen. + // See keep_pointer_in_view() in pointer.js for related logic to keep the pointer onscreen. var viewport_info = viewport.message_viewport_info(); var top_threshold = viewport_info.visible_top; diff --git a/tools/jslint/check-all.js b/tools/jslint/check-all.js index 2fe64954e2..f541e8ff60 100644 --- a/tools/jslint/check-all.js +++ b/tools/jslint/check-all.js @@ -54,7 +54,6 @@ var globals = // zulip.js + ' all_msg_list home_msg_list narrowed_msg_list current_msg_list' - + ' keep_pointer_in_view' + ' respond_to_message recenter_view last_viewport_movement_direction' + ' scroll_to_selected get_private_message_recipient' + ' process_loaded_for_unread'