diff --git a/.eslintrc.json b/.eslintrc.json index 583b37f944..8e6f15bdcc 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -348,6 +348,7 @@ "settings_display": false, "settings_emoji": false, "settings_exports": false, + "settings_list_widget": false, "settings_linkifiers": false, "settings_invites": false, "settings_muting": false, diff --git a/frontend_tests/node_tests/settings_org.js b/frontend_tests/node_tests/settings_org.js index 8469f7b450..af3f7d510f 100644 --- a/frontend_tests/node_tests/settings_org.js +++ b/frontend_tests/node_tests/settings_org.js @@ -73,6 +73,7 @@ zrequire('stream_data'); zrequire('settings_account'); zrequire('settings_org'); zrequire('settings_ui'); +zrequire('settings_list_widget'); run_test('unloaded', () => { // This test mostly gets us line coverage, and makes diff --git a/static/js/bundles/app.js b/static/js/bundles/app.js index 7fe9364280..d8b6d82ab6 100644 --- a/static/js/bundles/app.js +++ b/static/js/bundles/app.js @@ -163,6 +163,7 @@ import "../realm_icon.js"; import "../realm_logo.js"; import "../reminder.js"; import "../confirm_dialog.js"; +import "../settings_list_widget.js"; import "../settings_account.js"; import "../settings_display.js"; import "../settings_notifications.js"; diff --git a/static/js/settings_list_widget.js b/static/js/settings_list_widget.js new file mode 100644 index 0000000000..f875510b81 --- /dev/null +++ b/static/js/settings_list_widget.js @@ -0,0 +1,95 @@ +const DropdownListWidget = function (opts) { + opts = Object.assign({ + null_value: null, + render_text: (item_name) => item_name, + }, opts); + opts.container_id = `${opts.setting_name}_widget`; + opts.value_id = `id_${opts.setting_name}`; + + const render_dropdown_list = require("../templates/settings/dropdown_list.hbs"); + + const setup = () => { + // populate the dropdown + const dropdown_list_body = $(`#${opts.container_id} .dropdown-list-body`).expectOne(); + const search_input = $(`#${opts.container_id} .dropdown-search > input[type=text]`); + list_render.create(dropdown_list_body, opts.data, { + name: `${opts.setting_name}_list`, + modifier: function (item) { + return render_dropdown_list({ item: item }); + }, + filter: { + element: search_input, + predicate: function (item, value) { + return item.name.toLowerCase().includes(value); + }, + }, + }); + $(`#${opts.container_id} .dropdown-search`).click(function (e) { + e.stopPropagation(); + }); + + $(`#${opts.container_id} .dropdown-toggle`).click(function () { + search_input.val("").trigger("input"); + }); + }; + + const render = (value) => { + $(`#${opts.container_id} #${opts.value_id}`).data("value", value); + + const elem = $(`#${opts.container_id} #${opts.setting_name}_name`); + + if (!value || value === opts.null_value) { + elem.text(opts.default_text); + elem.addClass("text-warning"); + elem.closest('.input-group').find('.dropdown_list_reset_button').hide(); + return; + } + + // Happy path + const item = opts.data.find(x => x.value === value.toString()); + const text = opts.render_text(item.name); + elem.text(text); + elem.removeClass('text-warning'); + elem.closest('.input-group').find('.dropdown_list_reset_button').show(); + }; + + const update = (value) => { + render(value); + settings_org.save_discard_widget_status_handler($(`#org-${opts.subsection}`)); + }; + + const register_event_handlers = () => { + $(`#${opts.container_id} .dropdown-list-body`).on("click keypress", ".list_item", function (e) { + const setting_elem = $(this).closest(`.${opts.setting_name}_setting`); + if (e.type === "keypress") { + if (e.which === 13) { + setting_elem.find(".dropdown-menu").dropdown("toggle"); + } else { + return; + } + } + const value = $(this).attr('data-value'); + update(value); + }); + $(`#${opts.container_id} .dropdown_list_reset_button`).click(function () { + update(opts.null_value); + }); + }; + + const value = () => { + let val = $(`#${opts.container_id} #${opts.value_id}`).data('value'); + if (val === null) { + val = ''; + } + return val; + }; + + return { + setup, + render, + register_event_handlers, + value, + }; +}; + +window.settings_list_widget = DropdownListWidget; diff --git a/static/js/settings_org.js b/static/js/settings_org.js index dc6b2d3bc5..5cd9c47040 100644 --- a/static/js/settings_org.js +++ b/static/js/settings_org.js @@ -12,6 +12,7 @@ exports.reset = function () { meta.loaded = false; }; + exports.maybe_disable_widgets = function () { if (page_params.is_admin) { return; @@ -507,7 +508,7 @@ function check_property_changed(elem) { return current_val !== changed_val; } -function save_discard_widget_status_handler(subsection) { +exports.save_discard_widget_status_handler = (subsection) => { subsection.find('.subsection-failed-status p').hide(); subsection.find('.save-button').show(); const properties_elements = get_subsection_property_elements(subsection); @@ -516,100 +517,6 @@ function save_discard_widget_status_handler(subsection) { const save_btn_controls = subsection.find('.subsection-header .save-button-controls'); const button_state = show_change_process_button ? "unsaved" : "discarded"; exports.change_save_button_state(save_btn_controls, button_state); -} - -exports.DropdownListWidget = function (opts) { - opts = Object.assign({ - null_value: null, - render_text: (item_name) => item_name, - }, opts); - opts.container_id = `${opts.setting_name}_widget`; - opts.value_id = `id_${opts.setting_name}`; - - const render_dropdown_list = require("../templates/settings/dropdown_list.hbs"); - - const setup = () => { - // populate the dropdown - const dropdown_list_body = $(`#${opts.container_id} .dropdown-list-body`).expectOne(); - const search_input = $(`#${opts.container_id} .dropdown-search > input[type=text]`); - list_render.create(dropdown_list_body, opts.data, { - name: `${opts.setting_name}_list`, - modifier: function (item) { - return render_dropdown_list({ item: item }); - }, - filter: { - element: search_input, - predicate: function (item, value) { - return item.name.toLowerCase().includes(value); - }, - }, - }); - $(`#${opts.container_id} .dropdown-search`).click(function (e) { - e.stopPropagation(); - }); - - $(`#${opts.container_id} .dropdown-toggle`).click(function () { - search_input.val("").trigger("input"); - }); - }; - - const render = (value) => { - $(`#${opts.container_id} #${opts.value_id}`).data("value", value); - - const elem = $(`#${opts.container_id} #${opts.setting_name}_name`); - - if (!value || value === opts.null_value) { - elem.text(opts.default_text); - elem.addClass("text-warning"); - elem.closest('.input-group').find('.dropdown_list_reset_button').hide(); - return; - } - - // Happy path - const item = opts.data.find(x => x.value === value.toString()); - const text = opts.render_text(item.name); - elem.text(text); - elem.removeClass('text-warning'); - elem.closest('.input-group').find('.dropdown_list_reset_button').show(); - }; - - const update = (value) => { - render(value); - save_discard_widget_status_handler($(`#org-${opts.subsection}`)); - }; - - const register_event_handlers = () => { - $(`#${opts.container_id} .dropdown-list-body`).on("click keypress", ".list_item", function (e) { - const setting_elem = $(this).closest(`.${opts.setting_name}_setting`); - if (e.type === "keypress") { - if (e.which === 13) { - setting_elem.find(".dropdown-menu").dropdown("toggle"); - } else { - return; - } - } - const value = $(this).attr('data-value'); - update(value); - }); - $(`#${opts.container_id} .dropdown_list_reset_button`).click(function () { - update(opts.null_value); - }); - }; - - const value = () => { - let val = $(`#${opts.container_id} #${opts.value_id}`).data('value'); - if (val === null) { - val = ''; - } - return val; - }; - - return { - setup, - render, - register_event_handlers, - value, - }; }; exports.default_code_language_widget = null; @@ -631,13 +538,13 @@ exports.init_dropdown_widgets = () => { render_text: (x) => {return `#${x}`;}, null_value: -1, }; - exports.notifications_stream_widget = exports.DropdownListWidget( + exports.notifications_stream_widget = settings_list_widget( Object.assign({setting_name: 'realm_notifications_stream_id'}, notification_stream_options)); - exports.signup_notifications_stream_widget = exports.DropdownListWidget( + exports.signup_notifications_stream_widget = settings_list_widget( Object.assign({setting_name: 'realm_signup_notifications_stream_id'}, notification_stream_options)); - exports.default_code_language_widget = exports.DropdownListWidget({ + exports.default_code_language_widget = settings_list_widget({ setting_name: 'realm_default_code_block_language', data: Object.keys(pygments_data.langs).map(x => { return { @@ -703,7 +610,7 @@ exports.build_page = function () { } const subsection = $(e.target).closest('.org-subsection-parent'); - save_discard_widget_status_handler(subsection); + exports.save_discard_widget_status_handler(subsection); }); $('.organization').on('click', '.subsection-header .subsection-changes-discard .button', function (e) { diff --git a/tools/test-js-with-node b/tools/test-js-with-node index 6e7d825c10..240a22a2aa 100755 --- a/tools/test-js-with-node +++ b/tools/test-js-with-node @@ -108,6 +108,7 @@ EXEMPT_FILES = { 'static/js/search_pill_widget.js', 'static/js/sent_messages.js', 'static/js/server_events.js', + 'static/js/settings_list_widget.js', 'static/js/settings_account.js', 'static/js/settings_bots.js', 'static/js/settings_config.js',