diff --git a/static/js/settings.js b/static/js/settings.js index 10dde6978c..ac7cf3f9cd 100644 --- a/static/js/settings.js +++ b/static/js/settings.js @@ -23,12 +23,270 @@ function is_local_part(value, element) { // Choose avatar stamp fairly randomly, to help get old avatars out of cache. exports.avatar_stamp = Math.floor(Math.random()*100); -$(function () { +exports.setup_page = function () { + var settings_tab = templates.render('settings_tab', {page_params: page_params}); + $("#settings").html(settings_tab); + $("#settings-status").hide(); + $("#notify-settings-status").hide(); + $("#ui-settings-status").hide(); + + $("#api_key_value").text(""); + $("#get_api_key_box").hide(); + $("#show_api_key_box").hide(); + $("#api_key_button_box").show(); + + function clear_password_change() { + // Clear the password boxes so that passwords don't linger in the DOM + // for an XSS attacker to find. + $('#old_password, #new_password, #confirm_password').val(''); + } + + clear_password_change(); + + $('#api_key_button').click(function (e) { + if (page_params.password_auth_enabled !== false) { + $("#get_api_key_box").show(); + } else { + // Skip the password prompt step + $("#get_api_key_box form").submit(); + } + $("#api_key_button_box").hide(); + }); + + $('#pw_change_link').on('click', function (e) { + e.preventDefault(); + $('#pw_change_link').hide(); + $('#pw_change_controls').show(); + }); + + $('#new_password').on('change keyup', function () { + password_quality($('#new_password').val(), $('#pw_strength .bar')); + }); if (feature_flags.dont_show_digest_email_setting) { $("#digest_container").hide(); } + + function settings_change_error(message) { + // Scroll to the top so the error message is visible. + // We would scroll anyway if we end up submitting the form. + viewport.scrollTop(0); + var settings_status = $('#settings-status').expectOne(); + settings_status.removeClass(status_classes) + .addClass('alert-error') + .text(message).stop(true).fadeTo(0,1); + } + + $("form.your-account-settings").ajaxForm({ + dataType: 'json', // This seems to be ignored. We still get back an xhr. + beforeSubmit: function (arr, form, options) { + if (page_params.password_auth_enabled !== false) { + // FIXME: Check that the two password fields match + // FIXME: Use the same jQuery validation plugin as the signup form? + var new_pw = $('#new_password').val(); + if (new_pw !== '') { + var password_ok = password_quality(new_pw); + if (password_ok === undefined) { + // zxcvbn.js didn't load, for whatever reason. + settings_change_error( + 'An internal error occurred; try reloading the page. ' + + 'Sorry for the trouble!'); + return false; + } else if (!password_ok) { + settings_change_error('New password is too weak'); + return false; + } + } + } + return true; + }, + success: function (resp, statusText, xhr, form) { + var message = "Updated settings!"; + var result = $.parseJSON(xhr.responseText); + var settings_status = $('#settings-status').expectOne(); + + settings_status.removeClass(status_classes) + .addClass('alert-success') + .text(message).stop(true).fadeTo(0,1); + }, + 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_change_error(response); + }, + complete: function (xhr, statusText) { + // Whether successful or not, clear the password boxes. + // TODO: Clear these earlier, while the request is still pending. + clear_password_change(); + } + }); + + function update_notification_settings_success(resp, statusText, xhr, form) { + var message = "Updated notification settings!"; + var result = $.parseJSON(xhr.responseText); + var notify_settings_status = $('#notify-settings-status').expectOne(); + + // Stream notification settings. + + if (result.enable_stream_desktop_notifications !== undefined) { + page_params.stream_desktop_notifications_enabled = result.enable_stream_desktop_notifications; + } + if (result.enable_stream_sounds !== undefined) { + page_params.stream_sounds_enabled = result.enable_stream_sounds; + } + + // PM and @-mention notification settings. + + if (result.enable_desktop_notifications !== undefined) { + page_params.desktop_notifications_enabled = result.enable_desktop_notifications; + } + if (result.enable_sounds !== undefined) { + page_params.sounds_enabled = result.enable_sounds; + } + + if (result.enable_offline_email_notifications !== undefined) { + page_params.enable_offline_email_notifications = result.enable_offline_email_notifications; + } + + if (result.enable_offline_push_notifications !== undefined) { + page_params.enable_offline_push_notifications = result.enable_offline_push_notifications; + } + + // Other notification settings. + + if (result.enable_digest_emails !== undefined) { + page_params.enable_digest_emails = result.enable_digest_emails; + } + + notify_settings_status.removeClass(status_classes) + .addClass('alert-success') + .text(message).stop(true).fadeTo(0,1); + } + + function update_notification_settings_error(xhr, error_type, xhn) { + var response = "Error changing settings"; + var notify_settings_status = $('#notify-settings-status').expectOne(); + + 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; + } + + notify_settings_status.removeClass(status_classes) + .addClass('alert-error') + .text(response).stop(true).fadeTo(0,1); + } + + function post_notify_settings_changes(notification_changes, success_func, + error_func) { + return channel.post({ + url: "/json/notify_settings/change", + data: notification_changes, + success: success_func, + error: error_func + }); + } + + $("#change_notification_settings").on("click", function (e) { + var updated_settings = {}; + _.each(["enable_stream_desktop_notifications", "enable_stream_sounds", + "enable_desktop_notifications", "enable_sounds", + "enable_offline_email_notifications", + "enable_offline_push_notifications", "enable_digest_emails"], + function (setting) { + updated_settings[setting] = $("#" + setting).is(":checked"); + }); + post_notify_settings_changes(updated_settings, + update_notification_settings_success, + update_notification_settings_error); + }); + + function update_global_stream_setting(notification_type, new_setting) { + var data = {}; + data[notification_type] = new_setting; + channel.post({ + url: "/json/notify_settings/change", + data: data, + success: update_notification_settings_success, + error: update_notification_settings_error + }); + } + + function update_desktop_notification_setting(new_setting) { + update_global_stream_setting("enable_stream_desktop_notifications", new_setting); + subs.set_all_stream_desktop_notifications_to(new_setting); + } + + function update_audible_notification_setting(new_setting) { + update_global_stream_setting("enable_stream_sounds", new_setting); + subs.set_all_stream_audible_notifications_to(new_setting); + } + + function maybe_bulk_update_stream_notification_setting(notification_checkbox, + propagate_setting_function) { + var html = templates.render("propagate_notification_change"); + var control_group = notification_checkbox.closest(".control-group"); + var checkbox_status = notification_checkbox.is(":checked"); + control_group.find(".propagate_stream_notifications_change").html(html); + control_group.find(".yes_propagate_notifications").on("click", function (e) { + propagate_setting_function(checkbox_status); + control_group.find(".propagate_stream_notifications_change").empty(); + }); + control_group.find(".no_propagate_notifications").on("click", function (e) { + control_group.find(".propagate_stream_notifications_change").empty(); + }); + } + + $("#enable_stream_desktop_notifications").on("click", function (e) { + var notification_checkbox = $("#enable_stream_desktop_notifications"); + maybe_bulk_update_stream_notification_setting(notification_checkbox, + update_desktop_notification_setting); + }); + + $("#enable_stream_sounds").on("click", function (e) { + var notification_checkbox = $("#enable_stream_sounds"); + maybe_bulk_update_stream_notification_setting(notification_checkbox, + update_audible_notification_setting); + }); + + $("#get_api_key_box").hide(); + $("#show_api_key_box").hide(); + $("#get_api_key_box 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); + var settings_status = $('#settings-status').expectOne(); + + $("#get_api_key_password").val(""); + $("#api_key_value").text(result.api_key); + $("#show_api_key_box").show(); + $("#get_api_key_box").hide(); + settings_status.hide(); + }, + error: function (xhr, error_type, xhn) { + var response = "Error getting API key"; + var settings_status = $('#settings-status').expectOne(); + + 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); + $("#show_api_key_box").hide(); + $("#get_api_key_box").show(); + } + }); + function upload_avatar(file_input) { var form_data = new FormData(); @@ -269,7 +527,49 @@ $(function () { }); }); -}); + $("#ui-settings").on("click", "input[name='change_settings']", function (e) { + var labs_updates = {}; + _.each(["autoscroll_forever", "default_desktop_notifications"], + function (setting) { + labs_updates[setting] = $("#" + setting).is(":checked"); + }); + + channel.post({ + url: '/json/ui_settings/change', + data: labs_updates, + success: function (resp, statusText, xhr, form) { + var message = "Updated Zulip Labs settings!"; + var result = $.parseJSON(xhr.responseText); + var ui_settings_status = feature_flags.show_autoscroll_forever_option && + $('#ui-settings-status').expectOne(); + + if (result.autoscroll_forever !== undefined) { + page_params.autoscroll_forever = result.autoscroll_forever; + ui.resize_page_components(); + } + + ui_settings_status.removeClass(status_classes) + .addClass('alert-success') + .text(message).stop(true).fadeTo(0,1); + }, + error: function (xhr, error_type, xhn) { + var response = "Error changing settings"; + var ui_settings_status = feature_flags.show_autoscroll_forever_option && + $('#ui-settings-status').expectOne(); + + 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; + } + + ui_settings_status.removeClass(status_classes) + .addClass('alert-error') + .text(response).stop(true).fadeTo(0,1); + } + }); + }); +}; return exports; }()); diff --git a/static/js/ui.js b/static/js/ui.js index 9ada8b29e4..9a9454abaf 100644 --- a/static/js/ui.js +++ b/static/js/ui.js @@ -940,12 +940,6 @@ $(function () { e.preventDefault(); }); - function clear_password_change() { - // Clear the password boxes so that passwords don't linger in the DOM - // for an XSS attacker to find. - $('#old_password, #new_password, #confirm_password').val(''); - } - admin.show_or_hide_menu_item(); $('#gear-menu a[data-toggle="tab"]').on('show', function (e) { @@ -962,13 +956,6 @@ $(function () { $('.alert-info').hide(); $('.alert').hide(); - $("#api_key_value").text(""); - $("#get_api_key_box").hide(); - $("#show_api_key_box").hide(); - $("#api_key_button_box").show(); - - clear_password_change(); - // Set the URL bar title to show the sub-page you're currently on. var browser_url = target_tab; if (browser_url === "#home") { @@ -1003,265 +990,14 @@ $(function () { // Whenever the streams page comes up (from anywhere), populate it. subs_link.on('shown', subs.setup_page); + // The admin and settings pages are generated client-side through + // templates. + var admin_link = $('#gear-menu a[href="#administration"]'); admin_link.on('shown', admin.setup_page); - $('#pw_change_link').on('click', function (e) { - e.preventDefault(); - $('#pw_change_link').hide(); - $('#pw_change_controls').show(); - }); - - $('#new_password').on('change keyup', function () { - password_quality($('#new_password').val(), $('#pw_strength .bar')); - }); - - var settings_status = $('#settings-status').expectOne(); - var notify_settings_status = $('#notify-settings-status').expectOne(); - // does this make me a bad person? - var ui_settings_status = feature_flags.show_autoscroll_forever_option && $('#ui-settings-status').expectOne(); - - function settings_change_error(message) { - // Scroll to the top so the error message is visible. - // We would scroll anyway if we end up submitting the form. - viewport.scrollTop(0); - settings_status.removeClass(status_classes) - .addClass('alert-error') - .text(message).stop(true).fadeTo(0,1); - } - - $("form.your-account-settings").expectOne().ajaxForm({ - dataType: 'json', // This seems to be ignored. We still get back an xhr. - beforeSubmit: function (arr, form, options) { - if (page_params.password_auth_enabled !== false) { - // FIXME: Check that the two password fields match - // FIXME: Use the same jQuery validation plugin as the signup form? - var new_pw = $('#new_password').val(); - if (new_pw !== '') { - var password_ok = password_quality(new_pw); - if (password_ok === undefined) { - // zxcvbn.js didn't load, for whatever reason. - settings_change_error( - 'An internal error occurred; try reloading the page. ' + - 'Sorry for the trouble!'); - return false; - } else if (!password_ok) { - settings_change_error('New password is too weak'); - return false; - } - } - } - return true; - }, - success: function (resp, statusText, xhr, form) { - var message = "Updated settings!"; - var result = $.parseJSON(xhr.responseText); - - settings_status.removeClass(status_classes) - .addClass('alert-success') - .text(message).stop(true).fadeTo(0,1); - }, - 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_change_error(response); - }, - complete: function (xhr, statusText) { - // Whether successful or not, clear the password boxes. - // TODO: Clear these earlier, while the request is still pending. - clear_password_change(); - } - }); - - function update_notification_settings_success(resp, statusText, xhr, form) { - var message = "Updated notification settings!"; - var result = $.parseJSON(xhr.responseText); - - // Stream notification settings. - - if (result.enable_stream_desktop_notifications !== undefined) { - page_params.stream_desktop_notifications_enabled = result.enable_stream_desktop_notifications; - } - if (result.enable_stream_sounds !== undefined) { - page_params.stream_sounds_enabled = result.enable_stream_sounds; - } - - // PM and @-mention notification settings. - - if (result.enable_desktop_notifications !== undefined) { - page_params.desktop_notifications_enabled = result.enable_desktop_notifications; - } - if (result.enable_sounds !== undefined) { - page_params.sounds_enabled = result.enable_sounds; - } - - if (result.enable_offline_email_notifications !== undefined) { - page_params.enable_offline_email_notifications = result.enable_offline_email_notifications; - } - - if (result.enable_offline_push_notifications !== undefined) { - page_params.enable_offline_push_notifications = result.enable_offline_push_notifications; - } - - // Other notification settings. - - if (result.enable_digest_emails !== undefined) { - page_params.enable_digest_emails = result.enable_digest_emails; - } - - notify_settings_status.removeClass(status_classes) - .addClass('alert-success') - .text(message).stop(true).fadeTo(0,1); - } - - function update_notification_settings_error(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; - } - - notify_settings_status.removeClass(status_classes) - .addClass('alert-error') - .text(response).stop(true).fadeTo(0,1); - } - - function post_notify_settings_changes(notification_changes, success_func, - error_func) { - return channel.post({ - url: "/json/notify_settings/change", - data: notification_changes, - success: success_func, - error: error_func - }); - } - - $("#change_notification_settings").on("click", function (e) { - var updated_settings = {}; - _.each(["enable_stream_desktop_notifications", "enable_stream_sounds", - "enable_desktop_notifications", "enable_sounds", - "enable_offline_email_notifications", - "enable_offline_push_notifications", "enable_digest_emails"], - function (setting) { - updated_settings[setting] = $("#" + setting).is(":checked"); - }); - post_notify_settings_changes(updated_settings, - update_notification_settings_success, - update_notification_settings_error); - }); - - function update_global_stream_setting(notification_type, new_setting) { - var data = {}; - data[notification_type] = new_setting; - channel.post({ - url: "/json/notify_settings/change", - data: data, - success: update_notification_settings_success, - error: update_notification_settings_error - }); - } - - function update_desktop_notification_setting(new_setting) { - update_global_stream_setting("enable_stream_desktop_notifications", new_setting); - subs.set_all_stream_desktop_notifications_to(new_setting); - } - - function update_audible_notification_setting(new_setting) { - update_global_stream_setting("enable_stream_sounds", new_setting); - subs.set_all_stream_audible_notifications_to(new_setting); - } - - function maybe_bulk_update_stream_notification_setting(notification_checkbox, - propagate_setting_function) { - var html = templates.render("propagate_notification_change"); - var control_group = notification_checkbox.closest(".control-group"); - var checkbox_status = notification_checkbox.is(":checked"); - control_group.find(".propagate_stream_notifications_change").html(html); - control_group.find(".yes_propagate_notifications").on("click", function (e) { - propagate_setting_function(checkbox_status); - control_group.find(".propagate_stream_notifications_change").empty(); - }); - control_group.find(".no_propagate_notifications").on("click", function (e) { - control_group.find(".propagate_stream_notifications_change").empty(); - }); - } - - $("#enable_stream_desktop_notifications").on("click", function (e) { - var notification_checkbox = $("#enable_stream_desktop_notifications"); - maybe_bulk_update_stream_notification_setting(notification_checkbox, - update_desktop_notification_setting); - }); - - $("#enable_stream_sounds").on("click", function (e) { - var notification_checkbox = $("#enable_stream_sounds"); - maybe_bulk_update_stream_notification_setting(notification_checkbox, - update_audible_notification_setting); - }); - - if (feature_flags.show_autoscroll_forever_option) { - $("form.ui-settings").expectOne().ajaxForm({ - dataType: 'json', - - success: function (resp, statusText, xhr, form) { - var message = "Updated Zulip Labs settings!"; - var result = $.parseJSON(xhr.responseText); - - if (result.autoscroll_forever !== undefined) { - page_params.autoscroll_forever = result.autoscroll_forever; - exports.resize_page_components(); - } - - ui_settings_status.removeClass(status_classes) - .addClass('alert-success') - .text(message).stop(true).fadeTo(0,1); - }, - 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; - } - - ui_settings_status.removeClass(status_classes) - .addClass('alert-error') - .text(response).stop(true).fadeTo(0,1); - } - }); - } - - $("#get_api_key_box").hide(); - $("#show_api_key_box").hide(); - $("#get_api_key_box 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); - $("#get_api_key_password").val(""); - $("#api_key_value").text(result.api_key); - $("#show_api_key_box").show(); - $("#get_api_key_box").hide(); - settings_status.hide(); - }, - error: function (xhr, error_type, xhn) { - var response = "Error getting API key"; - 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); - $("#show_api_key_box").hide(); - $("#get_api_key_box").show(); - } - }); + var settings_link = $('#gear-menu a[href="#settings"]'); + settings_link.on('shown', settings.setup_page); // A little hackish, because it doesn't seem to totally get us the // exact right width for the floating_recipient_bar and compose @@ -1589,16 +1325,6 @@ $(function () { server_events.restart_get_events({dont_block: true}); }); - $('#api_key_button').click(function (e) { - if (page_params.password_auth_enabled !== false) { - $("#get_api_key_box").show(); - } else { - // Skip the password prompt step - $("#get_api_key_box form").submit(); - } - $("#api_key_button_box").hide(); - }); - $('body').on('click', '.edit_content_button', function (e) { var row = current_msg_list.get_row(rows.id($(this).closest(".message_row"))); message_edit.start(row); diff --git a/templates/zerver/settings.html b/static/templates/settings_tab.handlebars similarity index 87% rename from templates/zerver/settings.html rename to static/templates/settings_tab.handlebars index 11feccfa1b..1b695dffec 100644 --- a/templates/zerver/settings.html +++ b/static/templates/settings_tab.handlebars @@ -1,5 +1,3 @@ -{# Settings tab of the app. #} -

Settings

@@ -10,16 +8,16 @@
Your Account