Convert settings from static HTML to a template.

This will make life much easier for handling update events.

(imported from commit 66b101eb5fae89b4eec6fc797fee8be26ac99bfb)
This commit is contained in:
Jessica McKellar 2014-02-13 17:47:57 -05:00
parent c96ceeaea4
commit 87635b9e32
7 changed files with 408 additions and 336 deletions

View File

@ -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;
}());

View File

@ -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);

View File

@ -1,5 +1,3 @@
{# Settings tab of the app. #}
<h1><i class="icon-vector-wrench settings-icon"></i>Settings</h1>
<div id="settings-change-box">
@ -10,16 +8,16 @@
<div class="settings-section-title"><i class="icon-vector-user settings-section-icon"></i>Your Account</div>
<div class="account-settings-form">
<form action="/json/settings/change" method="post"
class="form-horizontal your-account-settings">{% csrf_token %}
class="form-horizontal your-account-settings">
<div class="control-group" id="name_change_container">
<label for="full_name" class="control-label">Full name</label>
<div class="controls">
<input type="text" name="full_name" id="full_name"
value="{{ user_profile.full_name }}" />
value="{{ page_params.fullname }}" />
</div>
</div>
{% if password_auth_enabled %}
{{#if page_params.password_auth_enabled}}
<div class="control-group" id="pw_change_link">
<label for="change_password_button" class="control-label">Password</label>
<div class="controls">
@ -63,7 +61,7 @@
</div>
</div>
{% endif %}
{{/if}}
<div class="control-group">
<div class="controls">
@ -74,7 +72,7 @@
<div class="user-avatar-section">
<p>
<img id="user-settings-avatar" src="{{ avatar_url }}" />
<img id="user-settings-avatar" src="{{ page_params.avatar_url }}" />
</p>
<div id="user_avatar_file_input_error" class="text-error"></div>
<div id="user_avatar_file"></div>
@ -102,9 +100,9 @@
<div class="controls">
<input type="checkbox" name="enable_stream_desktop_notifications"
id="enable_stream_desktop_notifications"
{% if user_profile.enable_stream_desktop_notifications %}
{{#if page_params.stream_desktop_notifications_enabled}}
checked="yes"
{% endif %} />
{{/if}} />
</div>
<label for="enable_stream_desktop_notifications" class="control-label">
Desktop notifications
@ -115,9 +113,9 @@
<div class="control-group">
<div class="controls">
<input type="checkbox" name="enable_stream_sounds" id="enable_stream_sounds"
{% if user_profile.enable_stream_sounds %}
{{#if page_params.stream_sounds_enabled}}
checked="yes"
{% endif %} />
{{/if}} />
</div>
<label for="enable_stream_sounds" class="control-label">
Audible notifications
@ -125,9 +123,10 @@
<div class="propagate_stream_notifications_change"></div>
</div>
<p class="notification-settings-note">Change notification settings for
individual streams on your <a href="/#subscriptions">Streams
page</a>.</p>
<p class="notification-settings-note">
Change notification settings for individual streams on your <a
href="/#subscriptions">Streams page</a>.
</p>
<h4>Private messages and @-mentions</h4>
@ -136,9 +135,9 @@
<div class="control-group">
<div class="controls">
<input type="checkbox" name="enable_desktop_notifications" id="enable_desktop_notifications"
{% if user_profile.enable_desktop_notifications %}
{{#if page_params.desktop_notifications_enabled}}
checked="yes"
{% endif %} />
{{/if}} />
</div>
<label for="enable_desktop_notifications" class="control-label">
Desktop notifications
@ -148,9 +147,9 @@
<div class="control-group">
<div class="controls">
<input type="checkbox" name="enable_sounds" id="enable_sounds"
{% if user_profile.enable_sounds %}
{{#if page_params.sounds_enabled}}
checked="yes"
{% endif %} />
{{/if}} />
</div>
<label for="enable_sounds" class="control-label">
Audible notifications
@ -160,9 +159,9 @@
<div class="control-group">
<div class="controls">
<input type="checkbox" name="enable_offline_email_notifications" id="enable_offline_email_notifications"
{% if user_profile.enable_offline_email_notifications %}
{{#if page_params.enable_offline_email_notifications}}
checked="yes"
{% endif %} />
{{/if}} />
</div>
<label for="enable_offline_email_notifications" class="control-label">
Email notifications when offline
@ -172,9 +171,9 @@
<div class="control-group">
<div class="controls">
<input type="checkbox" name="enable_offline_push_notifications" id="enable_offline_push_notifications"
{% if user_profile.enable_offline_push_notifications %}
{{#if page_params.enable_offline_push_notifications}}
checked="yes"
{% endif %} />
{{/if}} />
</div>
<label for="enable_offline_push_notifications" class="control-label">
Mobile push notifications when offline
@ -188,9 +187,9 @@
<div class="control-group" id="digest_container">
<div class="controls">
<input type="checkbox" name="enable_digest_emails" id="enable_digest_emails"
{% if user_profile.enable_digest_emails %}
{{#if page_params.enable_digest_emails}}
checked="yes"
{% endif %} />
{{/if}} />
</div>
<label for="enable_digest_emails" class="control-label">
Digest emails when I'm away
@ -235,7 +234,7 @@
<div class="control-group">
<label for="bot_short_name" class="control-label">Username</label>
<input type="text" name="bot_short_name" id="create_bot_short_name" class="required bot_local_part"
placeholder="bot_user_name" value="" />-bot@{{ user_profile.realm.domain }}
placeholder="bot_user_name" value="" />-bot@{{ page_params.domain }}
<div><label for="create_bot_short_name" generated="true" class="text-error"></label></div>
</div>
<div class="control-group">
@ -273,7 +272,7 @@
<div id="get_api_key_box">
<p>Please re-enter your password to confirm your identity.
(<a href="/accounts/password/reset/" target="_blank">Forgotten it?</a>)</p>
<form action="/json/fetch_api_key" method="post" class="form-horizontal">{% csrf_token %}
<form action="/json/fetch_api_key" method="post" class="form-horizontal">
<div class="control-group">
<label for="password" class="control-label">Current password</label>
<input type="password" autocomplete="off"
@ -304,9 +303,8 @@
</ul>
</div>
{% if show_autoscroll_forever_option or show_default_desktop_notifications_option%}
<form action="/json/ui_settings/change" method="post"
class="form-horizontal ui-settings">{% csrf_token %}
{{#if_or page_params.show_autoscroll_forever_option page_params.show_default_desktop_notifications_option}}
<div class="ui-settings">
<div id="ui-settings" class="settings-section">
<div class="settings-section-title"><i class="icon-vector-beaker settings-section-icon"></i>Zulip Labs</div>
<div class="alert" id="ui-settings-status"></div>
@ -316,29 +314,29 @@
features we're working on. Let us know what you think!
</p>
<div class="control-group">
{% if show_autoscroll_forever_option %}
{{#if page_params.show_autoscroll_forever_option}}
<div class="controls">
<input type="checkbox" name="autoscroll_forever" id="autoscroll_forever"
{% if user_profile.autoscroll_forever %}
{{#if page_params.autoscroll_forever}}
checked="yes"
{% endif %} />
{{/if}} />
</div>
<label for="autoscroll_forever" class="control-label">
Always auto-scroll to new messages
</label>
{% endif %}
{{/if}}
{% if show_default_desktop_notifications_option %}
{{#if page_params.show_default_desktop_notifications_option}}
<div class="controls">
<input type="checkbox" name="default_desktop_notifications" id="default_desktop_notifications"
{% if user_profile.default_desktop_notifications %}
{{#if page_params.default_desktop_notifications}}
checked="yes"
{% endif %} />
{{/if}} />
</div>
<label for="default_desktop_notifications" class="control-label">
Enable desktop notifications for new streams
</label>
{% endif %}
{{/if}}
</div>
<div class="control-group">
@ -348,5 +346,5 @@
</div>
</div>
</div>
</form>
{% endif %}
</div>
{{/if_or}}

View File

@ -104,7 +104,6 @@ var page_params = {{ page_params }};
<div class="tab-pane" id="administration">
</div>
<div class="tab-pane" id="settings">
{% include "zerver/settings.html" %}
</div>
{% if show_debug %}

View File

@ -537,22 +537,26 @@ class ChangeSettingsTest(AuthedTestCase):
def test_ui_settings(self):
self.login("hamlet@zulip.com")
json_result = self.client.post("/json/ui_settings/change", {"autoscroll_forever": "on"})
json_result = self.client.post("/json/ui_settings/change",
{"autoscroll_forever": ujson.dumps(True)})
self.assert_json_success(json_result)
self.assertEqual(get_user_profile_by_email("hamlet@zulip.com").
enable_desktop_notifications, True)
json_result = self.client.post("/json/ui_settings/change", {})
json_result = self.client.post("/json/ui_settings/change",
{"autoscroll_forever": ujson.dumps(False)})
self.assert_json_success(json_result)
self.assertEqual(get_user_profile_by_email("hamlet@zulip.com").
autoscroll_forever, False)
json_result = self.client.post("/json/ui_settings/change", {"default_desktop_notifications": "on"})
json_result = self.client.post("/json/ui_settings/change",
{"default_desktop_notifications": ujson.dumps(True)})
self.assert_json_success(json_result)
self.assertEqual(get_user_profile_by_email("hamlet@zulip.com").
default_desktop_notifications, True)
json_result = self.client.post("/json/ui_settings/change", {})
json_result = self.client.post("/json/ui_settings/change",
{"default_desktop_notifications": ujson.dumps(False)})
self.assert_json_success(json_result)
self.assertEqual(get_user_profile_by_email("hamlet@zulip.com").
default_desktop_notifications, False)

View File

@ -672,6 +672,50 @@ function render(template_name, args) {
assert.equal(button_area.find(".no_propagate_notifications").text().trim(), 'No');
}());
(function settings_tab() {
var page_param_checkbox_options = {
stream_desktop_notifications_enabled: true,
stream_sounds_enabled: true, desktop_notifications_enabled: true,
sounds_enabled: true, enable_offline_email_notifications: true,
enable_offline_push_notifications: true, enable_digest_emails: true,
autoscroll_forever: true, default_desktop_notifications: true
};
var page_params = $.extend(page_param_checkbox_options, {
fullname: "Alyssa P. Hacker", password_auth_enabled: true,
avatar_url: "https://google.com",
domain: "zulip.com", show_autoscroll_forever_option: true,
show_default_desktop_notifications_option: true
});
var checkbox_ids = ["enable_stream_desktop_notifications",
"enable_stream_sounds", "enable_desktop_notifications",
"enable_sounds", "enable_offline_push_notifications",
"enable_digest_emails", "autoscroll_forever",
"default_desktop_notifications"];
// Render with all booleans set to true.
var html = render('settings_tab', {page_params: page_params});
global.write_test_output("settings_tab.handlebars", html);
// All checkboxes should be checked.
_.each(checkbox_ids, function (checkbox) {
assert.equal($(html).find("#" + checkbox).is(":checked"), true);
});
// Re-render with checkbox booleans set to false.
_.each(page_param_checkbox_options, function (value, option) {
page_params[option] = false;
});
html = render('settings_tab', {page_params: page_params});
// All checkboxes should be unchecked.
_.each(checkbox_ids, function (checkbox) {
assert.equal($(html).find("#" + checkbox).is(":checked"), false);
});
}());
// By the end of this test, we should have compiled all our templates. Ideally,
// we will also have exercised them to some degree, but that's a little trickier
// to enforce.

View File

@ -55,8 +55,7 @@ from zerver.lib.validator import check_string, check_list, check_dict, check_int
from zerver.decorator import require_post, \
authenticated_api_view, authenticated_json_post_view, \
has_request_variables, authenticated_json_view, \
to_non_negative_int, json_to_bool, \
has_request_variables, authenticated_json_view, to_non_negative_int, \
JsonableError, get_user_profile_by_email, REQ, require_realm_admin, \
RequestVariableConversionError
from zerver.lib.avatar import avatar_url, get_avatar_url
@ -913,6 +912,8 @@ def home(request):
has_mobile_devices = num_push_devices_for_user(user_profile) > 0,
autoscroll_forever = user_profile.autoscroll_forever,
show_autoscroll_forever_option = user_profile.realm.domain in ("customer28.invalid", "zulip.com", "customer31.invalid"),
default_desktop_notifications = user_profile.default_desktop_notifications,
show_default_desktop_notifications_option = user_profile.realm.domain in ("customer13.invalid", "zulip.com",),
avatar_url = avatar_url(user_profile)
)
if narrow_stream is not None:
@ -952,8 +953,6 @@ def home(request):
'show_webathena': user_profile.realm.domain == "mit.edu",
'enable_feedback': settings.ENABLE_FEEDBACK,
'embedded': narrow_stream is not None,
'show_default_desktop_notifications_option': user_profile.realm.domain in ("customer13.invalid", "zulip.com",),
'show_autoscroll_forever_option': page_params["show_autoscroll_forever_option"],
},
context_instance=RequestContext(request))
patch_cache_control(response, no_cache=True, no_store=True, must_revalidate=True)
@ -1561,18 +1560,20 @@ def create_user_backend(request, user_profile, email=REQ, password=REQ,
@authenticated_json_post_view
@has_request_variables
def json_change_ui_settings(request, user_profile,
autoscroll_forever=REQ(converter=lambda x: x == "on",
default=False),
default_desktop_notifications=REQ(converter=lambda x: x == "on",
default=False)):
autoscroll_forever=REQ(validator=check_bool,
default=None),
default_desktop_notifications=REQ(validator=check_bool,
default=None)):
result = {}
if user_profile.autoscroll_forever != autoscroll_forever:
if autoscroll_forever is not None and \
user_profile.autoscroll_forever != autoscroll_forever:
do_change_autoscroll_forever(user_profile, autoscroll_forever)
result['autoscroll_forever'] = autoscroll_forever
if user_profile.default_desktop_notifications != default_desktop_notifications:
if default_desktop_notifications is not None and \
user_profile.default_desktop_notifications != default_desktop_notifications:
do_change_default_desktop_notifications(user_profile, default_desktop_notifications)
result['default_desktop_notifications'] = default_desktop_notifications