Files
zulip/zephyr/static/js/ui.js
Waseem Daher 22099dfe9f Fix scrolling bug related to resize.
When Bootstrap shrinks the divs down into 'tablet' mode, our selected
message might end up being even lower in the screen than it was before
(because more text wraps). But our scrollbar does not automatically
advance to keep it in view -- so we do it manually.

This implementation is a little hackish in that it does some
unnecessary recenter_view-ing in big views (which can be a touch
disorienting) to optimize recentering on resizing for small views.

If that behavior is annoying, we can deal with it by being
smarter about when we trigger the recenter code.

(imported from commit 6834e11f7a37833982c388f15174df661d7f55b3)
2012-10-12 00:17:24 -04:00

269 lines
9.4 KiB
JavaScript

// We want to remember how far we were scrolled on each 'tab'.
// To do so, we need to save away the old position of the
// scrollbar when we switch to a new tab (and restore it
// when we switch back.)
var scroll_positions = {};
function register_onclick(message_row, message_id) {
message_row.find(".messagebox").click(function (e) {
if (!(clicking && mouse_moved)) {
// Was a click (not a click-and-drag).
select_message_by_id(message_id);
respond_to_message();
}
mouse_moved = false;
clicking = false;
});
}
function focus_on(field_id) {
// Call after autocompleting on a field, to advance the focus to
// the next input field.
// Bootstrap's typeahead does not expose a callback for when an
// autocomplete selection has been made, so we have to do this
// manually.
$("#" + field_id).focus();
}
/* 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. */
function hide_email() {
$('.sender_email').addClass('invisible');
}
function show_email(message_id) {
hide_email();
get_message_row(message_id).find('.sender_email').removeClass('invisible');
}
function report_error(response, xhr, status_box) {
if (xhr.status.toString().charAt(0) === "4") {
// Only display the error response for 4XX, where we've crafted
// a nice response.
response += ": " + $.parseJSON(xhr.responseText).msg;
}
status_box.removeClass(status_classes).addClass('alert-error')
.text(response).stop(true).fadeTo(0, 1);
status_box.show();
}
function report_success(response, status_box) {
status_box.removeClass(status_classes).addClass('alert-success')
.text(response).stop(true).fadeTo(0, 1);
status_box.show();
}
var clicking = false;
var mouse_moved = false;
function mousedown() {
mouse_moved = false;
clicking = true;
}
function mousemove() {
if (clicking) {
mouse_moved = true;
}
}
function resizehandler(e) {
var viewport = $(window);
var sidebar = $("#sidebar");
var narrowcontent = $(".narrowcontent");
var sidebar_nav = $(".sidebar-nav");
var composebox = $("#compose");
var narrowbox = $("#narrowbox");
if (viewport.width() <= 767) {
sidebar.removeClass('nav-stacked');
var space_taken_up_by_navbar = sidebar_nav.outerHeight(true);
$("#nav_whitespace").height(space_taken_up_by_navbar); // .visible-phone only, so doesn't need undoing
narrowbox.css('top', space_taken_up_by_navbar);
var message_list_width = $("#main_div").outerWidth();
composebox.width(message_list_width);
// narrowcontent has padding and a border, so we need to
// subtract those out when we set the width
var border_and_padding = narrowcontent.outerWidth() - narrowcontent.width();
narrowcontent.width(message_list_width - border_and_padding);
sidebar_nav.width(message_list_width);
} else {
sidebar.addClass('nav-stacked');
narrowbox.css('top', 0);
composebox.width('');
narrowcontent.width('');
sidebar_nav.width('');
}
// This function might run onReady (if we're in a narrow window),
// but before we've loaded in the messages; in that case, don't
// try to scroll to one.
if (selected_message_id !== -1) {
scroll_to_selected();
}
}
var autocomplete_needs_update = false;
function update_autocomplete() {
stream_list.sort();
subject_list.sort();
people_list.sort();
// limit number of items so the list doesn't fall off the screen
$( "#stream" ).typeahead({
source: stream_list,
items: 3
});
$( "#subject" ).typeahead({
source: subject_list,
items: 2
});
$( "#huddle_recipient" ).typeahead({
source: people_list,
items: 4,
matcher: function (item) {
// Assumes we are matching on email addresses, not
// e.g. full names which would have spaces.
var current_recipient = $(this.query.split(" ")).last()[0];
// Case-insensitive (from Bootstrap's default matcher).
return (item.toLowerCase().indexOf(current_recipient.toLowerCase()) !== -1);
},
updater: function (item) {
var previous_recipients = this.query.split(" ");
previous_recipients.pop();
previous_recipients = previous_recipients.join(" ");
if (previous_recipients.length !== 0) {
previous_recipients += " ";
}
return previous_recipients + item;
}
});
autocomplete_needs_update = false;
}
$(function () {
// NB: This just binds to current elements, and won't bind to elements
// created after ready() is called.
$('#message-type-tabs a[href="#stream-message"]').on('shown', function (e) {
$('#personal-message').hide();
$('#stream-message').show();
$('#new_message_type').val('stream');
$("#send-status").removeClass(status_classes).hide();
focus_on("stream");
});
$('#message-type-tabs a[href="#personal-message"]').on('shown', function (e) {
$('#personal-message').show();
$('#stream-message').hide();
$('#new_message_type').val('personal');
$("#send-status").removeClass(status_classes).hide();
focus_on("huddle_recipient");
});
// Prepare the click handler for subbing to a new stream to which
// you have composed a message.
$('#create-it').click(function () {
sub_from_home(compose_stream_name(), $('#stream-dne'));
});
// Prepare the click handler for subbing to an existing stream.
$('#sub-it').click(function () {
sub_from_home(compose_stream_name(), $('#stream-nosub'));
});
var throttled_scrollhandler = $.throttle(50, function(e) {
if ($('#home').hasClass('active')) {
keep_pointer_in_view();
if (e.type === 'mousewheel') {
// If we mousewheel (or trackpad-scroll) when
// we're at the top and bottom of the page, the
// pointer may still want to move.
move_pointer_at_page_top_and_bottom();
}
}
});
$(window).mousewheel(throttled_scrollhandler);
$(window).scroll(throttled_scrollhandler);
var throttled_resizehandler = $.throttle(50, resizehandler);
$(window).resize(throttled_resizehandler);
$('#sidebar a[data-toggle="pill"]').on('show', function (e) {
// Save the position of our old tab away, before we switch
var viewport = $(window);
var old_tab = $(e.relatedTarget).attr('href');
scroll_positions[old_tab] = viewport.scrollTop();
});
$('#sidebar a[data-toggle="pill"]').on('shown', function (e) {
// Right after we show the new tab, restore its old scroll position
var viewport = $(window);
var target_tab = $(e.target).attr('href');
if (scroll_positions.hasOwnProperty(target_tab)) {
viewport.scrollTop(scroll_positions[target_tab]);
} else {
viewport.scrollTop(0);
}
// Hide all our error messages when switching tabs
$('.alert-error').hide();
$('.alert-success').hide();
$('.alert-info').hide();
$('.alert').hide();
// Set the URL bar title to show the sub-page you're currently on.
var browser_url = $(e.target).attr('href');
if (browser_url === "#home") {
browser_url = "#";
}
window.history.pushState("object or string", "Title", browser_url);
});
$('.button-slide').click(function () {
show_compose('stream', $("#stream"));
});
$('#sidebar a[href="#subscriptions"]').click(fetch_subs);
var settings_status = $('#settings-status');
$("#current_settings form").ajaxForm({
dataType: 'json', // This seems to be ignored. We still get back an xhr.
success: function (resp, statusText, xhr, form) {
var message = "Updated settings!";
var result = $.parseJSON(xhr.responseText);
if ((result.full_name !== undefined) || (result.short_name !== undefined)) {
message = "Updated settings! You will need to reload the page for your changes to take effect.";
}
settings_status.removeClass(status_classes)
.addClass('alert-success')
.text(message).stop(true).fadeTo(0,1);
// TODO: In theory we should auto-reload or something if
// you changed the email address or other fields that show
// up on all screens
},
error: function (xhr, error_type, xhn) {
var response = "Error changing settings";
if (xhr.status.toString().charAt(0) === "4") {
// Only display the error response for 4XX, where we've crafted
// a nice response.
response += ": " + $.parseJSON(xhr.responseText).msg;
}
settings_status.removeClass(status_classes)
.addClass('alert-error')
.text(response).stop(true).fadeTo(0,1);
}
});
// A little hackish, because it doesn't seem to totally get us
// the exact right width for the narrowbar and compose box,
// but, close enough for now.
resizehandler();
});