diff options
| author | Tom Carrick <tom@carrick.eu> | 2026-04-19 11:54:17 +0300 |
|---|---|---|
| committer | Jacob Walls <jacobtylerwalls@gmail.com> | 2026-04-19 13:45:56 +0300 |
| commit | fc0a0ebd4fe573299a5f978e77fa3bca8424f661 (patch) | |
| tree | 02df30c20820ddc4a6764969e8dbd9c3a22f437d | |
| parent | 47789e3a2b471995ed753c87ce69ffbaa59c0601 (diff) | |
Formatted JavaScript files.
31 files changed, 3021 insertions, 1651 deletions
diff --git a/django/contrib/admin/static/admin/js/SelectBox.js b/django/contrib/admin/static/admin/js/SelectBox.js index 17c182c53f..7b6a751ea0 100644 --- a/django/contrib/admin/static/admin/js/SelectBox.js +++ b/django/contrib/admin/static/admin/js/SelectBox.js @@ -1,26 +1,31 @@ -'use strict'; +"use strict"; { const getOptionGroupName = (option) => option.parentElement.label; const SelectBox = { cache: {}, - init: function(id) { + init: function (id) { const box = document.getElementById(id); SelectBox.cache[id] = []; const cache = SelectBox.cache[id]; for (const node of box.options) { const group = getOptionGroupName(node); - cache.push({group, value: node.value, text: node.text, displayed: 1}); + cache.push({ + group, + value: node.value, + text: node.text, + displayed: 1, + }); } // Only sort if there are any groups (to preserve existing behavior for non-grouped selects) - if (cache.some(item => item.group)) { + if (cache.some((item) => item.group)) { SelectBox.sort(id); } }, - redisplay: function(id) { + redisplay: function (id) { // Repopulate HTML select box from cache const box = document.getElementById(id); const scroll_value_from_top = box.scrollTop; - box.innerHTML = ''; + box.innerHTML = ""; let node = box; let currentOptgroup = null; for (const option of SelectBox.cache[id]) { @@ -28,15 +33,20 @@ // Create a new optgroup when the group changes if (option.group && option.group !== currentOptgroup) { currentOptgroup = option.group; - node = document.createElement('optgroup'); - node.setAttribute('label', option.group); + node = document.createElement("optgroup"); + node.setAttribute("label", option.group); box.appendChild(node); } else if (!option.group && currentOptgroup !== null) { // Back to ungrouped options currentOptgroup = null; node = box; } - const new_option = new Option(option.text, option.value, false, false); + const new_option = new Option( + option.text, + option.value, + false, + false, + ); // Shows a tooltip when hovering over the option new_option.title = option.text; node.appendChild(new_option); @@ -44,7 +54,7 @@ } box.scrollTop = scroll_value_from_top; }, - filter: function(id, text) { + filter: function (id, text) { // Redisplay the HTML select box, displaying only the choices containing ALL // the words in text. (It's an AND search.) const tokens = text.toLowerCase().split(/\s+/); @@ -62,9 +72,9 @@ }, get_hidden_node_count(id) { const cache = SelectBox.cache[id] || []; - return cache.filter(node => node.displayed === 0).length; + return cache.filter((node) => node.displayed === 0).length; }, - delete_from_cache: function(id, value) { + delete_from_cache: function (id, value) { let delete_index = null; const cache = SelectBox.cache[id]; for (const [i, node] of cache.entries()) { @@ -75,10 +85,15 @@ } cache.splice(delete_index, 1); }, - add_to_cache: function(id, option) { - SelectBox.cache[id].push({group: option.group, value: option.value, text: option.text, displayed: 1}); + add_to_cache: function (id, option) { + SelectBox.cache[id].push({ + group: option.group, + value: option.value, + text: option.text, + displayed: 1, + }); }, - cache_contains: function(id, value) { + cache_contains: function (id, value) { // Check if an item is contained in the cache for (const node of SelectBox.cache[id]) { if (node.value === value) { @@ -87,44 +102,61 @@ } return false; }, - move: function(from, to) { + move: function (from, to) { const from_box = document.getElementById(from); for (const option of from_box.options) { const option_value = option.value; - if (option.selected && SelectBox.cache_contains(from, option_value)) { + if ( + option.selected && + SelectBox.cache_contains(from, option_value) + ) { const group = getOptionGroupName(option); - SelectBox.add_to_cache(to, {group, value: option_value, text: option.text, displayed: 1}); + SelectBox.add_to_cache(to, { + group, + value: option_value, + text: option.text, + displayed: 1, + }); SelectBox.delete_from_cache(from, option_value); } } // Only sort if there are any groups (to preserve existing behavior for non-grouped selects) - if (SelectBox.cache[to].some(item => item.group)) { + if (SelectBox.cache[to].some((item) => item.group)) { SelectBox.sort(to); } SelectBox.redisplay(from); SelectBox.redisplay(to); }, - move_all: function(from, to) { + move_all: function (from, to) { const from_box = document.getElementById(from); for (const option of from_box.options) { const option_value = option.value; if (SelectBox.cache_contains(from, option_value)) { const group = getOptionGroupName(option); - SelectBox.add_to_cache(to, {group, value: option_value, text: option.text, displayed: 1}); + SelectBox.add_to_cache(to, { + group, + value: option_value, + text: option.text, + displayed: 1, + }); SelectBox.delete_from_cache(from, option_value); } } // Only sort if there are any groups (to preserve existing behavior for non-grouped selects) - if (SelectBox.cache[to].some(item => item.group)) { + if (SelectBox.cache[to].some((item) => item.group)) { SelectBox.sort(to); } SelectBox.redisplay(from); SelectBox.redisplay(to); }, - sort: function(id) { - SelectBox.cache[id].sort(function(a, b) { - a = (a.group && a.group.toLowerCase() || '') + a.text.toLowerCase(); - b = (b.group && b.group.toLowerCase() || '') + b.text.toLowerCase(); + sort: function (id) { + SelectBox.cache[id].sort(function (a, b) { + a = + ((a.group && a.group.toLowerCase()) || "") + + a.text.toLowerCase(); + b = + ((b.group && b.group.toLowerCase()) || "") + + b.text.toLowerCase(); if (a > b) { return 1; } @@ -132,14 +164,14 @@ return -1; } return 0; - } ); + }); }, - select_all: function(id) { + select_all: function (id) { const box = document.getElementById(id); for (const option of box.options) { option.selected = true; } - } + }, }; window.SelectBox = SelectBox; } diff --git a/django/contrib/admin/static/admin/js/SelectFilter2.js b/django/contrib/admin/static/admin/js/SelectFilter2.js index 99efa1e0ca..ebaaa0cd60 100644 --- a/django/contrib/admin/static/admin/js/SelectFilter2.js +++ b/django/contrib/admin/static/admin/js/SelectFilter2.js @@ -4,161 +4,289 @@ SelectFilter2 - Turns a multiple-select box into a filter interface. Requires core.js and SelectBox.js. */ -'use strict'; +"use strict"; { window.SelectFilter = { - init: function(field_id, field_name, is_stacked) { + init: function (field_id, field_name, is_stacked) { if (field_id.match(/__prefix__/)) { // Don't initialize on empty forms. return; } const from_box = document.getElementById(field_id); - from_box.id += '_from'; // change its ID - from_box.className = 'filtered'; - from_box.setAttribute('aria-labelledby', field_id + '_from_label'); - from_box.setAttribute('aria-describedby', `${field_id}_helptext ${field_id}_choose_helptext`); + from_box.id += "_from"; // change its ID + from_box.className = "filtered"; + from_box.setAttribute("aria-labelledby", field_id + "_from_label"); + from_box.setAttribute( + "aria-describedby", + `${field_id}_helptext ${field_id}_choose_helptext`, + ); // <div class="selector"> or <div class="selector stacked"> - const selector_div = quickElement('div', from_box.parentNode); + const selector_div = quickElement("div", from_box.parentNode); // Make sure the selector div appears between the label and the add link. - from_box.parentNode.insertBefore(selector_div, from_box.nextSibling); - selector_div.className = is_stacked ? 'selector stacked' : 'selector'; + from_box.parentNode.insertBefore( + selector_div, + from_box.nextSibling, + ); + selector_div.className = is_stacked + ? "selector stacked" + : "selector"; // <div class="selector-available"> - const selector_available = quickElement('div', selector_div); - selector_available.className = 'selector-available'; - const selector_available_title = quickElement('div', selector_available); - selector_available_title.id = field_id + '_from_title'; - selector_available_title.className = 'selector-available-title'; + const selector_available = quickElement("div", selector_div); + selector_available.className = "selector-available"; + const selector_available_title = quickElement( + "div", + selector_available, + ); + selector_available_title.id = field_id + "_from_title"; + selector_available_title.className = "selector-available-title"; quickElement( - 'label', + "label", selector_available_title, - interpolate(gettext('Available %s') + ' ', [field_name]), - 'id', - field_id + '_from_label', - 'for', - field_id + '_from' + interpolate(gettext("Available %s") + " ", [field_name]), + "id", + field_id + "_from_label", + "for", + field_id + "_from", ); quickElement( - 'p', + "p", selector_available_title, - interpolate(gettext('Choose %s by selecting them and then select the "Choose" arrow button.'), [field_name]), - 'id', `${field_id}_choose_helptext`, 'class', 'helptext' + interpolate( + gettext( + 'Choose %s by selecting them and then select the "Choose" arrow button.', + ), + [field_name], + ), + "id", + `${field_id}_choose_helptext`, + "class", + "helptext", ); - const filter_p = quickElement('p', selector_available, '', 'id', field_id + '_filter'); - filter_p.className = 'selector-filter'; + const filter_p = quickElement( + "p", + selector_available, + "", + "id", + field_id + "_filter", + ); + filter_p.className = "selector-filter"; - const search_filter_label = quickElement('label', filter_p, '', 'for', field_id + '_input'); + const search_filter_label = quickElement( + "label", + filter_p, + "", + "for", + field_id + "_input", + ); quickElement( - 'span', search_filter_label, '', - 'class', 'help-tooltip search-label-icon', - 'aria-label', interpolate(gettext("Type into this box to filter down the list of available %s."), [field_name]) + "span", + search_filter_label, + "", + "class", + "help-tooltip search-label-icon", + "aria-label", + interpolate( + gettext( + "Type into this box to filter down the list of available %s.", + ), + [field_name], + ), ); - filter_p.appendChild(document.createTextNode(' ')); + filter_p.appendChild(document.createTextNode(" ")); - const filter_input = quickElement('input', filter_p, '', 'type', 'text', 'placeholder', gettext("Filter")); - filter_input.id = field_id + '_input'; + const filter_input = quickElement( + "input", + filter_p, + "", + "type", + "text", + "placeholder", + gettext("Filter"), + ); + filter_input.id = field_id + "_input"; selector_available.appendChild(from_box); const choose_all = quickElement( - 'button', + "button", selector_available, - interpolate(gettext('Choose all %s'), [field_name]), - 'id', field_id + '_add_all', - 'class', 'selector-chooseall', - 'type', 'button' + interpolate(gettext("Choose all %s"), [field_name]), + "id", + field_id + "_add_all", + "class", + "selector-chooseall", + "type", + "button", ); // <ul class="selector-chooser"> - const selector_chooser = quickElement('ul', selector_div); - selector_chooser.className = 'selector-chooser'; + const selector_chooser = quickElement("ul", selector_div); + selector_chooser.className = "selector-chooser"; const add_button = quickElement( - 'button', - quickElement('li', selector_chooser), - interpolate(gettext('Choose selected %s'), [field_name]), - 'id', field_id + '_add', - 'class', 'selector-add', - 'type', 'button' + "button", + quickElement("li", selector_chooser), + interpolate(gettext("Choose selected %s"), [field_name]), + "id", + field_id + "_add", + "class", + "selector-add", + "type", + "button", ); const remove_button = quickElement( - 'button', - quickElement('li', selector_chooser), - interpolate(gettext('Remove selected %s'), [field_name]), - 'id', field_id + '_remove', - 'class', 'selector-remove', - 'type', 'button' + "button", + quickElement("li", selector_chooser), + interpolate(gettext("Remove selected %s"), [field_name]), + "id", + field_id + "_remove", + "class", + "selector-remove", + "type", + "button", ); // <div class="selector-chosen"> - const selector_chosen = quickElement('div', selector_div, '', 'id', field_id + '_selector_chosen'); - selector_chosen.className = 'selector-chosen'; - const selector_chosen_title = quickElement('div', selector_chosen); - selector_chosen_title.className = 'selector-chosen-title'; - selector_chosen_title.id = field_id + '_to_title'; + const selector_chosen = quickElement( + "div", + selector_div, + "", + "id", + field_id + "_selector_chosen", + ); + selector_chosen.className = "selector-chosen"; + const selector_chosen_title = quickElement("div", selector_chosen); + selector_chosen_title.className = "selector-chosen-title"; + selector_chosen_title.id = field_id + "_to_title"; quickElement( - 'label', + "label", selector_chosen_title, - interpolate(gettext('Chosen %s') + ' ', [field_name]), - 'id', - field_id + '_to_label', - 'for', - field_id + '_to' + interpolate(gettext("Chosen %s") + " ", [field_name]), + "id", + field_id + "_to_label", + "for", + field_id + "_to", ); quickElement( - 'p', + "p", selector_chosen_title, - interpolate(gettext('Remove %s by selecting them and then select the "Remove" arrow button.'), [field_name]), - 'id', `${field_id}_remove_helptext`, 'class', 'helptext' + interpolate( + gettext( + 'Remove %s by selecting them and then select the "Remove" arrow button.', + ), + [field_name], + ), + "id", + `${field_id}_remove_helptext`, + "class", + "helptext", ); - - const filter_selected_p = quickElement('p', selector_chosen, '', 'id', field_id + '_filter_selected'); - filter_selected_p.className = 'selector-filter'; - const search_filter_selected_label = quickElement('label', filter_selected_p, '', 'for', field_id + '_selected_input'); + const filter_selected_p = quickElement( + "p", + selector_chosen, + "", + "id", + field_id + "_filter_selected", + ); + filter_selected_p.className = "selector-filter"; + + const search_filter_selected_label = quickElement( + "label", + filter_selected_p, + "", + "for", + field_id + "_selected_input", + ); quickElement( - 'span', search_filter_selected_label, '', - 'class', 'help-tooltip search-label-icon', - 'aria-label', interpolate(gettext("Type into this box to filter down the list of selected %s."), [field_name]) + "span", + search_filter_selected_label, + "", + "class", + "help-tooltip search-label-icon", + "aria-label", + interpolate( + gettext( + "Type into this box to filter down the list of selected %s.", + ), + [field_name], + ), ); - filter_selected_p.appendChild(document.createTextNode(' ')); + filter_selected_p.appendChild(document.createTextNode(" ")); - const filter_selected_input = quickElement('input', filter_selected_p, '', 'type', 'text', 'placeholder', gettext("Filter")); - filter_selected_input.id = field_id + '_selected_input'; + const filter_selected_input = quickElement( + "input", + filter_selected_p, + "", + "type", + "text", + "placeholder", + gettext("Filter"), + ); + filter_selected_input.id = field_id + "_selected_input"; quickElement( - 'select', + "select", selector_chosen, - '', - 'id', field_id + '_to', - 'multiple', '', - 'size', from_box.size, - 'name', from_box.name, - 'aria-labelledby', field_id + '_to_label', - 'aria-describedby', `${field_id}_helptext ${field_id}_remove_helptext`, - 'class', 'filtered' + "", + "id", + field_id + "_to", + "multiple", + "", + "size", + from_box.size, + "name", + from_box.name, + "aria-labelledby", + field_id + "_to_label", + "aria-describedby", + `${field_id}_helptext ${field_id}_remove_helptext`, + "class", + "filtered", + ); + const warning_footer = quickElement( + "div", + selector_chosen, + "", + "class", + "list-footer-display", + ); + quickElement( + "span", + warning_footer, + "", + "id", + field_id + "_list-footer-display-text", + ); + quickElement( + "span", + warning_footer, + " " + gettext("(click to clear)"), + "class", + "list-footer-display__clear", ); - const warning_footer = quickElement('div', selector_chosen, '', 'class', 'list-footer-display'); - quickElement('span', warning_footer, '', 'id', field_id + '_list-footer-display-text'); - quickElement('span', warning_footer, ' ' + gettext('(click to clear)'), 'class', 'list-footer-display__clear'); const clear_all = quickElement( - 'button', + "button", selector_chosen, - interpolate(gettext('Remove all %s'), [field_name]), - 'id', field_id + '_remove_all', - 'class', 'selector-clearall', - 'type', 'button' + interpolate(gettext("Remove all %s"), [field_name]), + "id", + field_id + "_remove_all", + "class", + "selector-clearall", + "type", + "button", ); - from_box.name = from_box.name + '_old'; + from_box.name = from_box.name + "_old"; // Set up the JavaScript event handlers for the select box filter interface - const move_selection = function(e, elem, move_func, from, to) { - if (!elem.hasAttribute('disabled')) { + const move_selection = function (e, elem, move_func, from, to) { + if (!elem.hasAttribute("disabled")) { move_func(from, to); SelectFilter.refresh_icons(field_id); SelectFilter.refresh_filtered_selects(field_id); @@ -166,151 +294,230 @@ Requires core.js and SelectBox.js. } e.preventDefault(); }; - choose_all.addEventListener('click', function(e) { - move_selection(e, this, SelectBox.move_all, field_id + '_from', field_id + '_to'); + choose_all.addEventListener("click", function (e) { + move_selection( + e, + this, + SelectBox.move_all, + field_id + "_from", + field_id + "_to", + ); }); - add_button.addEventListener('click', function(e) { - move_selection(e, this, SelectBox.move, field_id + '_from', field_id + '_to'); + add_button.addEventListener("click", function (e) { + move_selection( + e, + this, + SelectBox.move, + field_id + "_from", + field_id + "_to", + ); }); - remove_button.addEventListener('click', function(e) { - move_selection(e, this, SelectBox.move, field_id + '_to', field_id + '_from'); + remove_button.addEventListener("click", function (e) { + move_selection( + e, + this, + SelectBox.move, + field_id + "_to", + field_id + "_from", + ); }); - clear_all.addEventListener('click', function(e) { - move_selection(e, this, SelectBox.move_all, field_id + '_to', field_id + '_from'); + clear_all.addEventListener("click", function (e) { + move_selection( + e, + this, + SelectBox.move_all, + field_id + "_to", + field_id + "_from", + ); }); - warning_footer.addEventListener('click', function(e) { - filter_selected_input.value = ''; - SelectBox.filter(field_id + '_to', ''); + warning_footer.addEventListener("click", function (e) { + filter_selected_input.value = ""; + SelectBox.filter(field_id + "_to", ""); SelectFilter.refresh_filtered_warning(field_id); SelectFilter.refresh_icons(field_id); }); - filter_input.addEventListener('keypress', function(e) { - SelectFilter.filter_key_press(e, field_id, '_from', '_to'); + filter_input.addEventListener("keypress", function (e) { + SelectFilter.filter_key_press(e, field_id, "_from", "_to"); }); - filter_input.addEventListener('keyup', function(e) { - SelectFilter.filter_key_up(e, field_id, '_from'); + filter_input.addEventListener("keyup", function (e) { + SelectFilter.filter_key_up(e, field_id, "_from"); }); - filter_input.addEventListener('keydown', function(e) { - SelectFilter.filter_key_down(e, field_id, '_from', '_to'); + filter_input.addEventListener("keydown", function (e) { + SelectFilter.filter_key_down(e, field_id, "_from", "_to"); }); - filter_selected_input.addEventListener('keypress', function(e) { - SelectFilter.filter_key_press(e, field_id, '_to', '_from'); + filter_selected_input.addEventListener("keypress", function (e) { + SelectFilter.filter_key_press(e, field_id, "_to", "_from"); }); - filter_selected_input.addEventListener('keyup', function(e) { - SelectFilter.filter_key_up(e, field_id, '_to', '_selected_input'); + filter_selected_input.addEventListener("keyup", function (e) { + SelectFilter.filter_key_up( + e, + field_id, + "_to", + "_selected_input", + ); }); - filter_selected_input.addEventListener('keydown', function(e) { - SelectFilter.filter_key_down(e, field_id, '_to', '_from'); + filter_selected_input.addEventListener("keydown", function (e) { + SelectFilter.filter_key_down(e, field_id, "_to", "_from"); }); - selector_div.addEventListener('change', function(e) { - if (e.target.tagName === 'SELECT') { + selector_div.addEventListener("change", function (e) { + if (e.target.tagName === "SELECT") { SelectFilter.refresh_icons(field_id); } }); - selector_div.addEventListener('dblclick', function(e) { - if (e.target.tagName === 'OPTION') { - if (e.target.closest('select').id === field_id + '_to') { - SelectBox.move(field_id + '_to', field_id + '_from'); + selector_div.addEventListener("dblclick", function (e) { + if (e.target.tagName === "OPTION") { + if (e.target.closest("select").id === field_id + "_to") { + SelectBox.move(field_id + "_to", field_id + "_from"); } else { - SelectBox.move(field_id + '_from', field_id + '_to'); + SelectBox.move(field_id + "_from", field_id + "_to"); } SelectFilter.refresh_icons(field_id); } }); - from_box.closest('form').addEventListener('submit', function() { - SelectBox.filter(field_id + '_to', ''); - SelectBox.select_all(field_id + '_to'); + from_box.closest("form").addEventListener("submit", function () { + SelectBox.filter(field_id + "_to", ""); + SelectBox.select_all(field_id + "_to"); }); - SelectBox.init(field_id + '_from'); - SelectBox.init(field_id + '_to'); + SelectBox.init(field_id + "_from"); + SelectBox.init(field_id + "_to"); // Move selected from_box options to to_box - SelectBox.move(field_id + '_from', field_id + '_to'); + SelectBox.move(field_id + "_from", field_id + "_to"); // Initial icon refresh SelectFilter.refresh_icons(field_id); }, - any_selected: function(field) { + any_selected: function (field) { // Temporarily add the required attribute and check validity. field.required = true; const any_selected = field.checkValidity(); field.required = false; return any_selected; }, - refresh_filtered_warning: function(field_id) { - const count = SelectBox.get_hidden_node_count(field_id + '_to'); - const selector = document.getElementById(field_id + '_selector_chosen'); - const warning = document.getElementById(field_id + '_list-footer-display-text'); - selector.className = selector.className.replace('selector-chosen--with-filtered', ''); - warning.textContent = interpolate(ngettext( - '%s selected option not visible', - '%s selected options not visible', - count - ), [count]); - if(count > 0) { - selector.className += ' selector-chosen--with-filtered'; + refresh_filtered_warning: function (field_id) { + const count = SelectBox.get_hidden_node_count(field_id + "_to"); + const selector = document.getElementById( + field_id + "_selector_chosen", + ); + const warning = document.getElementById( + field_id + "_list-footer-display-text", + ); + selector.className = selector.className.replace( + "selector-chosen--with-filtered", + "", + ); + warning.textContent = interpolate( + ngettext( + "%s selected option not visible", + "%s selected options not visible", + count, + ), + [count], + ); + if (count > 0) { + selector.className += " selector-chosen--with-filtered"; } }, - refresh_filtered_selects: function(field_id) { - SelectBox.filter(field_id + '_from', document.getElementById(field_id + "_input").value); - SelectBox.filter(field_id + '_to', document.getElementById(field_id + "_selected_input").value); + refresh_filtered_selects: function (field_id) { + SelectBox.filter( + field_id + "_from", + document.getElementById(field_id + "_input").value, + ); + SelectBox.filter( + field_id + "_to", + document.getElementById(field_id + "_selected_input").value, + ); }, - refresh_icons: function(field_id) { - const from = document.getElementById(field_id + '_from'); - const to = document.getElementById(field_id + '_to'); + refresh_icons: function (field_id) { + const from = document.getElementById(field_id + "_from"); + const to = document.getElementById(field_id + "_to"); // Disabled if no items are selected. - document.getElementById(field_id + '_add').disabled = !SelectFilter.any_selected(from); - document.getElementById(field_id + '_remove').disabled = !SelectFilter.any_selected(to); + document.getElementById(field_id + "_add").disabled = + !SelectFilter.any_selected(from); + document.getElementById(field_id + "_remove").disabled = + !SelectFilter.any_selected(to); // Disabled if the corresponding box is empty. - document.getElementById(field_id + '_add_all').disabled = !from.querySelector('option'); - document.getElementById(field_id + '_remove_all').disabled = !to.querySelector('option'); + document.getElementById(field_id + "_add_all").disabled = + !from.querySelector("option"); + document.getElementById(field_id + "_remove_all").disabled = + !to.querySelector("option"); }, - filter_key_press: function(event, field_id, source, target) { + filter_key_press: function (event, field_id, source, target) { const source_box = document.getElementById(field_id + source); // don't submit form if user pressed Enter - if ((event.which && event.which === 13) || (event.keyCode && event.keyCode === 13)) { + if ( + (event.which && event.which === 13) || + (event.keyCode && event.keyCode === 13) + ) { source_box.selectedIndex = 0; SelectBox.move(field_id + source, field_id + target); source_box.selectedIndex = 0; event.preventDefault(); } }, - filter_key_up: function(event, field_id, source, filter_input) { - const input = filter_input || '_input'; + filter_key_up: function (event, field_id, source, filter_input) { + const input = filter_input || "_input"; const source_box = document.getElementById(field_id + source); const temp = source_box.selectedIndex; - SelectBox.filter(field_id + source, document.getElementById(field_id + input).value); + SelectBox.filter( + field_id + source, + document.getElementById(field_id + input).value, + ); source_box.selectedIndex = temp; SelectFilter.refresh_filtered_warning(field_id); SelectFilter.refresh_icons(field_id); }, - filter_key_down: function(event, field_id, source, target) { + filter_key_down: function (event, field_id, source, target) { const source_box = document.getElementById(field_id + source); // right key (39) or left key (37) - const direction = source === '_from' ? 39 : 37; + const direction = source === "_from" ? 39 : 37; // right arrow -- move across - if ((event.which && event.which === direction) || (event.keyCode && event.keyCode === direction)) { + if ( + (event.which && event.which === direction) || + (event.keyCode && event.keyCode === direction) + ) { const old_index = source_box.selectedIndex; SelectBox.move(field_id + source, field_id + target); SelectFilter.refresh_filtered_selects(field_id); SelectFilter.refresh_filtered_warning(field_id); - source_box.selectedIndex = (old_index === source_box.length) ? source_box.length - 1 : old_index; + source_box.selectedIndex = + old_index === source_box.length + ? source_box.length - 1 + : old_index; return; } // down arrow -- wrap around - if ((event.which && event.which === 40) || (event.keyCode && event.keyCode === 40)) { - source_box.selectedIndex = (source_box.length === source_box.selectedIndex + 1) ? 0 : source_box.selectedIndex + 1; + if ( + (event.which && event.which === 40) || + (event.keyCode && event.keyCode === 40) + ) { + source_box.selectedIndex = + source_box.length === source_box.selectedIndex + 1 + ? 0 + : source_box.selectedIndex + 1; } // up arrow -- wrap around - if ((event.which && event.which === 38) || (event.keyCode && event.keyCode === 38)) { - source_box.selectedIndex = (source_box.selectedIndex === 0) ? source_box.length - 1 : source_box.selectedIndex - 1; + if ( + (event.which && event.which === 38) || + (event.keyCode && event.keyCode === 38) + ) { + source_box.selectedIndex = + source_box.selectedIndex === 0 + ? source_box.length - 1 + : source_box.selectedIndex - 1; } - } + }, }; - window.addEventListener('load', function(e) { - document.querySelectorAll('select.selectfilter, select.selectfilterstacked').forEach(function(el) { - const data = el.dataset; - SelectFilter.init(el.id, data.fieldName, parseInt(data.isStacked, 10)); - }); + window.addEventListener("load", function (e) { + document + .querySelectorAll("select.selectfilter, select.selectfilterstacked") + .forEach(function (el) { + const data = el.dataset; + SelectFilter.init( + el.id, + data.fieldName, + parseInt(data.isStacked, 10), + ); + }); }); } diff --git a/django/contrib/admin/static/admin/js/actions.js b/django/contrib/admin/static/admin/js/actions.js index 04b25e9684..e302bb4b22 100644 --- a/django/contrib/admin/static/admin/js/actions.js +++ b/django/contrib/admin/static/admin/js/actions.js @@ -1,15 +1,15 @@ /*global gettext, interpolate, ngettext, Actions*/ -'use strict'; +"use strict"; { function show(selector) { - document.querySelectorAll(selector).forEach(function(el) { - el.classList.remove('hidden'); + document.querySelectorAll(selector).forEach(function (el) { + el.classList.remove("hidden"); }); } function hide(selector) { - document.querySelectorAll(selector).forEach(function(el) { - el.classList.add('hidden'); + document.querySelectorAll(selector).forEach(function (el) { + el.classList.add("hidden"); }); } @@ -22,7 +22,9 @@ function showClear(options) { show(options.acrossClears); hide(options.acrossQuestions); - document.querySelector(options.actionContainer).classList.remove(options.selectedClass); + document + .querySelector(options.actionContainer) + .classList.remove(options.selectedClass); show(options.allContainer); hide(options.counterContainer); } @@ -37,10 +39,12 @@ function clearAcross(options) { reset(options); const acrossInputs = document.querySelectorAll(options.acrossInput); - acrossInputs.forEach(function(acrossInput) { + acrossInputs.forEach(function (acrossInput) { acrossInput.value = 0; }); - document.querySelector(options.actionContainer).classList.remove(options.selectedClass); + document + .querySelector(options.actionContainer) + .classList.remove(options.selectedClass); } function checker(actionCheckboxes, options, checked) { @@ -49,14 +53,14 @@ } else { reset(options); } - actionCheckboxes.forEach(function(el) { + actionCheckboxes.forEach(function (el) { el.checked = checked; - el.closest('tr').classList.toggle(options.selectedClass, checked); + el.closest("tr").classList.toggle(options.selectedClass, checked); }); } function updateCounter(actionCheckboxes, options) { - const sel = Array.from(actionCheckboxes).filter(function(el) { + const sel = Array.from(actionCheckboxes).filter(function (el) { return el.checked; }).length; const counter = document.querySelector(options.counterContainer); @@ -64,10 +68,17 @@ // and contains the total amount of objects in the queryset const actions_icnt = Number(counter.dataset.actionsIcnt); counter.textContent = interpolate( - ngettext('%(sel)s of %(cnt)s selected', '%(sel)s of %(cnt)s selected', sel), { + ngettext( + "%(sel)s of %(cnt)s selected", + "%(sel)s of %(cnt)s selected", + sel, + ), + { sel: sel, - cnt: actions_icnt - }, true); + cnt: actions_icnt, + }, + true, + ); const allToggle = document.getElementById(options.allToggleId); allToggle.checked = sel === actionCheckboxes.length; if (allToggle.checked) { @@ -85,94 +96,123 @@ acrossQuestions: "div.actions span.question", acrossClears: "div.actions span.clear", allToggleId: "action-toggle", - selectedClass: "selected" + selectedClass: "selected", }; - window.Actions = function(actionCheckboxes, options) { + window.Actions = function (actionCheckboxes, options) { options = Object.assign({}, defaults, options); let list_editable_changed = false; let lastChecked = null; let shiftPressed = false; - document.addEventListener('keydown', (event) => { + document.addEventListener("keydown", (event) => { shiftPressed = event.shiftKey; }); - document.addEventListener('keyup', (event) => { + document.addEventListener("keyup", (event) => { shiftPressed = event.shiftKey; }); - document.getElementById(options.allToggleId).addEventListener('click', function(event) { - checker(actionCheckboxes, options, this.checked); - updateCounter(actionCheckboxes, options); - }); + document + .getElementById(options.allToggleId) + .addEventListener("click", function (event) { + checker(actionCheckboxes, options, this.checked); + updateCounter(actionCheckboxes, options); + }); - document.querySelectorAll(options.acrossQuestions + " a").forEach(function(el) { - el.addEventListener('click', function(event) { - event.preventDefault(); - const acrossInputs = document.querySelectorAll(options.acrossInput); - acrossInputs.forEach(function(acrossInput) { - acrossInput.value = 1; + document + .querySelectorAll(options.acrossQuestions + " a") + .forEach(function (el) { + el.addEventListener("click", function (event) { + event.preventDefault(); + const acrossInputs = document.querySelectorAll( + options.acrossInput, + ); + acrossInputs.forEach(function (acrossInput) { + acrossInput.value = 1; + }); + showClear(options); }); - showClear(options); }); - }); - document.querySelectorAll(options.acrossClears + " a").forEach(function(el) { - el.addEventListener('click', function(event) { - event.preventDefault(); - document.getElementById(options.allToggleId).checked = false; - clearAcross(options); - checker(actionCheckboxes, options, false); - updateCounter(actionCheckboxes, options); + document + .querySelectorAll(options.acrossClears + " a") + .forEach(function (el) { + el.addEventListener("click", function (event) { + event.preventDefault(); + document.getElementById(options.allToggleId).checked = + false; + clearAcross(options); + checker(actionCheckboxes, options, false); + updateCounter(actionCheckboxes, options); + }); }); - }); function affectedCheckboxes(target, withModifier) { - const multiSelect = (lastChecked && withModifier && lastChecked !== target); + const multiSelect = + lastChecked && withModifier && lastChecked !== target; if (!multiSelect) { return [target]; } const checkboxes = Array.from(actionCheckboxes); - const targetIndex = checkboxes.findIndex(el => el === target); - const lastCheckedIndex = checkboxes.findIndex(el => el === lastChecked); + const targetIndex = checkboxes.findIndex((el) => el === target); + const lastCheckedIndex = checkboxes.findIndex( + (el) => el === lastChecked, + ); const startIndex = Math.min(targetIndex, lastCheckedIndex); const endIndex = Math.max(targetIndex, lastCheckedIndex); - const filtered = checkboxes.filter((el, index) => (startIndex <= index) && (index <= endIndex)); + const filtered = checkboxes.filter( + (el, index) => startIndex <= index && index <= endIndex, + ); return filtered; - }; + } - Array.from(document.getElementById('result_list').tBodies).forEach(function(el) { - el.addEventListener('change', function(event) { - const target = event.target; - if (target.classList.contains('action-select')) { - const checkboxes = affectedCheckboxes(target, shiftPressed); - checker(checkboxes, options, target.checked); - updateCounter(actionCheckboxes, options); - lastChecked = target; - } else { - list_editable_changed = true; - } - }); - }); + Array.from(document.getElementById("result_list").tBodies).forEach( + function (el) { + el.addEventListener("change", function (event) { + const target = event.target; + if (target.classList.contains("action-select")) { + const checkboxes = affectedCheckboxes( + target, + shiftPressed, + ); + checker(checkboxes, options, target.checked); + updateCounter(actionCheckboxes, options); + lastChecked = target; + } else { + list_editable_changed = true; + } + }); + }, + ); - document.querySelector('#changelist-form button[name=index]').addEventListener('click', function(event) { - if (list_editable_changed) { - const confirmed = confirm(gettext("You have unsaved changes on individual editable fields. If you run an action, your unsaved changes will be lost.")); - if (!confirmed) { - event.preventDefault(); + document + .querySelector("#changelist-form button[name=index]") + .addEventListener("click", function (event) { + if (list_editable_changed) { + const confirmed = confirm( + gettext( + "You have unsaved changes on individual editable fields. If you run an action, your unsaved changes will be lost.", + ), + ); + if (!confirmed) { + event.preventDefault(); + } } - } - }); + }); - const el = document.querySelector('#changelist-form input[name=_save]'); + const el = document.querySelector("#changelist-form input[name=_save]"); // The button does not exist if no fields are editable. if (el) { - el.addEventListener('click', function(event) { - if (document.querySelector('[name=action]').value) { + el.addEventListener("click", function (event) { + if (document.querySelector("[name=action]").value) { const text = list_editable_changed - ? gettext("You have selected an action, but you haven’t saved your changes to individual fields yet. Please click OK to save. You’ll need to re-run the action.") - : gettext("You have selected an action, and you haven’t made any changes on individual fields. You’re probably looking for the Go button rather than the Save button."); + ? gettext( + "You have selected an action, but you haven’t saved your changes to individual fields yet. Please click OK to save. You’ll need to re-run the action.", + ) + : gettext( + "You have selected an action, and you haven’t made any changes on individual fields. You’re probably looking for the Go button rather than the Save button.", + ); if (!confirm(text)) { event.preventDefault(); } @@ -181,22 +221,24 @@ } // Sync counter when navigating to the page, such as through the back // button. - window.addEventListener('pageshow', (event) => updateCounter(actionCheckboxes, options)); + window.addEventListener("pageshow", (event) => + updateCounter(actionCheckboxes, options), + ); }; // Call function fn when the DOM is loaded and ready. If it is already // loaded, call the function now. // http://youmightnotneedjquery.com/#ready function ready(fn) { - if (document.readyState !== 'loading') { + if (document.readyState !== "loading") { fn(); } else { - document.addEventListener('DOMContentLoaded', fn); + document.addEventListener("DOMContentLoaded", fn); } } - ready(function() { - const actionsEls = document.querySelectorAll('tr input.action-select'); + ready(function () { + const actionsEls = document.querySelectorAll("tr input.action-select"); if (actionsEls.length > 0) { Actions(actionsEls); } diff --git a/django/contrib/admin/static/admin/js/admin/DateTimeShortcuts.js b/django/contrib/admin/static/admin/js/admin/DateTimeShortcuts.js index b30a668a2e..6f71b25152 100644 --- a/django/contrib/admin/static/admin/js/admin/DateTimeShortcuts.js +++ b/django/contrib/admin/static/admin/js/admin/DateTimeShortcuts.js @@ -2,7 +2,7 @@ // Inserts shortcut buttons after all of the following: // <input type="text" class="vDateField"> // <input type="text" class="vTimeField"> -'use strict'; +"use strict"; { const DateTimeShortcuts = { calendars: [], @@ -10,55 +10,62 @@ clockInputs: [], clockHours: { default_: [ - [gettext_noop('Now'), -1], - [gettext_noop('Midnight'), 0], - [gettext_noop('6 a.m.'), 6], - [gettext_noop('Noon'), 12], - [gettext_noop('6 p.m.'), 18] - ] + [gettext_noop("Now"), -1], + [gettext_noop("Midnight"), 0], + [gettext_noop("6 a.m."), 6], + [gettext_noop("Noon"), 12], + [gettext_noop("6 p.m."), 18], + ], }, dismissClockFunc: [], dismissCalendarFunc: [], - calendarDivName1: 'calendarbox', // name of calendar <div> that gets toggled - calendarDivName2: 'calendarin', // name of <div> that contains calendar - calendarLinkName: 'calendarlink', // name of the link that is used to toggle - clockDivName: 'clockbox', // name of clock <div> that gets toggled - clockLinkName: 'clocklink', // name of the link that is used to toggle - shortCutsClass: 'datetimeshortcuts', // class of the clock and cal shortcuts - timezoneWarningClass: 'timezonewarning', // class of the warning for timezone mismatch + calendarDivName1: "calendarbox", // name of calendar <div> that gets toggled + calendarDivName2: "calendarin", // name of <div> that contains calendar + calendarLinkName: "calendarlink", // name of the link that is used to toggle + clockDivName: "clockbox", // name of clock <div> that gets toggled + clockLinkName: "clocklink", // name of the link that is used to toggle + shortCutsClass: "datetimeshortcuts", // class of the clock and cal shortcuts + timezoneWarningClass: "timezonewarning", // class of the warning for timezone mismatch timezoneOffset: 0, - init: function() { + init: function () { const serverOffset = document.body.dataset.adminUtcOffset; if (serverOffset) { const localOffset = new Date().getTimezoneOffset() * -60; DateTimeShortcuts.timezoneOffset = localOffset - serverOffset; } - for (const inp of document.getElementsByTagName('input')) { - if (inp.type === 'text' && inp.classList.contains('vTimeField')) { + for (const inp of document.getElementsByTagName("input")) { + if ( + inp.type === "text" && + inp.classList.contains("vTimeField") + ) { DateTimeShortcuts.addClock(inp); DateTimeShortcuts.addTimezoneWarning(inp); - } - else if (inp.type === 'text' && inp.classList.contains('vDateField')) { + } else if ( + inp.type === "text" && + inp.classList.contains("vDateField") + ) { DateTimeShortcuts.addCalendar(inp); DateTimeShortcuts.addTimezoneWarning(inp); } } }, // Return the current time while accounting for the server timezone. - now: function() { + now: function () { const serverOffset = document.body.dataset.adminUtcOffset; if (serverOffset) { const localNow = new Date(); const localOffset = localNow.getTimezoneOffset() * -60; - localNow.setTime(localNow.getTime() + 1000 * (serverOffset - localOffset)); + localNow.setTime( + localNow.getTime() + 1000 * (serverOffset - localOffset), + ); return localNow; } else { return new Date(); } }, // Add a warning when the time zone in the browser and backend do not match. - addTimezoneWarning: function(inp) { + addTimezoneWarning: function (inp) { const warningClass = DateTimeShortcuts.timezoneWarningClass; let timezoneOffset = DateTimeShortcuts.timezoneOffset / 3600; @@ -68,35 +75,40 @@ } // Check if warning is already there. - if (inp.parentNode.parentNode.querySelectorAll('.' + warningClass).length) { + if ( + inp.parentNode.parentNode.querySelectorAll("." + warningClass) + .length + ) { return; } let message; if (timezoneOffset > 0) { message = ngettext( - 'Note: You are %s hour ahead of server time.', - 'Note: You are %s hours ahead of server time.', - timezoneOffset + "Note: You are %s hour ahead of server time.", + "Note: You are %s hours ahead of server time.", + timezoneOffset, ); - } - else { + } else { timezoneOffset *= -1; message = ngettext( - 'Note: You are %s hour behind server time.', - 'Note: You are %s hours behind server time.', - timezoneOffset + "Note: You are %s hour behind server time.", + "Note: You are %s hours behind server time.", + timezoneOffset, ); } message = interpolate(message, [timezoneOffset]); - const warning = document.createElement('div'); + const warning = document.createElement("div"); const id = inp.id; - const field_id = inp.closest('p.datetime') ? id.slice(0, id.lastIndexOf("_")) : id; - warning.classList.add('help', warningClass); + const field_id = inp.closest("p.datetime") + ? id.slice(0, id.lastIndexOf("_")) + : id; + warning.classList.add("help", warningClass); warning.id = `${field_id}_timezone_warning_helptext`; warning.textContent = message; - const errorList = inp.parentNode.parentNode.querySelector('ul.errorlist'); + const errorList = + inp.parentNode.parentNode.querySelector("ul.errorlist"); if (errorList) { errorList.before(warning); } else { @@ -104,27 +116,30 @@ } }, // Add clock widget to a given field - addClock: function(inp) { + addClock: function (inp) { const num = DateTimeShortcuts.clockInputs.length; DateTimeShortcuts.clockInputs[num] = inp; - DateTimeShortcuts.dismissClockFunc[num] = function() { DateTimeShortcuts.dismissClock(num); return true; }; + DateTimeShortcuts.dismissClockFunc[num] = function () { + DateTimeShortcuts.dismissClock(num); + return true; + }; // Shortcut links (clock icon and "Now" link) - const shortcuts_span = document.createElement('span'); + const shortcuts_span = document.createElement("span"); shortcuts_span.className = DateTimeShortcuts.shortCutsClass; inp.parentNode.insertBefore(shortcuts_span, inp.nextSibling); - const now_link = document.createElement('a'); + const now_link = document.createElement("a"); now_link.href = "#"; - now_link.textContent = gettext('Now'); - now_link.role = 'button'; - now_link.addEventListener('click', function(e) { + now_link.textContent = gettext("Now"); + now_link.role = "button"; + now_link.addEventListener("click", function (e) { e.preventDefault(); DateTimeShortcuts.handleClockQuicklink(num, -1); }); - const clock_link = document.createElement('a'); - clock_link.href = '#'; + const clock_link = document.createElement("a"); + clock_link.href = "#"; clock_link.id = DateTimeShortcuts.clockLinkName + num; - clock_link.addEventListener('click', function(e) { + clock_link.addEventListener("click", function (e) { e.preventDefault(); // avoid triggering the document click handler to dismiss the clock e.stopPropagation(); @@ -132,13 +147,19 @@ }); quickElement( - 'span', clock_link, '', - 'class', 'clock-icon', - 'title', gettext('Choose a Time') + "span", + clock_link, + "", + "class", + "clock-icon", + "title", + gettext("Choose a Time"), ); - shortcuts_span.appendChild(document.createTextNode('\u00A0')); + shortcuts_span.appendChild(document.createTextNode("\u00A0")); shortcuts_span.appendChild(now_link); - shortcuts_span.appendChild(document.createTextNode('\u00A0|\u00A0')); + shortcuts_span.appendChild( + document.createTextNode("\u00A0|\u00A0"), + ); shortcuts_span.appendChild(clock_link); // Create clock link div @@ -156,38 +177,59 @@ // <p class="calendar-cancel"><a href="#">Cancel</a></p> // </div> - const clock_box = document.createElement('div'); - clock_box.style.display = 'none'; - clock_box.style.position = 'absolute'; - clock_box.className = 'clockbox module'; + const clock_box = document.createElement("div"); + clock_box.style.display = "none"; + clock_box.style.position = "absolute"; + clock_box.className = "clockbox module"; clock_box.id = DateTimeShortcuts.clockDivName + num; document.body.appendChild(clock_box); - clock_box.addEventListener('click', function(e) { e.stopPropagation(); }); + clock_box.addEventListener("click", function (e) { + e.stopPropagation(); + }); - quickElement('h2', clock_box, gettext('Choose a time')); - const time_list = quickElement('ul', clock_box); - time_list.className = 'timelist'; + quickElement("h2", clock_box, gettext("Choose a time")); + const time_list = quickElement("ul", clock_box); + time_list.className = "timelist"; // The list of choices can be overridden in JavaScript like this: // DateTimeShortcuts.clockHours.name = [['3 a.m.', 3]]; // where name is the name attribute of the <input>. - const name = typeof DateTimeShortcuts.clockHours[inp.name] === 'undefined' ? 'default_' : inp.name; - DateTimeShortcuts.clockHours[name].forEach(function(element) { - const time_link = quickElement('a', quickElement('li', time_list), gettext(element[0]), 'role', 'button', 'href', '#'); - time_link.addEventListener('click', function(e) { + const name = + typeof DateTimeShortcuts.clockHours[inp.name] === "undefined" + ? "default_" + : inp.name; + DateTimeShortcuts.clockHours[name].forEach(function (element) { + const time_link = quickElement( + "a", + quickElement("li", time_list), + gettext(element[0]), + "role", + "button", + "href", + "#", + ); + time_link.addEventListener("click", function (e) { e.preventDefault(); DateTimeShortcuts.handleClockQuicklink(num, element[1]); }); }); - const cancel_p = quickElement('p', clock_box); - cancel_p.className = 'calendar-cancel'; - const cancel_link = quickElement('a', cancel_p, gettext('Cancel'), 'role', 'button', 'href', '#'); - cancel_link.addEventListener('click', function(e) { + const cancel_p = quickElement("p", clock_box); + cancel_p.className = "calendar-cancel"; + const cancel_link = quickElement( + "a", + cancel_p, + gettext("Cancel"), + "role", + "button", + "href", + "#", + ); + cancel_link.addEventListener("click", function (e) { e.preventDefault(); DateTimeShortcuts.dismissClock(num); }); - document.addEventListener('keyup', function(event) { + document.addEventListener("keyup", function (event) { if (event.which === 27) { // ESC key closes popup DateTimeShortcuts.dismissClock(num); @@ -195,78 +237,99 @@ } }); }, - openClock: function(num) { - const clock_box = document.getElementById(DateTimeShortcuts.clockDivName + num); - const clock_link = document.getElementById(DateTimeShortcuts.clockLinkName + num); + openClock: function (num) { + const clock_box = document.getElementById( + DateTimeShortcuts.clockDivName + num, + ); + const clock_link = document.getElementById( + DateTimeShortcuts.clockLinkName + num, + ); // Recalculate the clockbox position // is it left-to-right or right-to-left layout ? - if (window.getComputedStyle(document.body).direction !== 'rtl') { - clock_box.style.left = findPosX(clock_link) + 17 + 'px'; - } - else { + if (window.getComputedStyle(document.body).direction !== "rtl") { + clock_box.style.left = findPosX(clock_link) + 17 + "px"; + } else { // since style's width is in em, it'd be tough to calculate // px value of it. let's use an estimated px for now - clock_box.style.left = findPosX(clock_link) - 110 + 'px'; + clock_box.style.left = findPosX(clock_link) - 110 + "px"; } - clock_box.style.top = Math.max(0, findPosY(clock_link) - 30) + 'px'; + clock_box.style.top = Math.max(0, findPosY(clock_link) - 30) + "px"; // Show the clock box - clock_box.style.display = 'block'; - document.addEventListener('click', DateTimeShortcuts.dismissClockFunc[num]); + clock_box.style.display = "block"; + document.addEventListener( + "click", + DateTimeShortcuts.dismissClockFunc[num], + ); }, - dismissClock: function(num) { - document.getElementById(DateTimeShortcuts.clockDivName + num).style.display = 'none'; - document.removeEventListener('click', DateTimeShortcuts.dismissClockFunc[num]); + dismissClock: function (num) { + document.getElementById( + DateTimeShortcuts.clockDivName + num, + ).style.display = "none"; + document.removeEventListener( + "click", + DateTimeShortcuts.dismissClockFunc[num], + ); }, - handleClockQuicklink: function(num, val) { + handleClockQuicklink: function (num, val) { let d; if (val === -1) { d = DateTimeShortcuts.now(); - } - else { + } else { d = new Date(1970, 1, 1, val, 0, 0, 0); } - DateTimeShortcuts.clockInputs[num].value = d.strftime(get_format('TIME_INPUT_FORMATS')[0]); + DateTimeShortcuts.clockInputs[num].value = d.strftime( + get_format("TIME_INPUT_FORMATS")[0], + ); DateTimeShortcuts.clockInputs[num].focus(); DateTimeShortcuts.dismissClock(num); }, // Add calendar widget to a given field. - addCalendar: function(inp) { + addCalendar: function (inp) { const num = DateTimeShortcuts.calendars.length; DateTimeShortcuts.calendarInputs[num] = inp; - DateTimeShortcuts.dismissCalendarFunc[num] = function() { DateTimeShortcuts.dismissCalendar(num); return true; }; + DateTimeShortcuts.dismissCalendarFunc[num] = function () { + DateTimeShortcuts.dismissCalendar(num); + return true; + }; // Shortcut links (calendar icon and "Today" link) - const shortcuts_span = document.createElement('span'); + const shortcuts_span = document.createElement("span"); shortcuts_span.className = DateTimeShortcuts.shortCutsClass; inp.parentNode.insertBefore(shortcuts_span, inp.nextSibling); - const today_link = document.createElement('a'); - today_link.href = '#'; - today_link.role = 'button'; - today_link.appendChild(document.createTextNode(gettext('Today'))); - today_link.addEventListener('click', function(e) { + const today_link = document.createElement("a"); + today_link.href = "#"; + today_link.role = "button"; + today_link.appendChild(document.createTextNode(gettext("Today"))); + today_link.addEventListener("click", function (e) { e.preventDefault(); DateTimeShortcuts.handleCalendarQuickLink(num, 0); }); - const cal_link = document.createElement('a'); - cal_link.href = '#'; + const cal_link = document.createElement("a"); + cal_link.href = "#"; cal_link.id = DateTimeShortcuts.calendarLinkName + num; - cal_link.addEventListener('click', function(e) { + cal_link.addEventListener("click", function (e) { e.preventDefault(); // avoid triggering the document click handler to dismiss the calendar e.stopPropagation(); DateTimeShortcuts.openCalendar(num); }); quickElement( - 'span', cal_link, '', - 'class', 'date-icon', - 'title', gettext('Choose a Date') + "span", + cal_link, + "", + "class", + "date-icon", + "title", + gettext("Choose a Date"), ); - shortcuts_span.appendChild(document.createTextNode('\u00A0')); + shortcuts_span.appendChild(document.createTextNode("\u00A0")); shortcuts_span.appendChild(today_link); - shortcuts_span.appendChild(document.createTextNode('\u00A0|\u00A0')); + shortcuts_span.appendChild( + document.createTextNode("\u00A0|\u00A0"), + ); shortcuts_span.appendChild(cal_link); // Create calendarbox div. @@ -286,66 +349,109 @@ // </div> // <p class="calendar-cancel"><a href="#">Cancel</a></p> // </div> - const cal_box = document.createElement('div'); - cal_box.style.display = 'none'; - cal_box.style.position = 'absolute'; - cal_box.className = 'calendarbox module'; + const cal_box = document.createElement("div"); + cal_box.style.display = "none"; + cal_box.style.position = "absolute"; + cal_box.className = "calendarbox module"; cal_box.id = DateTimeShortcuts.calendarDivName1 + num; document.body.appendChild(cal_box); - cal_box.addEventListener('click', function(e) { e.stopPropagation(); }); + cal_box.addEventListener("click", function (e) { + e.stopPropagation(); + }); // next-prev links - const cal_nav = quickElement('div', cal_box); - const cal_nav_prev = quickElement('a', cal_nav, '<', 'href', '#'); - cal_nav_prev.className = 'calendarnav-previous'; - cal_nav_prev.addEventListener('click', function(e) { + const cal_nav = quickElement("div", cal_box); + const cal_nav_prev = quickElement("a", cal_nav, "<", "href", "#"); + cal_nav_prev.className = "calendarnav-previous"; + cal_nav_prev.addEventListener("click", function (e) { e.preventDefault(); DateTimeShortcuts.drawPrev(num); }); - const cal_nav_next = quickElement('a', cal_nav, '>', 'href', '#'); - cal_nav_next.className = 'calendarnav-next'; - cal_nav_next.addEventListener('click', function(e) { + const cal_nav_next = quickElement("a", cal_nav, ">", "href", "#"); + cal_nav_next.className = "calendarnav-next"; + cal_nav_next.addEventListener("click", function (e) { e.preventDefault(); DateTimeShortcuts.drawNext(num); }); // main box - const cal_main = quickElement('div', cal_box, '', 'id', DateTimeShortcuts.calendarDivName2 + num); - cal_main.className = 'calendar'; - DateTimeShortcuts.calendars[num] = new Calendar(DateTimeShortcuts.calendarDivName2 + num, DateTimeShortcuts.handleCalendarCallback(num)); + const cal_main = quickElement( + "div", + cal_box, + "", + "id", + DateTimeShortcuts.calendarDivName2 + num, + ); + cal_main.className = "calendar"; + DateTimeShortcuts.calendars[num] = new Calendar( + DateTimeShortcuts.calendarDivName2 + num, + DateTimeShortcuts.handleCalendarCallback(num), + ); DateTimeShortcuts.calendars[num].drawCurrent(); // calendar shortcuts - const shortcuts = quickElement('div', cal_box); - shortcuts.className = 'calendar-shortcuts'; - let day_link = quickElement('a', shortcuts, gettext('Yesterday'), 'role', 'button', 'href', '#'); - day_link.addEventListener('click', function(e) { + const shortcuts = quickElement("div", cal_box); + shortcuts.className = "calendar-shortcuts"; + let day_link = quickElement( + "a", + shortcuts, + gettext("Yesterday"), + "role", + "button", + "href", + "#", + ); + day_link.addEventListener("click", function (e) { e.preventDefault(); DateTimeShortcuts.handleCalendarQuickLink(num, -1); }); - shortcuts.appendChild(document.createTextNode('\u00A0|\u00A0')); - day_link = quickElement('a', shortcuts, gettext('Today'), 'role', 'button', 'href', '#'); - day_link.addEventListener('click', function(e) { + shortcuts.appendChild(document.createTextNode("\u00A0|\u00A0")); + day_link = quickElement( + "a", + shortcuts, + gettext("Today"), + "role", + "button", + "href", + "#", + ); + day_link.addEventListener("click", function (e) { e.preventDefault(); DateTimeShortcuts.handleCalendarQuickLink(num, 0); }); - shortcuts.appendChild(document.createTextNode('\u00A0|\u00A0')); - day_link = quickElement('a', shortcuts, gettext('Tomorrow'), 'role', 'button', 'href', '#'); - day_link.addEventListener('click', function(e) { + shortcuts.appendChild(document.createTextNode("\u00A0|\u00A0")); + day_link = quickElement( + "a", + shortcuts, + gettext("Tomorrow"), + "role", + "button", + "href", + "#", + ); + day_link.addEventListener("click", function (e) { e.preventDefault(); DateTimeShortcuts.handleCalendarQuickLink(num, +1); }); // cancel bar - const cancel_p = quickElement('p', cal_box); - cancel_p.className = 'calendar-cancel'; - const cancel_link = quickElement('a', cancel_p, gettext('Cancel'), 'role', 'button', 'href', '#'); - cancel_link.addEventListener('click', function(e) { + const cancel_p = quickElement("p", cal_box); + cancel_p.className = "calendar-cancel"; + const cancel_link = quickElement( + "a", + cancel_p, + gettext("Cancel"), + "role", + "button", + "href", + "#", + ); + cancel_link.addEventListener("click", function (e) { e.preventDefault(); DateTimeShortcuts.dismissCalendar(num); }); - document.addEventListener('keyup', function(event) { + document.addEventListener("keyup", function (event) { if (event.which === 27) { // ESC key closes popup DateTimeShortcuts.dismissCalendar(num); @@ -353,66 +459,89 @@ } }); }, - openCalendar: function(num) { - const cal_box = document.getElementById(DateTimeShortcuts.calendarDivName1 + num); - const cal_link = document.getElementById(DateTimeShortcuts.calendarLinkName + num); + openCalendar: function (num) { + const cal_box = document.getElementById( + DateTimeShortcuts.calendarDivName1 + num, + ); + const cal_link = document.getElementById( + DateTimeShortcuts.calendarLinkName + num, + ); const inp = DateTimeShortcuts.calendarInputs[num]; // Determine if the current value in the input has a valid date. // If so, draw the calendar with that date's year and month. if (inp.value) { - const format = get_format('DATE_INPUT_FORMATS')[0]; + const format = get_format("DATE_INPUT_FORMATS")[0]; const selected = inp.value.strptime(format); const year = selected.getUTCFullYear(); const month = selected.getUTCMonth() + 1; const re = /\d{4}/; if (re.test(year.toString()) && month >= 1 && month <= 12) { - DateTimeShortcuts.calendars[num].drawDate(month, year, selected); + DateTimeShortcuts.calendars[num].drawDate( + month, + year, + selected, + ); } } // Recalculate the clockbox position // is it left-to-right or right-to-left layout ? - if (window.getComputedStyle(document.body).direction !== 'rtl') { - cal_box.style.left = findPosX(cal_link) + 17 + 'px'; - } - else { + if (window.getComputedStyle(document.body).direction !== "rtl") { + cal_box.style.left = findPosX(cal_link) + 17 + "px"; + } else { // since style's width is in em, it'd be tough to calculate // px value of it. let's use an estimated px for now - cal_box.style.left = findPosX(cal_link) - 180 + 'px'; + cal_box.style.left = findPosX(cal_link) - 180 + "px"; } - cal_box.style.top = Math.max(0, findPosY(cal_link) - 75) + 'px'; + cal_box.style.top = Math.max(0, findPosY(cal_link) - 75) + "px"; - cal_box.style.display = 'block'; - document.addEventListener('click', DateTimeShortcuts.dismissCalendarFunc[num]); + cal_box.style.display = "block"; + document.addEventListener( + "click", + DateTimeShortcuts.dismissCalendarFunc[num], + ); }, - dismissCalendar: function(num) { - document.getElementById(DateTimeShortcuts.calendarDivName1 + num).style.display = 'none'; - document.removeEventListener('click', DateTimeShortcuts.dismissCalendarFunc[num]); + dismissCalendar: function (num) { + document.getElementById( + DateTimeShortcuts.calendarDivName1 + num, + ).style.display = "none"; + document.removeEventListener( + "click", + DateTimeShortcuts.dismissCalendarFunc[num], + ); }, - drawPrev: function(num) { + drawPrev: function (num) { DateTimeShortcuts.calendars[num].drawPreviousMonth(); }, - drawNext: function(num) { + drawNext: function (num) { DateTimeShortcuts.calendars[num].drawNextMonth(); }, - handleCalendarCallback: function(num) { - const format = get_format('DATE_INPUT_FORMATS')[0]; - return function(y, m, d) { - DateTimeShortcuts.calendarInputs[num].value = new Date(y, m - 1, d).strftime(format); + handleCalendarCallback: function (num) { + const format = get_format("DATE_INPUT_FORMATS")[0]; + return function (y, m, d) { + DateTimeShortcuts.calendarInputs[num].value = new Date( + y, + m - 1, + d, + ).strftime(format); DateTimeShortcuts.calendarInputs[num].focus(); - document.getElementById(DateTimeShortcuts.calendarDivName1 + num).style.display = 'none'; + document.getElementById( + DateTimeShortcuts.calendarDivName1 + num, + ).style.display = "none"; }; }, - handleCalendarQuickLink: function(num, offset) { + handleCalendarQuickLink: function (num, offset) { const d = DateTimeShortcuts.now(); d.setDate(d.getDate() + offset); - DateTimeShortcuts.calendarInputs[num].value = d.strftime(get_format('DATE_INPUT_FORMATS')[0]); + DateTimeShortcuts.calendarInputs[num].value = d.strftime( + get_format("DATE_INPUT_FORMATS")[0], + ); DateTimeShortcuts.calendarInputs[num].focus(); DateTimeShortcuts.dismissCalendar(num); - } + }, }; - window.addEventListener('load', DateTimeShortcuts.init); + window.addEventListener("load", DateTimeShortcuts.init); window.DateTimeShortcuts = DateTimeShortcuts; } diff --git a/django/contrib/admin/static/admin/js/admin/RelatedObjectLookups.js b/django/contrib/admin/static/admin/js/admin/RelatedObjectLookups.js index fb5db940d6..a9c06ad4ae 100644 --- a/django/contrib/admin/static/admin/js/admin/RelatedObjectLookups.js +++ b/django/contrib/admin/static/admin/js/admin/RelatedObjectLookups.js @@ -1,25 +1,25 @@ /*global SelectBox, interpolate*/ // Handles related-objects functionality: lookup link for raw_id_fields // and Add Another links. -'use strict'; +"use strict"; { const $ = django.jQuery; let popupIndex = 0; const relatedWindows = []; function dismissChildPopups() { - relatedWindows.forEach(function(win) { - if(!win.closed) { + relatedWindows.forEach(function (win) { + if (!win.closed) { win.dismissChildPopups(); - win.close(); + win.close(); } }); } function setPopupIndex() { - if(document.getElementsByName("_popup").length > 0) { + if (document.getElementsByName("_popup").length > 0) { const index = window.name.lastIndexOf("__") + 2; - popupIndex = parseInt(window.name.substring(index)); + popupIndex = parseInt(window.name.substring(index)); } else { popupIndex = 0; } @@ -30,16 +30,20 @@ } function removePopupIndex(name) { - return name.replace(new RegExp("__" + (popupIndex + 1) + "$"), ''); + return name.replace(new RegExp("__" + (popupIndex + 1) + "$"), ""); } function showAdminPopup(triggeringLink, name_regexp, add_popup) { - const name = addPopupIndex(triggeringLink.id.replace(name_regexp, '')); + const name = addPopupIndex(triggeringLink.id.replace(name_regexp, "")); const href = new URL(triggeringLink.href); if (add_popup) { - href.searchParams.set('_popup', 1); + href.searchParams.set("_popup", 1); } - const win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes'); + const win = window.open( + href, + name, + "height=500,width=800,resizable=yes,scrollbars=yes", + ); relatedWindows.push(win); win.focus(); return false; @@ -52,12 +56,15 @@ function dismissRelatedLookupPopup(win, chosenId) { const name = removePopupIndex(win.name); const elem = document.getElementById(name); - if (elem.classList.contains('vManyToManyRawIdAdminField') && elem.value) { - elem.value += ',' + chosenId; + if ( + elem.classList.contains("vManyToManyRawIdAdminField") && + elem.value + ) { + elem.value += "," + chosenId; } else { elem.value = chosenId; } - $(elem).trigger('change'); + $(elem).trigger("change"); const index = relatedWindows.indexOf(win); if (index > -1) { relatedWindows.splice(index, 1); @@ -71,24 +78,36 @@ function updateRelatedObjectLinks(triggeringLink) { const $this = $(triggeringLink); - const siblings = $this.nextAll('.view-related, .change-related, .delete-related'); + const siblings = $this.nextAll( + ".view-related, .change-related, .delete-related", + ); if (!siblings.length) { return; } const value = $this.val(); if (value) { - siblings.each(function() { + siblings.each(function () { const elm = $(this); - elm.attr('href', elm.attr('data-href-template').replace('__fk__', value)); - elm.removeAttr('aria-disabled'); + elm.attr( + "href", + elm.attr("data-href-template").replace("__fk__", value), + ); + elm.removeAttr("aria-disabled"); }); } else { - siblings.removeAttr('href'); - siblings.attr('aria-disabled', true); + siblings.removeAttr("href"); + siblings.attr("aria-disabled", true); } } - function updateRelatedSelectsOptions(currentSelect, win, objId, newRepr, newId, skipIds = []) { + function updateRelatedSelectsOptions( + currentSelect, + win, + objId, + newRepr, + newId, + skipIds = [], + ) { // After create/edit a model from the options next to the current // select (+ or :pencil:) update ForeignKey PK of the rest of selects // in the page. @@ -96,12 +115,18 @@ const path = win.location.pathname; // Extract the model from the popup url '.../<model>/add/' or // '.../<model>/<id>/change/' depending the action (add or change). - const modelName = path.split('/')[path.split('/').length - (objId ? 4 : 3)]; + const modelName = + path.split("/")[path.split("/").length - (objId ? 4 : 3)]; // Select elements with a specific model reference and context of "available-source". - const selectsRelated = document.querySelectorAll(`[data-model-ref="${modelName}"] [data-context="available-source"]`); + const selectsRelated = document.querySelectorAll( + `[data-model-ref="${modelName}"] [data-context="available-source"]`, + ); - selectsRelated.forEach(function(select) { - if (currentSelect === select || skipIds && skipIds.includes(select.id)) { + selectsRelated.forEach(function (select) { + if ( + currentSelect === select || + (skipIds && skipIds.includes(select.id)) + ) { return; } @@ -112,14 +137,14 @@ select.options.add(option); // Update SelectBox cache for related fields. if ( - window.SelectBox !== undefined - && !SelectBox.cache[currentSelect.id] + window.SelectBox !== undefined && + !SelectBox.cache[currentSelect.id] && // Only if SelectBox is managing that field. - && SelectBox.cache[select.id] + SelectBox.cache[select.id] ) { SelectBox.add_to_cache(select.id, option); // Sort if there are any groups present - if (SelectBox.cache[select.id].some(item => item.group)) { + if (SelectBox.cache[select.id].some((item) => item.group)) { SelectBox.sort(select.id); } SelectBox.redisplay(select.id); @@ -137,18 +162,26 @@ const elem = document.getElementById(name); if (elem) { const elemName = elem.nodeName.toUpperCase(); - if (elemName === 'SELECT') { - elem.options[elem.options.length] = new Option(newRepr, newId, true, true); + if (elemName === "SELECT") { + elem.options[elem.options.length] = new Option( + newRepr, + newId, + true, + true, + ); updateRelatedSelectsOptions(elem, win, null, newRepr, newId); - } else if (elemName === 'INPUT') { - if (elem.classList.contains('vManyToManyRawIdAdminField') && elem.value) { - elem.value += ',' + newId; + } else if (elemName === "INPUT") { + if ( + elem.classList.contains("vManyToManyRawIdAdminField") && + elem.value + ) { + elem.value += "," + newId; } else { elem.value = newId; } } // Trigger a change event to update related links if required. - $(elem).trigger('change'); + $(elem).trigger("change"); } else { const toId = name + "_to"; const toElem = document.getElementById(toId); @@ -156,13 +189,20 @@ newOption.group = optgroup; SelectBox.add_to_cache(toId, newOption); // Sort if there are any groups present - if (SelectBox.cache[toId].some(item => item.group)) { + if (SelectBox.cache[toId].some((item) => item.group)) { SelectBox.sort(toId); } SelectBox.redisplay(toId); - if (toElem && toElem.nodeName.toUpperCase() === 'SELECT') { + if (toElem && toElem.nodeName.toUpperCase() === "SELECT") { const skipIds = [name + "_from"]; - updateRelatedSelectsOptions(toElem, win, null, newRepr, newId, skipIds); + updateRelatedSelectsOptions( + toElem, + win, + null, + newRepr, + newId, + skipIds, + ); } } const index = relatedWindows.indexOf(win); @@ -173,22 +213,32 @@ } function dismissChangeRelatedObjectPopup(win, objId, newRepr, newId) { - const id = removePopupIndex(win.name.replace(/^edit_/, '')); - const selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]); + const id = removePopupIndex(win.name.replace(/^edit_/, "")); + const selectsSelector = interpolate("#%s, #%s_from, #%s_to", [ + id, + id, + id, + ]); const selects = $(selectsSelector); - selects.find('option').each(function() { - if (this.value === objId) { - this.textContent = newRepr; - this.value = newId; - } - }).trigger('change'); + selects + .find("option") + .each(function () { + if (this.value === objId) { + this.textContent = newRepr; + this.value = newId; + } + }) + .trigger("change"); updateRelatedSelectsOptions(selects[0], win, objId, newRepr, newId); - selects.next().find('.select2-selection__rendered').each(function() { - // The element can have a clear button as a child. - // Use the lastChild to modify only the displayed value. - this.lastChild.textContent = newRepr; - this.title = newRepr; - }); + selects + .next() + .find(".select2-selection__rendered") + .each(function () { + // The element can have a clear button as a child. + // Use the lastChild to modify only the displayed value. + this.lastChild.textContent = newRepr; + this.title = newRepr; + }); const index = relatedWindows.indexOf(win); if (index > -1) { relatedWindows.splice(index, 1); @@ -197,14 +247,21 @@ } function dismissDeleteRelatedObjectPopup(win, objId) { - const id = removePopupIndex(win.name.replace(/^delete_/, '')); - const selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]); + const id = removePopupIndex(win.name.replace(/^delete_/, "")); + const selectsSelector = interpolate("#%s, #%s_from, #%s_to", [ + id, + id, + id, + ]); const selects = $(selectsSelector); - selects.find('option').each(function() { - if (this.value === objId) { - $(this).remove(); - } - }).trigger('change'); + selects + .find("option") + .each(function () { + if (this.value === objId) { + $(this).remove(); + } + }) + .trigger("change"); const index = relatedWindows.indexOf(win); if (index > -1) { relatedWindows.splice(index, 1); @@ -226,37 +283,46 @@ window.showAddAnotherPopup = showRelatedObjectPopup; window.dismissAddAnotherPopup = dismissAddRelatedObjectPopup; - window.addEventListener('unload', function(evt) { + window.addEventListener("unload", function (evt) { window.dismissChildPopups(); }); - $(document).ready(function() { + $(document).ready(function () { setPopupIndex(); - $("a[data-popup-opener]").on('click', function(event) { + $("a[data-popup-opener]").on("click", function (event) { event.preventDefault(); - opener.dismissRelatedLookupPopup(window, $(this).data("popup-opener")); + opener.dismissRelatedLookupPopup( + window, + $(this).data("popup-opener"), + ); }); - $('body').on('click', '.related-widget-wrapper-link[data-popup="yes"]', function(e) { - e.preventDefault(); - if (this.href) { - const event = $.Event('django:show-related', {href: this.href}); - $(this).trigger(event); - if (!event.isDefaultPrevented()) { - showRelatedObjectPopup(this); + $("body").on( + "click", + '.related-widget-wrapper-link[data-popup="yes"]', + function (e) { + e.preventDefault(); + if (this.href) { + const event = $.Event("django:show-related", { + href: this.href, + }); + $(this).trigger(event); + if (!event.isDefaultPrevented()) { + showRelatedObjectPopup(this); + } } - } - }); - $('body').on('change', '.related-widget-wrapper select', function(e) { - const event = $.Event('django:update-related'); + }, + ); + $("body").on("change", ".related-widget-wrapper select", function (e) { + const event = $.Event("django:update-related"); $(this).trigger(event); if (!event.isDefaultPrevented()) { updateRelatedObjectLinks(this); } }); - $('.related-widget-wrapper select').trigger('change'); - $('body').on('click', '.related-lookup', function(e) { + $(".related-widget-wrapper select").trigger("change"); + $("body").on("click", ".related-lookup", function (e) { e.preventDefault(); - const event = $.Event('django:lookup-related'); + const event = $.Event("django:lookup-related"); $(this).trigger(event); if (!event.isDefaultPrevented()) { showRelatedObjectLookupPopup(this); diff --git a/django/contrib/admin/static/admin/js/autocomplete.js b/django/contrib/admin/static/admin/js/autocomplete.js index d3daeab890..30fd5209ae 100644 --- a/django/contrib/admin/static/admin/js/autocomplete.js +++ b/django/contrib/admin/static/admin/js/autocomplete.js @@ -1,9 +1,9 @@ -'use strict'; +"use strict"; { const $ = django.jQuery; - $.fn.djangoAdminSelect2 = function() { - $.each(this, function(i, element) { + $.fn.djangoAdminSelect2 = function () { + $.each(this, function (i, element) { $(element).select2({ ajax: { data: (params) => { @@ -12,22 +12,22 @@ page: params.page, app_label: element.dataset.appLabel, model_name: element.dataset.modelName, - field_name: element.dataset.fieldName + field_name: element.dataset.fieldName, }; - } - } + }, + }, }); }); return this; }; - $(function() { + $(function () { // Initialize all autocomplete widgets except the one in the template // form used when a new formset is added. - $('.admin-autocomplete').not('[name*=__prefix__]').djangoAdminSelect2(); + $(".admin-autocomplete").not("[name*=__prefix__]").djangoAdminSelect2(); }); - document.addEventListener('formset:added', (event) => { - $(event.target).find('.admin-autocomplete').djangoAdminSelect2(); + document.addEventListener("formset:added", (event) => { + $(event.target).find(".admin-autocomplete").djangoAdminSelect2(); }); } diff --git a/django/contrib/admin/static/admin/js/calendar.js b/django/contrib/admin/static/admin/js/calendar.js index b13242078a..f10a584fa9 100644 --- a/django/contrib/admin/static/admin/js/calendar.js +++ b/django/contrib/admin/static/admin/js/calendar.js @@ -3,91 +3,102 @@ calendar.js - Calendar functions by Adrian Holovaty depends on core.js for utility functions like removeChildren or quickElement */ -'use strict'; +"use strict"; { // CalendarNamespace -- Provides a collection of HTML calendar-related helper functions const CalendarNamespace = { monthsOfYear: [ - gettext('January'), - gettext('February'), - gettext('March'), - gettext('April'), - gettext('May'), - gettext('June'), - gettext('July'), - gettext('August'), - gettext('September'), - gettext('October'), - gettext('November'), - gettext('December') + gettext("January"), + gettext("February"), + gettext("March"), + gettext("April"), + gettext("May"), + gettext("June"), + gettext("July"), + gettext("August"), + gettext("September"), + gettext("October"), + gettext("November"), + gettext("December"), ], monthsOfYearAbbrev: [ - pgettext('abbrev. month January', 'Jan'), - pgettext('abbrev. month February', 'Feb'), - pgettext('abbrev. month March', 'Mar'), - pgettext('abbrev. month April', 'Apr'), - pgettext('abbrev. month May', 'May'), - pgettext('abbrev. month June', 'Jun'), - pgettext('abbrev. month July', 'Jul'), - pgettext('abbrev. month August', 'Aug'), - pgettext('abbrev. month September', 'Sep'), - pgettext('abbrev. month October', 'Oct'), - pgettext('abbrev. month November', 'Nov'), - pgettext('abbrev. month December', 'Dec') + pgettext("abbrev. month January", "Jan"), + pgettext("abbrev. month February", "Feb"), + pgettext("abbrev. month March", "Mar"), + pgettext("abbrev. month April", "Apr"), + pgettext("abbrev. month May", "May"), + pgettext("abbrev. month June", "Jun"), + pgettext("abbrev. month July", "Jul"), + pgettext("abbrev. month August", "Aug"), + pgettext("abbrev. month September", "Sep"), + pgettext("abbrev. month October", "Oct"), + pgettext("abbrev. month November", "Nov"), + pgettext("abbrev. month December", "Dec"), ], daysOfWeek: [ - gettext('Sunday'), - gettext('Monday'), - gettext('Tuesday'), - gettext('Wednesday'), - gettext('Thursday'), - gettext('Friday'), - gettext('Saturday') + gettext("Sunday"), + gettext("Monday"), + gettext("Tuesday"), + gettext("Wednesday"), + gettext("Thursday"), + gettext("Friday"), + gettext("Saturday"), ], daysOfWeekAbbrev: [ - pgettext('abbrev. day Sunday', 'Sun'), - pgettext('abbrev. day Monday', 'Mon'), - pgettext('abbrev. day Tuesday', 'Tue'), - pgettext('abbrev. day Wednesday', 'Wed'), - pgettext('abbrev. day Thursday', 'Thur'), - pgettext('abbrev. day Friday', 'Fri'), - pgettext('abbrev. day Saturday', 'Sat') + pgettext("abbrev. day Sunday", "Sun"), + pgettext("abbrev. day Monday", "Mon"), + pgettext("abbrev. day Tuesday", "Tue"), + pgettext("abbrev. day Wednesday", "Wed"), + pgettext("abbrev. day Thursday", "Thur"), + pgettext("abbrev. day Friday", "Fri"), + pgettext("abbrev. day Saturday", "Sat"), ], daysOfWeekInitial: [ - pgettext('one letter Sunday', 'S'), - pgettext('one letter Monday', 'M'), - pgettext('one letter Tuesday', 'T'), - pgettext('one letter Wednesday', 'W'), - pgettext('one letter Thursday', 'T'), - pgettext('one letter Friday', 'F'), - pgettext('one letter Saturday', 'S') + pgettext("one letter Sunday", "S"), + pgettext("one letter Monday", "M"), + pgettext("one letter Tuesday", "T"), + pgettext("one letter Wednesday", "W"), + pgettext("one letter Thursday", "T"), + pgettext("one letter Friday", "F"), + pgettext("one letter Saturday", "S"), ], - firstDayOfWeek: parseInt(get_format('FIRST_DAY_OF_WEEK')), - isLeapYear: function(year) { - return (((year % 4) === 0) && ((year % 100) !== 0 ) || ((year % 400) === 0)); + firstDayOfWeek: parseInt(get_format("FIRST_DAY_OF_WEEK")), + isLeapYear: function (year) { + return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; }, - getDaysInMonth: function(month, year) { + getDaysInMonth: function (month, year) { let days; - if (month === 1 || month === 3 || month === 5 || month === 7 || month === 8 || month === 10 || month === 12) { + if ( + month === 1 || + month === 3 || + month === 5 || + month === 7 || + month === 8 || + month === 10 || + month === 12 + ) { days = 31; - } - else if (month === 4 || month === 6 || month === 9 || month === 11) { + } else if ( + month === 4 || + month === 6 || + month === 9 || + month === 11 + ) { days = 30; - } - else if (month === 2 && CalendarNamespace.isLeapYear(year)) { + } else if (month === 2 && CalendarNamespace.isLeapYear(year)) { days = 29; - } - else { + } else { days = 28; } return days; }, - draw: function(month, year, div_id, callback, selected) { // month = 1-12, year = 1-9999 + draw: function (month, year, div_id, callback, selected) { + // month = 1-12, year = 1-9999 const today = new Date(); const todayDay = today.getDate(); const todayMonth = today.getMonth() + 1; const todayYear = today.getFullYear(); - let todayClass = ''; + let todayClass = ""; // Use UTC functions here because the date field does not contain time // and using the UTC function variants prevent the local time offset @@ -101,33 +112,49 @@ depends on core.js for utility functions like removeChildren or quickElement // The day variable above will be 1 instead of 2 in, say, US Pacific time // zone. let isSelectedMonth = false; - if (typeof selected !== 'undefined') { - isSelectedMonth = (selected.getUTCFullYear() === year && (selected.getUTCMonth() + 1) === month); + if (typeof selected !== "undefined") { + isSelectedMonth = + selected.getUTCFullYear() === year && + selected.getUTCMonth() + 1 === month; } month = parseInt(month); year = parseInt(year); const calDiv = document.getElementById(div_id); removeChildren(calDiv); - const calTable = document.createElement('table'); - quickElement('caption', calTable, CalendarNamespace.monthsOfYear[month - 1] + ' ' + year); - const tableBody = quickElement('tbody', calTable); + const calTable = document.createElement("table"); + quickElement( + "caption", + calTable, + CalendarNamespace.monthsOfYear[month - 1] + " " + year, + ); + const tableBody = quickElement("tbody", calTable); // Draw days-of-week header - let tableRow = quickElement('tr', tableBody); + let tableRow = quickElement("tr", tableBody); for (let i = 0; i < 7; i++) { - quickElement('th', tableRow, CalendarNamespace.daysOfWeekInitial[(i + CalendarNamespace.firstDayOfWeek) % 7]); + quickElement( + "th", + tableRow, + CalendarNamespace.daysOfWeekInitial[ + (i + CalendarNamespace.firstDayOfWeek) % 7 + ], + ); } - const startingPos = new Date(year, month - 1, 1 - CalendarNamespace.firstDayOfWeek).getDay(); + const startingPos = new Date( + year, + month - 1, + 1 - CalendarNamespace.firstDayOfWeek, + ).getDay(); const days = CalendarNamespace.getDaysInMonth(month, year); let nonDayCell; // Draw blanks before first of month - tableRow = quickElement('tr', tableBody); + tableRow = quickElement("tr", tableBody); for (let i = 0; i < startingPos; i++) { - nonDayCell = quickElement('td', tableRow, ' '); + nonDayCell = quickElement("td", tableRow, " "); nonDayCell.className = "nonday"; } @@ -143,36 +170,54 @@ depends on core.js for utility functions like removeChildren or quickElement let currentDay = 1; for (let i = startingPos; currentDay <= days; i++) { if (i % 7 === 0 && currentDay !== 1) { - tableRow = quickElement('tr', tableBody); + tableRow = quickElement("tr", tableBody); } - if ((currentDay === todayDay) && (month === todayMonth) && (year === todayYear)) { - todayClass = 'today'; + if ( + currentDay === todayDay && + month === todayMonth && + year === todayYear + ) { + todayClass = "today"; } else { - todayClass = ''; + todayClass = ""; } // use UTC function; see above for explanation. if (isSelectedMonth && currentDay === selected.getUTCDate()) { - if (todayClass !== '') { + if (todayClass !== "") { todayClass += " "; } todayClass += "selected"; } - const cell = quickElement('td', tableRow, '', 'class', todayClass); - const link = quickElement('a', cell, currentDay, 'role', 'button', 'href', '#'); - link.addEventListener('click', calendarMonth(year, month)); + const cell = quickElement( + "td", + tableRow, + "", + "class", + todayClass, + ); + const link = quickElement( + "a", + cell, + currentDay, + "role", + "button", + "href", + "#", + ); + link.addEventListener("click", calendarMonth(year, month)); currentDay++; } // Draw blanks after end of month (optional, but makes for valid code) while (tableRow.childNodes.length < 7) { - nonDayCell = quickElement('td', tableRow, ' '); + nonDayCell = quickElement("td", tableRow, " "); nonDayCell.className = "nonday"; } calDiv.appendChild(calTable); - } + }, }; // Calendar -- A calendar instance @@ -187,52 +232,56 @@ depends on core.js for utility functions like removeChildren or quickElement this.today = new Date(); this.currentMonth = this.today.getMonth() + 1; this.currentYear = this.today.getFullYear(); - if (typeof selected !== 'undefined') { + if (typeof selected !== "undefined") { this.selected = selected; } } Calendar.prototype = { - drawCurrent: function() { - CalendarNamespace.draw(this.currentMonth, this.currentYear, this.div_id, this.callback, this.selected); + drawCurrent: function () { + CalendarNamespace.draw( + this.currentMonth, + this.currentYear, + this.div_id, + this.callback, + this.selected, + ); }, - drawDate: function(month, year, selected) { + drawDate: function (month, year, selected) { this.currentMonth = month; this.currentYear = year; - if(selected) { + if (selected) { this.selected = selected; } this.drawCurrent(); }, - drawPreviousMonth: function() { + drawPreviousMonth: function () { if (this.currentMonth === 1) { this.currentMonth = 12; this.currentYear--; - } - else { + } else { this.currentMonth--; } this.drawCurrent(); }, - drawNextMonth: function() { + drawNextMonth: function () { if (this.currentMonth === 12) { this.currentMonth = 1; this.currentYear++; - } - else { + } else { this.currentMonth++; } this.drawCurrent(); }, - drawPreviousYear: function() { + drawPreviousYear: function () { this.currentYear--; this.drawCurrent(); }, - drawNextYear: function() { + drawNextYear: function () { this.currentYear++; this.drawCurrent(); - } + }, }; window.Calendar = Calendar; window.CalendarNamespace = CalendarNamespace; diff --git a/django/contrib/admin/static/admin/js/cancel.js b/django/contrib/admin/static/admin/js/cancel.js index 3069c6f27b..b4bc29c8db 100644 --- a/django/contrib/admin/static/admin/js/cancel.js +++ b/django/contrib/admin/static/admin/js/cancel.js @@ -1,29 +1,29 @@ -'use strict'; +"use strict"; { // Call function fn when the DOM is loaded and ready. If it is already // loaded, call the function now. // http://youmightnotneedjquery.com/#ready function ready(fn) { - if (document.readyState !== 'loading') { + if (document.readyState !== "loading") { fn(); } else { - document.addEventListener('DOMContentLoaded', fn); + document.addEventListener("DOMContentLoaded", fn); } } - ready(function() { + ready(function () { function handleClick(event) { event.preventDefault(); const params = new URLSearchParams(window.location.search); - if (params.has('_popup')) { + if (params.has("_popup")) { window.close(); // Close the popup. } else { window.history.back(); // Otherwise, go back. } } - document.querySelectorAll('.cancel-link').forEach(function(el) { - el.addEventListener('click', handleClick); + document.querySelectorAll(".cancel-link").forEach(function (el) { + el.addEventListener("click", handleClick); }); }); } diff --git a/django/contrib/admin/static/admin/js/change_form.js b/django/contrib/admin/static/admin/js/change_form.js index 96a4c62ef4..f692d7ffe1 100644 --- a/django/contrib/admin/static/admin/js/change_form.js +++ b/django/contrib/admin/static/admin/js/change_form.js @@ -1,13 +1,18 @@ -'use strict'; +"use strict"; { - const inputTags = ['BUTTON', 'INPUT', 'SELECT', 'TEXTAREA']; - const modelName = document.getElementById('django-admin-form-add-constants').dataset.modelName; + const inputTags = ["BUTTON", "INPUT", "SELECT", "TEXTAREA"]; + const modelName = document.getElementById("django-admin-form-add-constants") + .dataset.modelName; if (modelName) { - const form = document.getElementById(modelName + '_form'); + const form = document.getElementById(modelName + "_form"); for (const element of form.elements) { // HTMLElement.offsetParent returns null when the element is not // rendered. - if (inputTags.includes(element.tagName) && !element.disabled && element.offsetParent) { + if ( + inputTags.includes(element.tagName) && + !element.disabled && + element.offsetParent + ) { element.focus(); break; } diff --git a/django/contrib/admin/static/admin/js/core.js b/django/contrib/admin/static/admin/js/core.js index 10504d4a84..d36dad6f49 100644 --- a/django/contrib/admin/static/admin/js/core.js +++ b/django/contrib/admin/static/admin/js/core.js @@ -1,5 +1,5 @@ // Core JavaScript helper functions -'use strict'; +"use strict"; // quickElement(tagType, parentReference [, textInChildNode, attribute, attributeValue ...]); function quickElement() { @@ -57,59 +57,67 @@ function findPosY(obj) { // Date object extensions // ---------------------------------------------------------------------------- { - Date.prototype.getTwelveHours = function() { + Date.prototype.getTwelveHours = function () { return this.getHours() % 12 || 12; }; - Date.prototype.getTwoDigitMonth = function() { - return (this.getMonth() < 9) ? '0' + (this.getMonth() + 1) : (this.getMonth() + 1); + Date.prototype.getTwoDigitMonth = function () { + return this.getMonth() < 9 + ? "0" + (this.getMonth() + 1) + : this.getMonth() + 1; }; - Date.prototype.getTwoDigitDate = function() { - return (this.getDate() < 10) ? '0' + this.getDate() : this.getDate(); + Date.prototype.getTwoDigitDate = function () { + return this.getDate() < 10 ? "0" + this.getDate() : this.getDate(); }; - Date.prototype.getTwoDigitTwelveHour = function() { - return (this.getTwelveHours() < 10) ? '0' + this.getTwelveHours() : this.getTwelveHours(); + Date.prototype.getTwoDigitTwelveHour = function () { + return this.getTwelveHours() < 10 + ? "0" + this.getTwelveHours() + : this.getTwelveHours(); }; - Date.prototype.getTwoDigitHour = function() { - return (this.getHours() < 10) ? '0' + this.getHours() : this.getHours(); + Date.prototype.getTwoDigitHour = function () { + return this.getHours() < 10 ? "0" + this.getHours() : this.getHours(); }; - Date.prototype.getTwoDigitMinute = function() { - return (this.getMinutes() < 10) ? '0' + this.getMinutes() : this.getMinutes(); + Date.prototype.getTwoDigitMinute = function () { + return this.getMinutes() < 10 + ? "0" + this.getMinutes() + : this.getMinutes(); }; - Date.prototype.getTwoDigitSecond = function() { - return (this.getSeconds() < 10) ? '0' + this.getSeconds() : this.getSeconds(); + Date.prototype.getTwoDigitSecond = function () { + return this.getSeconds() < 10 + ? "0" + this.getSeconds() + : this.getSeconds(); }; - Date.prototype.getAbbrevDayName = function() { + Date.prototype.getAbbrevDayName = function () { return typeof window.CalendarNamespace === "undefined" - ? '0' + this.getDay() + ? "0" + this.getDay() : window.CalendarNamespace.daysOfWeekAbbrev[this.getDay()]; }; - Date.prototype.getFullDayName = function() { + Date.prototype.getFullDayName = function () { return typeof window.CalendarNamespace === "undefined" - ? '0' + this.getDay() + ? "0" + this.getDay() : window.CalendarNamespace.daysOfWeek[this.getDay()]; }; - Date.prototype.getAbbrevMonthName = function() { + Date.prototype.getAbbrevMonthName = function () { return typeof window.CalendarNamespace === "undefined" ? this.getTwoDigitMonth() : window.CalendarNamespace.monthsOfYearAbbrev[this.getMonth()]; }; - Date.prototype.getFullMonthName = function() { + Date.prototype.getFullMonthName = function () { return typeof window.CalendarNamespace === "undefined" ? this.getTwoDigitMonth() : window.CalendarNamespace.monthsOfYear[this.getMonth()]; }; - Date.prototype.strftime = function(format) { + Date.prototype.strftime = function (format) { const fields = { a: this.getAbbrevDayName(), A: this.getFullDayName(), @@ -121,22 +129,22 @@ function findPosY(obj) { I: this.getTwoDigitTwelveHour(), m: this.getTwoDigitMonth(), M: this.getTwoDigitMinute(), - p: (this.getHours() >= 12) ? 'PM' : 'AM', + p: this.getHours() >= 12 ? "PM" : "AM", S: this.getTwoDigitSecond(), - w: '0' + this.getDay(), + w: "0" + this.getDay(), x: this.toLocaleDateString(), X: this.toLocaleTimeString(), - y: ('' + this.getFullYear()).substr(2, 4), - Y: '' + this.getFullYear(), - '%': '%' + y: ("" + this.getFullYear()).substr(2, 4), + Y: "" + this.getFullYear(), + "%": "%", }; - let result = '', i = 0; + let result = "", + i = 0; while (i < format.length) { - if (format.charAt(i) === '%') { + if (format.charAt(i) === "%") { result += fields[format.charAt(i + 1)]; ++i; - } - else { + } else { result += format.charAt(i); } ++i; @@ -147,32 +155,34 @@ function findPosY(obj) { // ---------------------------------------------------------------------------- // String object extensions // ---------------------------------------------------------------------------- - String.prototype.strptime = function(format) { + String.prototype.strptime = function (format) { const split_format = format.split(/[.\-/]/); const date = this.split(/[.\-/]/); let i = 0; let day, month, year; while (i < split_format.length) { switch (split_format[i]) { - case "%d": - day = date[i]; - break; - case "%m": - month = date[i] - 1; - break; - case "%Y": - year = date[i]; - break; - case "%y": - // A %y value in the range of [00, 68] is in the current - // century, while [69, 99] is in the previous century, - // according to the Open Group Specification. - if (parseInt(date[i], 10) >= 69) { + case "%d": + day = date[i]; + break; + case "%m": + month = date[i] - 1; + break; + case "%Y": year = date[i]; - } else { - year = (new Date(Date.UTC(date[i], 0))).getUTCFullYear() + 100; - } - break; + break; + case "%y": + // A %y value in the range of [00, 68] is in the current + // century, while [69, 99] is in the previous century, + // according to the Open Group Specification. + if (parseInt(date[i], 10) >= 69) { + year = date[i]; + } else { + year = + new Date(Date.UTC(date[i], 0)).getUTCFullYear() + + 100; + } + break; } ++i; } diff --git a/django/contrib/admin/static/admin/js/filters.js b/django/contrib/admin/static/admin/js/filters.js index f5536ebc2d..c765264b3f 100644 --- a/django/contrib/admin/static/admin/js/filters.js +++ b/django/contrib/admin/static/admin/js/filters.js @@ -1,30 +1,39 @@ /** * Persist changelist filters state (collapsed/expanded). */ -'use strict'; +"use strict"; { // Init filters. - let filters = JSON.parse(sessionStorage.getItem('django.admin.filtersState')); + let filters = JSON.parse( + sessionStorage.getItem("django.admin.filtersState"), + ); if (!filters) { filters = {}; } Object.entries(filters).forEach(([key, value]) => { - const detailElement = document.querySelector(`[data-filter-title='${CSS.escape(key)}']`); + const detailElement = document.querySelector( + `[data-filter-title='${CSS.escape(key)}']`, + ); // Check if the filter is present, it could be from other view. if (detailElement) { - value ? detailElement.setAttribute('open', '') : detailElement.removeAttribute('open'); + value + ? detailElement.setAttribute("open", "") + : detailElement.removeAttribute("open"); } }); // Save filter state when clicks. - const details = document.querySelectorAll('details'); - details.forEach(detail => { - detail.addEventListener('toggle', event => { + const details = document.querySelectorAll("details"); + details.forEach((detail) => { + detail.addEventListener("toggle", (event) => { filters[`${event.target.dataset.filterTitle}`] = detail.open; - sessionStorage.setItem('django.admin.filtersState', JSON.stringify(filters)); + sessionStorage.setItem( + "django.admin.filtersState", + JSON.stringify(filters), + ); }); }); } diff --git a/django/contrib/admin/static/admin/js/inlines.js b/django/contrib/admin/static/admin/js/inlines.js index cd3726cf30..9944252295 100644 --- a/django/contrib/admin/static/admin/js/inlines.js +++ b/django/contrib/admin/static/admin/js/inlines.js @@ -15,18 +15,21 @@ * Licensed under the New BSD License * See: https://opensource.org/licenses/bsd-license.php */ -'use strict'; +"use strict"; { const $ = django.jQuery; - $.fn.formset = function(opts) { + $.fn.formset = function (opts) { const options = $.extend({}, $.fn.formset.defaults, opts); const $this = $(this); const $parent = $this.parent(); - const updateElementIndex = function(el, prefix, ndx) { + const updateElementIndex = function (el, prefix, ndx) { const id_regex = new RegExp("(" + prefix + "-(\\d+|__prefix__))"); const replacement = prefix + "-" + ndx; if ($(el).prop("for")) { - $(el).prop("for", $(el).prop("for").replace(id_regex, replacement)); + $(el).prop( + "for", + $(el).prop("for").replace(id_regex, replacement), + ); } if (el.id) { el.id = el.id.replace(id_regex, replacement); @@ -35,33 +38,58 @@ el.name = el.name.replace(id_regex, replacement); } }; - const totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS").prop("autocomplete", "off"); + const totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS").prop( + "autocomplete", + "off", + ); let nextIndex = parseInt(totalForms.val(), 10); - const maxForms = $("#id_" + options.prefix + "-MAX_NUM_FORMS").prop("autocomplete", "off"); - const minForms = $("#id_" + options.prefix + "-MIN_NUM_FORMS").prop("autocomplete", "off"); + const maxForms = $("#id_" + options.prefix + "-MAX_NUM_FORMS").prop( + "autocomplete", + "off", + ); + const minForms = $("#id_" + options.prefix + "-MIN_NUM_FORMS").prop( + "autocomplete", + "off", + ); let addButton; /** * The "Add another MyModel" button below the inline forms. */ - const addInlineAddButton = function() { + const addInlineAddButton = function () { if (addButton === null) { if ($this.prop("tagName") === "TR") { // If forms are laid out as table rows, insert the // "add" button in a new table row: const numCols = $this.eq(-1).children().length; - $parent.append('<tr class="' + options.addCssClass + '"><td colspan="' + numCols + '"><a role="button" class="addlink" href="#">' + options.addText + "</a></tr>"); + $parent.append( + '<tr class="' + + options.addCssClass + + '"><td colspan="' + + numCols + + '"><a role="button" class="addlink" href="#">' + + options.addText + + "</a></tr>", + ); addButton = $parent.find("tr:last a"); } else { // Otherwise, insert it immediately after the last form: - $this.filter(":last").after('<div class="' + options.addCssClass + '"><a role="button" class="addlink" href="#">' + options.addText + "</a></div>"); + $this + .filter(":last") + .after( + '<div class="' + + options.addCssClass + + '"><a role="button" class="addlink" href="#">' + + options.addText + + "</a></div>", + ); addButton = $this.filter(":last").next().find("a"); } } - addButton.on('click', addInlineClickHandler); + addButton.on("click", addInlineClickHandler); }; - const addInlineClickHandler = function(e) { + const addInlineClickHandler = function (e) { e.preventDefault(); const template = $("#" + options.prefix + "-empty"); const row = template.clone(true); @@ -69,7 +97,7 @@ .addClass(options.formCssClass) .attr("id", options.prefix + "-" + nextIndex); addInlineDeleteButton(row); - row.find("*").each(function() { + row.find("*").each(function () { updateElementIndex(this, options.prefix, totalForms.val()); }); // Insert the new form when it has been fully edited. @@ -78,55 +106,81 @@ $(totalForms).val(parseInt(totalForms.val(), 10) + 1); nextIndex += 1; // Hide the add button if there's a limit and it's been reached. - if ((maxForms.val() !== '') && (maxForms.val() - totalForms.val()) <= 0) { + if ( + maxForms.val() !== "" && + maxForms.val() - totalForms.val() <= 0 + ) { addButton.parent().hide(); } // Show the remove buttons if there are more than min_num. - toggleDeleteButtonVisibility(row.closest('.inline-group')); + toggleDeleteButtonVisibility(row.closest(".inline-group")); // Pass the new form to the post-add callback, if provided. if (options.added) { options.added(row); } - row.get(0).dispatchEvent(new CustomEvent("formset:added", { - bubbles: true, - detail: { - formsetName: options.prefix - } - })); + row.get(0).dispatchEvent( + new CustomEvent("formset:added", { + bubbles: true, + detail: { + formsetName: options.prefix, + }, + }), + ); }; /** * The "X" button that is part of every unsaved inline. * (When saved, it is replaced with a "Delete" checkbox.) */ - const addInlineDeleteButton = function(row) { + const addInlineDeleteButton = function (row) { if (row.is("tr")) { // If the forms are laid out in table rows, insert // the remove button into the last table cell: - row.children(":last").append('<div><a role="button" class="' + options.deleteCssClass + '" href="#">' + options.deleteText + "</a></div>"); + row.children(":last").append( + '<div><a role="button" class="' + + options.deleteCssClass + + '" href="#">' + + options.deleteText + + "</a></div>", + ); } else if (row.is("ul") || row.is("ol")) { // If they're laid out as an ordered/unordered list, // insert an <li> after the last list item: - row.append('<li><a role="button" class="' + options.deleteCssClass + '" href="#">' + options.deleteText + "</a></li>"); + row.append( + '<li><a role="button" class="' + + options.deleteCssClass + + '" href="#">' + + options.deleteText + + "</a></li>", + ); } else { // Otherwise, just insert the remove button as the // last child element of the form's container: - row.children(":first").append('<span><a role="button" class="' + options.deleteCssClass + '" href="#">' + options.deleteText + "</a></span>"); + row.children(":first").append( + '<span><a role="button" class="' + + options.deleteCssClass + + '" href="#">' + + options.deleteText + + "</a></span>", + ); } // Add delete handler for each row. - row.find("a." + options.deleteCssClass).on('click', inlineDeleteHandler.bind(this)); + row.find("a." + options.deleteCssClass).on( + "click", + inlineDeleteHandler.bind(this), + ); }; - const inlineDeleteHandler = function(e1) { + const inlineDeleteHandler = function (e1) { e1.preventDefault(); const deleteButton = $(e1.target); - const row = deleteButton.closest('.' + options.formCssClass); - const inlineGroup = row.closest('.inline-group'); + const row = deleteButton.closest("." + options.formCssClass); + const inlineGroup = row.closest(".inline-group"); // Remove the parent form containing this button, // and also remove the relevant row with non-field errors: const prevRow = row.prev(); - if (prevRow.length && prevRow.hasClass('row-form-errors')) { + if (prevRow.length && prevRow.hasClass("row-form-errors")) { prevRow.remove(); } row.remove(); @@ -135,16 +189,18 @@ if (options.removed) { options.removed(row); } - document.dispatchEvent(new CustomEvent("formset:removed", { - detail: { - formsetName: options.prefix - } - })); + document.dispatchEvent( + new CustomEvent("formset:removed", { + detail: { + formsetName: options.prefix, + }, + }), + ); // Update the TOTAL_FORMS form count. const forms = $("." + options.formCssClass); $("#id_" + options.prefix + "-TOTAL_FORMS").val(forms.length); // Show add button again once below maximum number. - if ((maxForms.val() === '') || (maxForms.val() - forms.length) > 0) { + if (maxForms.val() === "" || maxForms.val() - forms.length > 0) { addButton.parent().show(); } // Hide the remove buttons if at min_num. @@ -152,7 +208,7 @@ // Also, update names and ids for all remaining form controls so // they remain in sequence: let i, formCount; - const updateElementCallback = function() { + const updateElementCallback = function () { updateElementIndex(this, options.prefix, i); }; for (i = 0, formCount = forms.length; i < formCount; i++) { @@ -161,22 +217,35 @@ } }; - const toggleDeleteButtonVisibility = function(inlineGroup) { - if ((minForms.val() !== '') && (minForms.val() - totalForms.val()) >= 0) { - inlineGroup.find('.inline-deletelink').hide(); + const toggleDeleteButtonVisibility = function (inlineGroup) { + if ( + minForms.val() !== "" && + minForms.val() - totalForms.val() >= 0 + ) { + inlineGroup.find(".inline-deletelink").hide(); } else { - inlineGroup.find('.inline-deletelink').show(); + inlineGroup.find(".inline-deletelink").show(); } }; - $this.each(function(i) { - $(this).not("." + options.emptyCssClass).addClass(options.formCssClass); + $this.each(function (i) { + $(this) + .not("." + options.emptyCssClass) + .addClass(options.formCssClass); }); // Create the delete buttons for all unsaved inlines: - $this.filter('.' + options.formCssClass + ':not(.has_original):not(.' + options.emptyCssClass + ')').each(function() { - addInlineDeleteButton($(this)); - }); + $this + .filter( + "." + + options.formCssClass + + ":not(.has_original):not(." + + options.emptyCssClass + + ")", + ) + .each(function () { + addInlineDeleteButton($(this)); + }); toggleDeleteButtonVisibility($this); // Create the add button, initially hidden. @@ -185,7 +254,8 @@ // Show the add button if allowed to add more items. // Note that max_num = None translates to a blank string. - const showAddButton = maxForms.val() === '' || (maxForms.val() - totalForms.val()) > 0; + const showAddButton = + maxForms.val() === "" || maxForms.val() - totalForms.val() > 0; if ($this.length && showAddButton) { addButton.parent().show(); } else { @@ -206,15 +276,14 @@ formCssClass: "dynamic-form", // CSS class applied to each form in a formset added: null, // Function called each time a new form is added removed: null, // Function called each time a form is deleted - addButton: null // Existing add button to use + addButton: null, // Existing add button to use }; - // Tabular inlines --------------------------------------------------------- - $.fn.tabularFormset = function(selector, options) { + $.fn.tabularFormset = function (selector, options) { const $rows = $(this); - const reinitDateTimeShortCuts = function() { + const reinitDateTimeShortCuts = function () { // Reinitialize the calendar and clock widgets by force if (typeof DateTimeShortcuts !== "undefined") { $(".datetimeshortcuts").remove(); @@ -222,30 +291,36 @@ } }; - const updateSelectFilter = function() { + const updateSelectFilter = function () { // If any SelectFilter widgets are a part of the new form, // instantiate a new SelectFilter instance for it. - if (typeof SelectFilter !== 'undefined') { - $('.selectfilter').each(function(index, value) { + if (typeof SelectFilter !== "undefined") { + $(".selectfilter").each(function (index, value) { SelectFilter.init(value.id, this.dataset.fieldName, false); }); - $('.selectfilterstacked').each(function(index, value) { + $(".selectfilterstacked").each(function (index, value) { SelectFilter.init(value.id, this.dataset.fieldName, true); }); } }; - const initPrepopulatedFields = function(row) { - row.find('.prepopulated_field').each(function() { + const initPrepopulatedFields = function (row) { + row.find(".prepopulated_field").each(function () { const field = $(this), - input = field.find('input, select, textarea'), - dependency_list = input.data('dependency_list') || [], + input = field.find("input, select, textarea"), + dependency_list = input.data("dependency_list") || [], dependencies = []; - $.each(dependency_list, function(i, field_name) { - dependencies.push('#' + row.find('.field-' + field_name).find('input, select, textarea').attr('id')); + $.each(dependency_list, function (i, field_name) { + dependencies.push( + "#" + + row + .find(".field-" + field_name) + .find("input, select, textarea") + .attr("id"), + ); }); if (dependencies.length) { - input.prepopulate(dependencies, input.attr('maxlength')); + input.prepopulate(dependencies, input.attr("maxlength")); } }); }; @@ -257,28 +332,34 @@ deleteCssClass: "inline-deletelink", deleteText: options.deleteText, emptyCssClass: "empty-form", - added: function(row) { + added: function (row) { initPrepopulatedFields(row); reinitDateTimeShortCuts(); updateSelectFilter(); }, - addButton: options.addButton + addButton: options.addButton, }); return $rows; }; // Stacked inlines --------------------------------------------------------- - $.fn.stackedFormset = function(selector, options) { + $.fn.stackedFormset = function (selector, options) { const $rows = $(this); - const updateInlineLabel = function(row) { - $(selector).find(".inline_label").each(function(i) { - const count = i + 1; - $(this).html($(this).html().replace(/(#\d+)/g, "#" + count)); - }); + const updateInlineLabel = function (row) { + $(selector) + .find(".inline_label") + .each(function (i) { + const count = i + 1; + $(this).html( + $(this) + .html() + .replace(/(#\d+)/g, "#" + count), + ); + }); }; - const reinitDateTimeShortCuts = function() { + const reinitDateTimeShortCuts = function () { // Reinitialize the calendar and clock widgets by force, yuck. if (typeof DateTimeShortcuts !== "undefined") { $(".datetimeshortcuts").remove(); @@ -286,35 +367,44 @@ } }; - const updateSelectFilter = function() { + const updateSelectFilter = function () { // If any SelectFilter widgets were added, instantiate a new instance. if (typeof SelectFilter !== "undefined") { - $(".selectfilter").each(function(index, value) { + $(".selectfilter").each(function (index, value) { SelectFilter.init(value.id, this.dataset.fieldName, false); }); - $(".selectfilterstacked").each(function(index, value) { + $(".selectfilterstacked").each(function (index, value) { SelectFilter.init(value.id, this.dataset.fieldName, true); }); } }; - const initPrepopulatedFields = function(row) { - row.find('.prepopulated_field').each(function() { + const initPrepopulatedFields = function (row) { + row.find(".prepopulated_field").each(function () { const field = $(this), - input = field.find('input, select, textarea'), - dependency_list = input.data('dependency_list') || [], + input = field.find("input, select, textarea"), + dependency_list = input.data("dependency_list") || [], dependencies = []; - $.each(dependency_list, function(i, field_name) { + $.each(dependency_list, function (i, field_name) { // Dependency in a fieldset. - let field_element = row.find('.form-row .field-' + field_name); + let field_element = row.find( + ".form-row .field-" + field_name, + ); // Dependency without a fieldset. if (!field_element.length) { - field_element = row.find('.form-row.field-' + field_name); + field_element = row.find( + ".form-row.field-" + field_name, + ); } - dependencies.push('#' + field_element.find('input, select, textarea').attr('id')); + dependencies.push( + "#" + + field_element + .find("input, select, textarea") + .attr("id"), + ); }); if (dependencies.length) { - input.prepopulate(dependencies, input.attr('maxlength')); + input.prepopulate(dependencies, input.attr("maxlength")); } }); }; @@ -327,32 +417,34 @@ deleteText: options.deleteText, emptyCssClass: "empty-form", removed: updateInlineLabel, - added: function(row) { + added: function (row) { initPrepopulatedFields(row); reinitDateTimeShortCuts(); updateSelectFilter(); updateInlineLabel(row); }, - addButton: options.addButton + addButton: options.addButton, }); return $rows; }; - $(document).ready(function() { - $(".js-inline-admin-formset").each(function() { + $(document).ready(function () { + $(".js-inline-admin-formset").each(function () { const data = $(this).data(), inlineOptions = data.inlineFormset; let selector; - switch(data.inlineType) { - case "stacked": - selector = inlineOptions.name + "-group .inline-related"; - $(selector).stackedFormset(selector, inlineOptions.options); - break; - case "tabular": - selector = inlineOptions.name + "-group .tabular.inline-related tbody:first > tr.form-row"; - $(selector).tabularFormset(selector, inlineOptions.options); - break; + switch (data.inlineType) { + case "stacked": + selector = inlineOptions.name + "-group .inline-related"; + $(selector).stackedFormset(selector, inlineOptions.options); + break; + case "tabular": + selector = + inlineOptions.name + + "-group .tabular.inline-related tbody:first > tr.form-row"; + $(selector).tabularFormset(selector, inlineOptions.options); + break; } }); }); diff --git a/django/contrib/admin/static/admin/js/jquery.init.js b/django/contrib/admin/static/admin/js/jquery.init.js index f40b27f47d..e9f446f96e 100644 --- a/django/contrib/admin/static/admin/js/jquery.init.js +++ b/django/contrib/admin/static/admin/js/jquery.init.js @@ -1,8 +1,8 @@ /*global jQuery:false*/ -'use strict'; +"use strict"; /* Puts the included jQuery into our own namespace using noConflict and passing * it 'true'. This ensures that the included jQuery doesn't pollute the global * namespace (i.e. this preserves pre-existing values for both window.$ and * window.jQuery). */ -window.django = {jQuery: jQuery.noConflict(true)}; +window.django = { jQuery: jQuery.noConflict(true) }; diff --git a/django/contrib/admin/static/admin/js/nav_sidebar.js b/django/contrib/admin/static/admin/js/nav_sidebar.js index 7e735db15c..777299f8b0 100644 --- a/django/contrib/admin/static/admin/js/nav_sidebar.js +++ b/django/contrib/admin/static/admin/js/nav_sidebar.js @@ -1,36 +1,41 @@ -'use strict'; +"use strict"; { - const toggleNavSidebar = document.getElementById('toggle-nav-sidebar'); + const toggleNavSidebar = document.getElementById("toggle-nav-sidebar"); if (toggleNavSidebar !== null) { - const navSidebar = document.getElementById('nav-sidebar'); - const main = document.getElementById('main'); - let navSidebarIsOpen = localStorage.getItem('django.admin.navSidebarIsOpen'); + const navSidebar = document.getElementById("nav-sidebar"); + const main = document.getElementById("main"); + let navSidebarIsOpen = localStorage.getItem( + "django.admin.navSidebarIsOpen", + ); if (navSidebarIsOpen === null) { - navSidebarIsOpen = 'true'; + navSidebarIsOpen = "true"; } - main.classList.toggle('shifted', navSidebarIsOpen === 'true'); - navSidebar.setAttribute('aria-expanded', navSidebarIsOpen); + main.classList.toggle("shifted", navSidebarIsOpen === "true"); + navSidebar.setAttribute("aria-expanded", navSidebarIsOpen); - toggleNavSidebar.addEventListener('click', function() { - if (navSidebarIsOpen === 'true') { - navSidebarIsOpen = 'false'; + toggleNavSidebar.addEventListener("click", function () { + if (navSidebarIsOpen === "true") { + navSidebarIsOpen = "false"; } else { - navSidebarIsOpen = 'true'; + navSidebarIsOpen = "true"; } - localStorage.setItem('django.admin.navSidebarIsOpen', navSidebarIsOpen); - main.classList.toggle('shifted'); - navSidebar.setAttribute('aria-expanded', navSidebarIsOpen); + localStorage.setItem( + "django.admin.navSidebarIsOpen", + navSidebarIsOpen, + ); + main.classList.toggle("shifted"); + navSidebar.setAttribute("aria-expanded", navSidebarIsOpen); }); } function initSidebarQuickFilter() { const options = []; - const navSidebar = document.getElementById('nav-sidebar'); + const navSidebar = document.getElementById("nav-sidebar"); if (!navSidebar) { return; } - navSidebar.querySelectorAll('th[scope=row] a').forEach((container) => { - options.push({title: container.innerHTML, node: container}); + navSidebar.querySelectorAll("th[scope=row] a").forEach((container) => { + options.push({ title: container.innerHTML, node: container }); }); function checkValue(event) { @@ -38,16 +43,16 @@ if (filterValue) { filterValue = filterValue.toLowerCase(); } - if (event.key === 'Escape') { - filterValue = ''; - event.target.value = ''; // clear input + if (event.key === "Escape") { + filterValue = ""; + event.target.value = ""; // clear input } let matches = false; for (const o of options) { - let displayValue = ''; + let displayValue = ""; if (filterValue) { if (o.title.toLowerCase().indexOf(filterValue) === -1) { - displayValue = 'none'; + displayValue = "none"; } else { matches = true; } @@ -56,22 +61,27 @@ o.node.parentNode.parentNode.style.display = displayValue; } if (!filterValue || matches) { - event.target.classList.remove('no-results'); + event.target.classList.remove("no-results"); } else { - event.target.classList.add('no-results'); + event.target.classList.add("no-results"); } - sessionStorage.setItem('django.admin.navSidebarFilterValue', filterValue); + sessionStorage.setItem( + "django.admin.navSidebarFilterValue", + filterValue, + ); } - const nav = document.getElementById('nav-filter'); - nav.addEventListener('change', checkValue, false); - nav.addEventListener('input', checkValue, false); - nav.addEventListener('keyup', checkValue, false); + const nav = document.getElementById("nav-filter"); + nav.addEventListener("change", checkValue, false); + nav.addEventListener("input", checkValue, false); + nav.addEventListener("keyup", checkValue, false); - const storedValue = sessionStorage.getItem('django.admin.navSidebarFilterValue'); + const storedValue = sessionStorage.getItem( + "django.admin.navSidebarFilterValue", + ); if (storedValue) { nav.value = storedValue; - checkValue({target: nav, key: ''}); + checkValue({ target: nav, key: "" }); } } window.initSidebarQuickFilter = initSidebarQuickFilter; diff --git a/django/contrib/admin/static/admin/js/popup_response.js b/django/contrib/admin/static/admin/js/popup_response.js index bdd93a6eb5..1da24f0daf 100644 --- a/django/contrib/admin/static/admin/js/popup_response.js +++ b/django/contrib/admin/static/admin/js/popup_response.js @@ -1,15 +1,28 @@ -'use strict'; +"use strict"; { - const initData = JSON.parse(document.getElementById('django-admin-popup-response-constants').dataset.popupResponse); - switch(initData.action) { - case 'change': - opener.dismissChangeRelatedObjectPopup(window, initData.value, initData.obj, initData.new_value); - break; - case 'delete': - opener.dismissDeleteRelatedObjectPopup(window, initData.value); - break; - default: - opener.dismissAddRelatedObjectPopup(window, initData.value, initData.obj, initData.optgroup); - break; + const initData = JSON.parse( + document.getElementById("django-admin-popup-response-constants").dataset + .popupResponse, + ); + switch (initData.action) { + case "change": + opener.dismissChangeRelatedObjectPopup( + window, + initData.value, + initData.obj, + initData.new_value, + ); + break; + case "delete": + opener.dismissDeleteRelatedObjectPopup(window, initData.value); + break; + default: + opener.dismissAddRelatedObjectPopup( + window, + initData.value, + initData.obj, + initData.optgroup, + ); + break; } } diff --git a/django/contrib/admin/static/admin/js/prepopulate.js b/django/contrib/admin/static/admin/js/prepopulate.js index 89e95ab44d..5b1950d907 100644 --- a/django/contrib/admin/static/admin/js/prepopulate.js +++ b/django/contrib/admin/static/admin/js/prepopulate.js @@ -1,8 +1,8 @@ /*global URLify*/ -'use strict'; +"use strict"; { const $ = django.jQuery; - $.fn.prepopulate = function(dependencies, maxLength, allowUnicode) { + $.fn.prepopulate = function (dependencies, maxLength, allowUnicode) { /* Depends on urlify.js Populates a selected field with the values of the dependent fields, @@ -11,32 +11,34 @@ maxLength - maximum length of the URLify'd string allowUnicode - Unicode support of the URLify'd string */ - return this.each(function() { + return this.each(function () { const prepopulatedField = $(this); - const populate = function() { + const populate = function () { // Bail if the field's value has been changed by the user - if (prepopulatedField.data('_changed')) { + if (prepopulatedField.data("_changed")) { return; } const values = []; - $.each(dependencies, function(i, field) { + $.each(dependencies, function (i, field) { field = $(field); if (field.val().length > 0) { values.push(field.val()); } }); - prepopulatedField.val(URLify(values.join(' '), maxLength, allowUnicode)); + prepopulatedField.val( + URLify(values.join(" "), maxLength, allowUnicode), + ); }; - prepopulatedField.data('_changed', false); - prepopulatedField.on('change', function() { - prepopulatedField.data('_changed', true); + prepopulatedField.data("_changed", false); + prepopulatedField.on("change", function () { + prepopulatedField.data("_changed", true); }); if (!prepopulatedField.val()) { - $(dependencies.join(',')).on('keyup change focus', populate); + $(dependencies.join(",")).on("keyup change focus", populate); } }); }; diff --git a/django/contrib/admin/static/admin/js/prepopulate_init.js b/django/contrib/admin/static/admin/js/prepopulate_init.js index a58841f004..617065ac4d 100644 --- a/django/contrib/admin/static/admin/js/prepopulate_init.js +++ b/django/contrib/admin/static/admin/js/prepopulate_init.js @@ -1,15 +1,24 @@ -'use strict'; +"use strict"; { const $ = django.jQuery; - const fields = $('#django-admin-prepopulated-fields-constants').data('prepopulatedFields'); - $.each(fields, function(index, field) { + const fields = $("#django-admin-prepopulated-fields-constants").data( + "prepopulatedFields", + ); + $.each(fields, function (index, field) { $( - '.empty-form .form-row .field-' + field.name + - ', .empty-form.form-row .field-' + field.name + - ', .empty-form .form-row.field-' + field.name - ).addClass('prepopulated_field'); - $(field.id).data('dependency_list', field.dependency_list).prepopulate( - field.dependency_ids, field.maxLength, field.allowUnicode - ); + ".empty-form .form-row .field-" + + field.name + + ", .empty-form.form-row .field-" + + field.name + + ", .empty-form .form-row.field-" + + field.name, + ).addClass("prepopulated_field"); + $(field.id) + .data("dependency_list", field.dependency_list) + .prepopulate( + field.dependency_ids, + field.maxLength, + field.allowUnicode, + ); }); } diff --git a/django/contrib/admin/static/admin/js/theme.js b/django/contrib/admin/static/admin/js/theme.js index e79d375c55..0f5767ff6f 100644 --- a/django/contrib/admin/static/admin/js/theme.js +++ b/django/contrib/admin/static/admin/js/theme.js @@ -1,8 +1,10 @@ -'use strict'; +"use strict"; { function setTheme(mode) { if (mode !== "light" && mode !== "dark" && mode !== "auto") { - console.error(`Got invalid theme mode: ${mode}. Resetting to auto.`); + console.error( + `Got invalid theme mode: ${mode}. Resetting to auto.`, + ); mode = "auto"; } document.documentElement.dataset.theme = mode; @@ -11,7 +13,9 @@ function cycleTheme() { const currentTheme = localStorage.getItem("theme") || "auto"; - const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches; + const prefersDark = window.matchMedia( + "(prefers-color-scheme: dark)", + ).matches; if (prefersDark) { // Auto (dark) -> Light -> Dark @@ -40,7 +44,7 @@ currentTheme ? setTheme(currentTheme) : setTheme("auto"); } - window.addEventListener('load', function(_) { + window.addEventListener("load", function (_) { const buttons = document.getElementsByClassName("theme-toggle"); Array.from(buttons).forEach((btn) => { btn.addEventListener("click", cycleTheme); diff --git a/django/contrib/admin/static/admin/js/urlify.js b/django/contrib/admin/static/admin/js/urlify.js index 9fc0409496..3a23ec1647 100644 --- a/django/contrib/admin/static/admin/js/urlify.js +++ b/django/contrib/admin/static/admin/js/urlify.js @@ -1,109 +1,469 @@ /*global XRegExp*/ -'use strict'; +"use strict"; { const LATIN_MAP = { - 'À': 'A', 'Á': 'A', 'Â': 'A', 'Ã': 'A', 'Ä': 'A', 'Å': 'A', 'Æ': 'AE', - 'Ç': 'C', 'È': 'E', 'É': 'E', 'Ê': 'E', 'Ë': 'E', 'Ì': 'I', 'Í': 'I', - 'Î': 'I', 'Ï': 'I', 'Ð': 'D', 'Ñ': 'N', 'Ò': 'O', 'Ó': 'O', 'Ô': 'O', - 'Õ': 'O', 'Ö': 'O', 'Ő': 'O', 'Ø': 'O', 'Ù': 'U', 'Ú': 'U', 'Û': 'U', - 'Ü': 'U', 'Ű': 'U', 'Ý': 'Y', 'Þ': 'TH', 'Ÿ': 'Y', 'ß': 'ss', 'à': 'a', - 'á': 'a', 'â': 'a', 'ã': 'a', 'ä': 'a', 'å': 'a', 'æ': 'ae', 'ç': 'c', - 'è': 'e', 'é': 'e', 'ê': 'e', 'ë': 'e', 'ì': 'i', 'í': 'i', 'î': 'i', - 'ï': 'i', 'ð': 'd', 'ñ': 'n', 'ò': 'o', 'ó': 'o', 'ô': 'o', 'õ': 'o', - 'ö': 'o', 'ő': 'o', 'ø': 'o', 'ù': 'u', 'ú': 'u', 'û': 'u', 'ü': 'u', - 'ű': 'u', 'ý': 'y', 'þ': 'th', 'ÿ': 'y' + À: "A", + Á: "A", + Â: "A", + Ã: "A", + Ä: "A", + Å: "A", + Æ: "AE", + Ç: "C", + È: "E", + É: "E", + Ê: "E", + Ë: "E", + Ì: "I", + Í: "I", + Î: "I", + Ï: "I", + Ð: "D", + Ñ: "N", + Ò: "O", + Ó: "O", + Ô: "O", + Õ: "O", + Ö: "O", + Ő: "O", + Ø: "O", + Ù: "U", + Ú: "U", + Û: "U", + Ü: "U", + Ű: "U", + Ý: "Y", + Þ: "TH", + Ÿ: "Y", + ß: "ss", + à: "a", + á: "a", + â: "a", + ã: "a", + ä: "a", + å: "a", + æ: "ae", + ç: "c", + è: "e", + é: "e", + ê: "e", + ë: "e", + ì: "i", + í: "i", + î: "i", + ï: "i", + ð: "d", + ñ: "n", + ò: "o", + ó: "o", + ô: "o", + õ: "o", + ö: "o", + ő: "o", + ø: "o", + ù: "u", + ú: "u", + û: "u", + ü: "u", + ű: "u", + ý: "y", + þ: "th", + ÿ: "y", }; const LATIN_SYMBOLS_MAP = { - '©': '(c)' + "©": "(c)", }; const GREEK_MAP = { - 'α': 'a', 'β': 'b', 'γ': 'g', 'δ': 'd', 'ε': 'e', 'ζ': 'z', 'η': 'h', - 'θ': '8', 'ι': 'i', 'κ': 'k', 'λ': 'l', 'μ': 'm', 'ν': 'n', 'ξ': '3', - 'ο': 'o', 'π': 'p', 'ρ': 'r', 'σ': 's', 'τ': 't', 'υ': 'y', 'φ': 'f', - 'χ': 'x', 'ψ': 'ps', 'ω': 'w', 'ά': 'a', 'έ': 'e', 'ί': 'i', 'ό': 'o', - 'ύ': 'y', 'ή': 'h', 'ώ': 'w', 'ς': 's', 'ϊ': 'i', 'ΰ': 'y', 'ϋ': 'y', - 'ΐ': 'i', 'Α': 'A', 'Β': 'B', 'Γ': 'G', 'Δ': 'D', 'Ε': 'E', 'Ζ': 'Z', - 'Η': 'H', 'Θ': '8', 'Ι': 'I', 'Κ': 'K', 'Λ': 'L', 'Μ': 'M', 'Ν': 'N', - 'Ξ': '3', 'Ο': 'O', 'Π': 'P', 'Ρ': 'R', 'Σ': 'S', 'Τ': 'T', 'Υ': 'Y', - 'Φ': 'F', 'Χ': 'X', 'Ψ': 'PS', 'Ω': 'W', 'Ά': 'A', 'Έ': 'E', 'Ί': 'I', - 'Ό': 'O', 'Ύ': 'Y', 'Ή': 'H', 'Ώ': 'W', 'Ϊ': 'I', 'Ϋ': 'Y' + α: "a", + β: "b", + γ: "g", + δ: "d", + ε: "e", + ζ: "z", + η: "h", + θ: "8", + ι: "i", + κ: "k", + λ: "l", + μ: "m", + ν: "n", + ξ: "3", + ο: "o", + π: "p", + ρ: "r", + σ: "s", + τ: "t", + υ: "y", + φ: "f", + χ: "x", + ψ: "ps", + ω: "w", + ά: "a", + έ: "e", + ί: "i", + ό: "o", + ύ: "y", + ή: "h", + ώ: "w", + ς: "s", + ϊ: "i", + ΰ: "y", + ϋ: "y", + ΐ: "i", + Α: "A", + Β: "B", + Γ: "G", + Δ: "D", + Ε: "E", + Ζ: "Z", + Η: "H", + Θ: "8", + Ι: "I", + Κ: "K", + Λ: "L", + Μ: "M", + Ν: "N", + Ξ: "3", + Ο: "O", + Π: "P", + Ρ: "R", + Σ: "S", + Τ: "T", + Υ: "Y", + Φ: "F", + Χ: "X", + Ψ: "PS", + Ω: "W", + Ά: "A", + Έ: "E", + Ί: "I", + Ό: "O", + Ύ: "Y", + Ή: "H", + Ώ: "W", + Ϊ: "I", + Ϋ: "Y", }; const TURKISH_MAP = { - 'ş': 's', 'Ş': 'S', 'ı': 'i', 'İ': 'I', 'ç': 'c', 'Ç': 'C', 'ü': 'u', - 'Ü': 'U', 'ö': 'o', 'Ö': 'O', 'ğ': 'g', 'Ğ': 'G' + ş: "s", + Ş: "S", + ı: "i", + İ: "I", + ç: "c", + Ç: "C", + ü: "u", + Ü: "U", + ö: "o", + Ö: "O", + ğ: "g", + Ğ: "G", }; const ROMANIAN_MAP = { - 'ă': 'a', 'î': 'i', 'ș': 's', 'ț': 't', 'â': 'a', - 'Ă': 'A', 'Î': 'I', 'Ș': 'S', 'Ț': 'T', 'Â': 'A' + ă: "a", + î: "i", + ș: "s", + ț: "t", + â: "a", + Ă: "A", + Î: "I", + Ș: "S", + Ț: "T", + Â: "A", }; const RUSSIAN_MAP = { - 'а': 'a', 'б': 'b', 'в': 'v', 'г': 'g', 'д': 'd', 'е': 'e', 'ё': 'yo', - 'ж': 'zh', 'з': 'z', 'и': 'i', 'й': 'j', 'к': 'k', 'л': 'l', 'м': 'm', - 'н': 'n', 'о': 'o', 'п': 'p', 'р': 'r', 'с': 's', 'т': 't', 'у': 'u', - 'ф': 'f', 'х': 'h', 'ц': 'c', 'ч': 'ch', 'ш': 'sh', 'щ': 'sh', 'ъ': '', - 'ы': 'y', 'ь': '', 'э': 'e', 'ю': 'yu', 'я': 'ya', - 'А': 'A', 'Б': 'B', 'В': 'V', 'Г': 'G', 'Д': 'D', 'Е': 'E', 'Ё': 'Yo', - 'Ж': 'Zh', 'З': 'Z', 'И': 'I', 'Й': 'J', 'К': 'K', 'Л': 'L', 'М': 'M', - 'Н': 'N', 'О': 'O', 'П': 'P', 'Р': 'R', 'С': 'S', 'Т': 'T', 'У': 'U', - 'Ф': 'F', 'Х': 'H', 'Ц': 'C', 'Ч': 'Ch', 'Ш': 'Sh', 'Щ': 'Sh', 'Ъ': '', - 'Ы': 'Y', 'Ь': '', 'Э': 'E', 'Ю': 'Yu', 'Я': 'Ya' + а: "a", + б: "b", + в: "v", + г: "g", + д: "d", + е: "e", + ё: "yo", + ж: "zh", + з: "z", + и: "i", + й: "j", + к: "k", + л: "l", + м: "m", + н: "n", + о: "o", + п: "p", + р: "r", + с: "s", + т: "t", + у: "u", + ф: "f", + х: "h", + ц: "c", + ч: "ch", + ш: "sh", + щ: "sh", + ъ: "", + ы: "y", + ь: "", + э: "e", + ю: "yu", + я: "ya", + А: "A", + Б: "B", + В: "V", + Г: "G", + Д: "D", + Е: "E", + Ё: "Yo", + Ж: "Zh", + З: "Z", + И: "I", + Й: "J", + К: "K", + Л: "L", + М: "M", + Н: "N", + О: "O", + П: "P", + Р: "R", + С: "S", + Т: "T", + У: "U", + Ф: "F", + Х: "H", + Ц: "C", + Ч: "Ch", + Ш: "Sh", + Щ: "Sh", + Ъ: "", + Ы: "Y", + Ь: "", + Э: "E", + Ю: "Yu", + Я: "Ya", }; const UKRAINIAN_MAP = { - 'Є': 'Ye', 'І': 'I', 'Ї': 'Yi', 'Ґ': 'G', 'є': 'ye', 'і': 'i', - 'ї': 'yi', 'ґ': 'g' + Є: "Ye", + І: "I", + Ї: "Yi", + Ґ: "G", + є: "ye", + і: "i", + ї: "yi", + ґ: "g", }; const CZECH_MAP = { - 'č': 'c', 'ď': 'd', 'ě': 'e', 'ň': 'n', 'ř': 'r', 'š': 's', 'ť': 't', - 'ů': 'u', 'ž': 'z', 'Č': 'C', 'Ď': 'D', 'Ě': 'E', 'Ň': 'N', 'Ř': 'R', - 'Š': 'S', 'Ť': 'T', 'Ů': 'U', 'Ž': 'Z' + č: "c", + ď: "d", + ě: "e", + ň: "n", + ř: "r", + š: "s", + ť: "t", + ů: "u", + ž: "z", + Č: "C", + Ď: "D", + Ě: "E", + Ň: "N", + Ř: "R", + Š: "S", + Ť: "T", + Ů: "U", + Ž: "Z", }; const SLOVAK_MAP = { - 'á': 'a', 'ä': 'a', 'č': 'c', 'ď': 'd', 'é': 'e', 'í': 'i', 'ľ': 'l', - 'ĺ': 'l', 'ň': 'n', 'ó': 'o', 'ô': 'o', 'ŕ': 'r', 'š': 's', 'ť': 't', - 'ú': 'u', 'ý': 'y', 'ž': 'z', - 'Á': 'a', 'Ä': 'A', 'Č': 'C', 'Ď': 'D', 'É': 'E', 'Í': 'I', 'Ľ': 'L', - 'Ĺ': 'L', 'Ň': 'N', 'Ó': 'O', 'Ô': 'O', 'Ŕ': 'R', 'Š': 'S', 'Ť': 'T', - 'Ú': 'U', 'Ý': 'Y', 'Ž': 'Z' + á: "a", + ä: "a", + č: "c", + ď: "d", + é: "e", + í: "i", + ľ: "l", + ĺ: "l", + ň: "n", + ó: "o", + ô: "o", + ŕ: "r", + š: "s", + ť: "t", + ú: "u", + ý: "y", + ž: "z", + Á: "a", + Ä: "A", + Č: "C", + Ď: "D", + É: "E", + Í: "I", + Ľ: "L", + Ĺ: "L", + Ň: "N", + Ó: "O", + Ô: "O", + Ŕ: "R", + Š: "S", + Ť: "T", + Ú: "U", + Ý: "Y", + Ž: "Z", }; const POLISH_MAP = { - 'ą': 'a', 'ć': 'c', 'ę': 'e', 'ł': 'l', 'ń': 'n', 'ó': 'o', 'ś': 's', - 'ź': 'z', 'ż': 'z', - 'Ą': 'A', 'Ć': 'C', 'Ę': 'E', 'Ł': 'L', 'Ń': 'N', 'Ó': 'O', 'Ś': 'S', - 'Ź': 'Z', 'Ż': 'Z' + ą: "a", + ć: "c", + ę: "e", + ł: "l", + ń: "n", + ó: "o", + ś: "s", + ź: "z", + ż: "z", + Ą: "A", + Ć: "C", + Ę: "E", + Ł: "L", + Ń: "N", + Ó: "O", + Ś: "S", + Ź: "Z", + Ż: "Z", }; const LATVIAN_MAP = { - 'ā': 'a', 'č': 'c', 'ē': 'e', 'ģ': 'g', 'ī': 'i', 'ķ': 'k', 'ļ': 'l', - 'ņ': 'n', 'š': 's', 'ū': 'u', 'ž': 'z', - 'Ā': 'A', 'Č': 'C', 'Ē': 'E', 'Ģ': 'G', 'Ī': 'I', 'Ķ': 'K', 'Ļ': 'L', - 'Ņ': 'N', 'Š': 'S', 'Ū': 'U', 'Ž': 'Z' + ā: "a", + č: "c", + ē: "e", + ģ: "g", + ī: "i", + ķ: "k", + ļ: "l", + ņ: "n", + š: "s", + ū: "u", + ž: "z", + Ā: "A", + Č: "C", + Ē: "E", + Ģ: "G", + Ī: "I", + Ķ: "K", + Ļ: "L", + Ņ: "N", + Š: "S", + Ū: "U", + Ž: "Z", }; const ARABIC_MAP = { - 'أ': 'a', 'ب': 'b', 'ت': 't', 'ث': 'th', 'ج': 'g', 'ح': 'h', 'خ': 'kh', 'د': 'd', - 'ذ': 'th', 'ر': 'r', 'ز': 'z', 'س': 's', 'ش': 'sh', 'ص': 's', 'ض': 'd', 'ط': 't', - 'ظ': 'th', 'ع': 'aa', 'غ': 'gh', 'ف': 'f', 'ق': 'k', 'ك': 'k', 'ل': 'l', 'م': 'm', - 'ن': 'n', 'ه': 'h', 'و': 'o', 'ي': 'y' + أ: "a", + ب: "b", + ت: "t", + ث: "th", + ج: "g", + ح: "h", + خ: "kh", + د: "d", + ذ: "th", + ر: "r", + ز: "z", + س: "s", + ش: "sh", + ص: "s", + ض: "d", + ط: "t", + ظ: "th", + ع: "aa", + غ: "gh", + ف: "f", + ق: "k", + ك: "k", + ل: "l", + م: "m", + ن: "n", + ه: "h", + و: "o", + ي: "y", }; const LITHUANIAN_MAP = { - 'ą': 'a', 'č': 'c', 'ę': 'e', 'ė': 'e', 'į': 'i', 'š': 's', 'ų': 'u', - 'ū': 'u', 'ž': 'z', - 'Ą': 'A', 'Č': 'C', 'Ę': 'E', 'Ė': 'E', 'Į': 'I', 'Š': 'S', 'Ų': 'U', - 'Ū': 'U', 'Ž': 'Z' + ą: "a", + č: "c", + ę: "e", + ė: "e", + į: "i", + š: "s", + ų: "u", + ū: "u", + ž: "z", + Ą: "A", + Č: "C", + Ę: "E", + Ė: "E", + Į: "I", + Š: "S", + Ų: "U", + Ū: "U", + Ž: "Z", }; const SERBIAN_MAP = { - 'ђ': 'dj', 'ј': 'j', 'љ': 'lj', 'њ': 'nj', 'ћ': 'c', 'џ': 'dz', - 'đ': 'dj', 'Ђ': 'Dj', 'Ј': 'j', 'Љ': 'Lj', 'Њ': 'Nj', 'Ћ': 'C', - 'Џ': 'Dz', 'Đ': 'Dj' + ђ: "dj", + ј: "j", + љ: "lj", + њ: "nj", + ћ: "c", + џ: "dz", + đ: "dj", + Ђ: "Dj", + Ј: "j", + Љ: "Lj", + Њ: "Nj", + Ћ: "C", + Џ: "Dz", + Đ: "Dj", }; const AZERBAIJANI_MAP = { - 'ç': 'c', 'ə': 'e', 'ğ': 'g', 'ı': 'i', 'ö': 'o', 'ş': 's', 'ü': 'u', - 'Ç': 'C', 'Ə': 'E', 'Ğ': 'G', 'İ': 'I', 'Ö': 'O', 'Ş': 'S', 'Ü': 'U' + ç: "c", + ə: "e", + ğ: "g", + ı: "i", + ö: "o", + ş: "s", + ü: "u", + Ç: "C", + Ə: "E", + Ğ: "G", + İ: "I", + Ö: "O", + Ş: "S", + Ü: "U", }; const GEORGIAN_MAP = { - 'ა': 'a', 'ბ': 'b', 'გ': 'g', 'დ': 'd', 'ე': 'e', 'ვ': 'v', 'ზ': 'z', - 'თ': 't', 'ი': 'i', 'კ': 'k', 'ლ': 'l', 'მ': 'm', 'ნ': 'n', 'ო': 'o', - 'პ': 'p', 'ჟ': 'j', 'რ': 'r', 'ს': 's', 'ტ': 't', 'უ': 'u', 'ფ': 'f', - 'ქ': 'q', 'ღ': 'g', 'ყ': 'y', 'შ': 'sh', 'ჩ': 'ch', 'ც': 'c', 'ძ': 'dz', - 'წ': 'w', 'ჭ': 'ch', 'ხ': 'x', 'ჯ': 'j', 'ჰ': 'h' + ა: "a", + ბ: "b", + გ: "g", + დ: "d", + ე: "e", + ვ: "v", + ზ: "z", + თ: "t", + ი: "i", + კ: "k", + ლ: "l", + მ: "m", + ნ: "n", + ო: "o", + პ: "p", + ჟ: "j", + რ: "r", + ს: "s", + ტ: "t", + უ: "u", + ფ: "f", + ქ: "q", + ღ: "g", + ყ: "y", + შ: "sh", + ჩ: "ch", + ც: "c", + ძ: "dz", + წ: "w", + ჭ: "ch", + ხ: "x", + ჯ: "j", + ჰ: "h", }; const ALL_DOWNCODE_MAPS = [ @@ -122,30 +482,33 @@ LITHUANIAN_MAP, SERBIAN_MAP, AZERBAIJANI_MAP, - GEORGIAN_MAP + GEORGIAN_MAP, ]; const Downcoder = { - 'Initialize': function() { - if (Downcoder.map) { // already made + Initialize: function () { + if (Downcoder.map) { + // already made return; } Downcoder.map = {}; for (const lookup of ALL_DOWNCODE_MAPS) { Object.assign(Downcoder.map, lookup); } - Downcoder.regex = new RegExp(Object.keys(Downcoder.map).join('|'), 'g'); - } + Downcoder.regex = new RegExp( + Object.keys(Downcoder.map).join("|"), + "g", + ); + }, }; function downcode(slug) { Downcoder.Initialize(); - return slug.replace(Downcoder.regex, function(m) { + return slug.replace(Downcoder.regex, function (m) { return Downcoder.map[m]; }); } - function URLify(s, num_chars, allowUnicode) { // changes, e.g., "Petty theft" to "petty-theft" if (!allowUnicode) { @@ -156,14 +519,14 @@ if (allowUnicode) { // Keep Unicode letters including both lowercase and uppercase // characters, whitespace, and dash; remove other characters. - s = XRegExp.replace(s, XRegExp('[^-_\\p{L}\\p{N}\\s]', 'g'), ''); + s = XRegExp.replace(s, XRegExp("[^-_\\p{L}\\p{N}\\s]", "g"), ""); } else { - s = s.replace(/[^-\w\s]/g, ''); // remove unneeded chars + s = s.replace(/[^-\w\s]/g, ""); // remove unneeded chars } - s = s.replace(/^\s+|\s+$/g, ''); // trim leading/trailing spaces - s = s.replace(/[-\s]+/g, '-'); // convert spaces to hyphens + s = s.replace(/^\s+|\s+$/g, ""); // trim leading/trailing spaces + s = s.replace(/[-\s]+/g, "-"); // convert spaces to hyphens s = s.substring(0, num_chars); // trim to first num_chars chars - return s.replace(/-+$/g, ''); // trim any trailing hyphens + return s.replace(/-+$/g, ""); // trim any trailing hyphens } window.URLify = URLify; } diff --git a/django/contrib/gis/static/gis/js/OLMapWidget.js b/django/contrib/gis/static/gis/js/OLMapWidget.js index 50860650f9..05629496c8 100644 --- a/django/contrib/gis/static/gis/js/OLMapWidget.js +++ b/django/contrib/gis/static/gis/js/OLMapWidget.js @@ -1,38 +1,45 @@ /* global ol */ -'use strict'; +"use strict"; class GeometryTypeControl extends ol.control.Control { // Map control to switch type when geometry type is unknown constructor(opt_options) { const options = opt_options || {}; - const element = document.createElement('div'); - element.className = 'switch-type type-' + options.type + ' ol-control ol-unselectable'; + const element = document.createElement("div"); + element.className = + "switch-type type-" + options.type + " ol-control ol-unselectable"; if (options.active) { element.classList.add("type-active"); } super({ element: element, - target: options.target + target: options.target, }); const self = this; - const switchType = function(e) { + const switchType = function (e) { e.preventDefault(); if (options.widget.currentGeometryType !== self) { - options.widget.map.removeInteraction(options.widget.interactions.draw); + options.widget.map.removeInteraction( + options.widget.interactions.draw, + ); options.widget.interactions.draw = new ol.interaction.Draw({ features: options.widget.featureCollection, - type: options.type + type: options.type, }); - options.widget.map.addInteraction(options.widget.interactions.draw); - options.widget.currentGeometryType.element.classList.remove('type-active'); + options.widget.map.addInteraction( + options.widget.interactions.draw, + ); + options.widget.currentGeometryType.element.classList.remove( + "type-active", + ); options.widget.currentGeometryType = self; element.classList.add("type-active"); } }; - element.addEventListener('click', switchType, false); - element.addEventListener('touchstart', switchType, false); + element.addEventListener("click", switchType, false); + element.addEventListener("touchstart", switchType, false); } } @@ -40,7 +47,7 @@ class GeometryTypeControl extends ol.control.Control { class MapWidget { constructor(options) { this.map = null; - this.interactions = {draw: null, modify: null}; + this.interactions = { draw: null, modify: null }; this.typeChoices = false; this.ready = false; @@ -49,7 +56,9 @@ class MapWidget { default_lat: 0, default_lon: 0, default_zoom: 12, - is_collection: options.geom_name.includes('Multi') || options.geom_name.includes('Collection') + is_collection: + options.geom_name.includes("Multi") || + options.geom_name.includes("Collection"), }; // Altering using user-provided options @@ -62,9 +71,12 @@ class MapWidget { // Options' base_layer can be empty, or contain a layerBuilder key, or // be a layer already constructed. const base_layer = options.base_layer; - if (typeof base_layer === 'string' && base_layer in MapWidget.layerBuilder) { + if ( + typeof base_layer === "string" && + base_layer in MapWidget.layerBuilder + ) { this.baseLayer = MapWidget.layerBuilder[base_layer](); - } else if (base_layer && typeof base_layer !== 'string') { + } else if (base_layer && typeof base_layer !== "string") { this.baseLayer = base_layer; } else { this.baseLayer = MapWidget.layerBuilder.osm(); @@ -76,17 +88,17 @@ class MapWidget { map: this.map, source: new ol.source.Vector({ features: this.featureCollection, - useSpatialIndex: false // improve performance + useSpatialIndex: false, // improve performance }), updateWhileAnimating: true, // optional, for instant visual feedback - updateWhileInteracting: true // optional, for instant visual feedback + updateWhileInteracting: true, // optional, for instant visual feedback }); // Populate and set handlers for the feature container const self = this; - this.featureCollection.on('add', function(event) { + this.featureCollection.on("add", function (event) { const feature = event.element; - feature.on('change', function() { + feature.on("change", function () { self.serializeFeatures(); }); if (self.ready) { @@ -100,14 +112,16 @@ class MapWidget { const initial_value = document.getElementById(this.options.id).value; if (initial_value) { const jsonFormat = new ol.format.GeoJSON(); - const features = jsonFormat.readFeatures('{"type": "Feature", "geometry": ' + initial_value + '}'); + const features = jsonFormat.readFeatures( + '{"type": "Feature", "geometry": ' + initial_value + "}", + ); const extent = ol.extent.createEmpty(); - features.forEach(function(feature) { + features.forEach(function (feature) { this.featureOverlay.getSource().addFeature(feature); ol.extent.extend(extent, feature.getGeometry().getExtent()); }, this); // Center/zoom the map - this.map.getView().fit(extent, {minResolution: 1}); + this.map.getView().fit(extent, { minResolution: 1 }); } else { this.map.getView().setCenter(this.defaultCenter()); } @@ -115,9 +129,11 @@ class MapWidget { if (initial_value && !this.options.is_collection) { this.disableDrawing(); } - const clearNode = document.getElementById(this.map.getTarget()).nextElementSibling; - if (clearNode.classList.contains('clear_features')) { - clearNode.querySelector('a').addEventListener('click', (ev) => { + const clearNode = document.getElementById( + this.map.getTarget(), + ).nextElementSibling; + if (clearNode.classList.contains("clear_features")) { + clearNode.querySelector("a").addEventListener("click", (ev) => { ev.preventDefault(); self.clearFeatures(); }); @@ -130,8 +146,8 @@ class MapWidget { target: this.options.map_id, layers: [this.baseLayer], view: new ol.View({ - zoom: this.options.default_zoom - }) + zoom: this.options.default_zoom, + }), }); } @@ -139,10 +155,12 @@ class MapWidget { // Initialize the modify interaction this.interactions.modify = new ol.interaction.Modify({ features: this.featureCollection, - deleteCondition: function(event) { - return ol.events.condition.shiftKeyOnly(event) && - ol.events.condition.singleClick(event); - } + deleteCondition: function (event) { + return ( + ol.events.condition.shiftKeyOnly(event) && + ol.events.condition.singleClick(event) + ); + }, }); // Initialize the draw interaction @@ -150,15 +168,31 @@ class MapWidget { if (geomType === "Geometry" || geomType === "GeometryCollection") { // Default to Point, but create icons to switch type geomType = "Point"; - this.currentGeometryType = new GeometryTypeControl({widget: this, type: "Point", active: true}); + this.currentGeometryType = new GeometryTypeControl({ + widget: this, + type: "Point", + active: true, + }); this.map.addControl(this.currentGeometryType); - this.map.addControl(new GeometryTypeControl({widget: this, type: "LineString", active: false})); - this.map.addControl(new GeometryTypeControl({widget: this, type: "Polygon", active: false})); + this.map.addControl( + new GeometryTypeControl({ + widget: this, + type: "LineString", + active: false, + }), + ); + this.map.addControl( + new GeometryTypeControl({ + widget: this, + type: "Polygon", + active: false, + }), + ); this.typeChoices = true; } this.interactions.draw = new ol.interaction.Draw({ features: this.featureCollection, - type: geomType + type: geomType, }); this.map.addInteraction(this.interactions.draw); @@ -168,7 +202,11 @@ class MapWidget { defaultCenter() { const center = [this.options.default_lon, this.options.default_lat]; if (this.options.map_srid) { - return ol.proj.transform(center, 'EPSG:4326', this.map.getView().getProjection()); + return ol.proj.transform( + center, + "EPSG:4326", + this.map.getView().getProjection(), + ); } return center; } @@ -200,7 +238,7 @@ class MapWidget { clearFeatures() { this.featureCollection.clear(); // Empty textarea widget - document.getElementById(this.options.id).value = ''; + document.getElementById(this.options.id).value = ""; this.enableDrawing(); } @@ -219,14 +257,20 @@ class MapWidget { geometry = features[0].getGeometry().clone(); for (let j = 1; j < features.length; j++) { switch (geometry.getType()) { - case "MultiPoint": - geometry.appendPoint(features[j].getGeometry().getPoint(0)); - break; - case "MultiLineString": - geometry.appendLineString(features[j].getGeometry().getLineString(0)); - break; - case "MultiPolygon": - geometry.appendPolygon(features[j].getGeometry().getPolygon(0)); + case "MultiPoint": + geometry.appendPoint( + features[j].getGeometry().getPoint(0), + ); + break; + case "MultiLineString": + geometry.appendLineString( + features[j].getGeometry().getLineString(0), + ); + break; + case "MultiPolygon": + geometry.appendPolygon( + features[j].getGeometry().getPolygon(0), + ); } } } @@ -236,7 +280,8 @@ class MapWidget { } } const jsonFormat = new ol.format.GeoJSON(); - document.getElementById(this.options.id).value = jsonFormat.writeGeometry(geometry); + document.getElementById(this.options.id).value = + jsonFormat.writeGeometry(geometry); } } @@ -247,15 +292,16 @@ MapWidget.layerBuilder = { source: new ol.source.XYZ({ attributions: "NASA Worldview", maxZoom: 8, - url: "https://map1{a-c}.vis.earthdata.nasa.gov/wmts-webmerc/" + - "BlueMarble_ShadedRelief_Bathymetry/default/%7BTime%7D/" + - "GoogleMapsCompatible_Level8/{z}/{y}/{x}.jpg" - }) + url: + "https://map1{a-c}.vis.earthdata.nasa.gov/wmts-webmerc/" + + "BlueMarble_ShadedRelief_Bathymetry/default/%7BTime%7D/" + + "GoogleMapsCompatible_Level8/{z}/{y}/{x}.jpg", + }), }); }, osm: () => { - return new ol.layer.Tile({source: new ol.source.OSM()}); - } + return new ol.layer.Tile({ source: new ol.source.OSM() }); + }, }; function initMapWidgetInSection(section) { @@ -263,11 +309,13 @@ function initMapWidgetInSection(section) { section.querySelectorAll(".dj_map_wrapper").forEach((wrapper) => { // Avoid initializing map widget on an empty form. - if (wrapper.id.includes('__prefix__')) { + if (wrapper.id.includes("__prefix__")) { return; } const textarea_id = wrapper.querySelector("textarea").id; - const options_script = wrapper.querySelector(`script#${textarea_id}_mapwidget_options`); + const options_script = wrapper.querySelector( + `script#${textarea_id}_mapwidget_options`, + ); const options = JSON.parse(options_script.textContent); options.id = textarea_id; options.map_id = wrapper.querySelector(".dj_map").id; @@ -275,9 +323,11 @@ function initMapWidgetInSection(section) { }); return maps; -}; +} document.addEventListener("DOMContentLoaded", () => { initMapWidgetInSection(document); - document.addEventListener('formset:added', (ev) => {initMapWidgetInSection(ev.target);}); + document.addEventListener("formset:added", (ev) => { + initMapWidgetInSection(ev.target); + }); }); diff --git a/js_tests/admin/DateTimeShortcuts.test.js b/js_tests/admin/DateTimeShortcuts.test.js index 6cb534610c..5c850ce7d2 100644 --- a/js_tests/admin/DateTimeShortcuts.test.js +++ b/js_tests/admin/DateTimeShortcuts.test.js @@ -1,59 +1,81 @@ /* global QUnit, DateTimeShortcuts */ -'use strict'; +"use strict"; -QUnit.module('admin.DateTimeShortcuts'); +QUnit.module("admin.DateTimeShortcuts"); -QUnit.test('init', function(assert) { +QUnit.test("init", function (assert) { const $ = django.jQuery; - const dateField = $('<input type="text" class="vDateField" value="2015-03-16"><br>'); - $('#qunit-fixture').append(dateField); + const dateField = $( + '<input type="text" class="vDateField" value="2015-03-16"><br>', + ); + $("#qunit-fixture").append(dateField); DateTimeShortcuts.init(); - const shortcuts = $('.datetimeshortcuts'); + const shortcuts = $(".datetimeshortcuts"); assert.equal(shortcuts.length, 1); - assert.equal(shortcuts.find('a:first').text(), 'Today'); - assert.equal(shortcuts.find('a:last .date-icon').length, 1); + assert.equal(shortcuts.find("a:first").text(), "Today"); + assert.equal(shortcuts.find("a:last .date-icon").length, 1); // To prevent incorrect timezone warnings on date/time widgets, timezoneOffset // should be 0 when a timezone offset isn't set in the HTML body attribute. assert.equal(DateTimeShortcuts.timezoneOffset, 0); }); -QUnit.test('custom time shortcuts', function(assert) { +QUnit.test("custom time shortcuts", function (assert) { const $ = django.jQuery; - const timeField = $('<input type="text" name="time_test" class="vTimeField">'); - $('#qunit-fixture').append(timeField); - DateTimeShortcuts.clockHours.time_test = [['3 a.m.', 3]]; + const timeField = $( + '<input type="text" name="time_test" class="vTimeField">', + ); + $("#qunit-fixture").append(timeField); + DateTimeShortcuts.clockHours.time_test = [["3 a.m.", 3]]; DateTimeShortcuts.init(); - assert.equal($('.clockbox').find('a').first().text(), '3 a.m.'); + assert.equal($(".clockbox").find("a").first().text(), "3 a.m."); }); -QUnit.test('time zone offset warning - single field', function(assert) { +QUnit.test("time zone offset warning - single field", function (assert) { const $ = django.jQuery; - const savedOffset = $('body').attr('data-admin-utc-offset'); + const savedOffset = $("body").attr("data-admin-utc-offset"); // Single date or time field. - const timeField = $('<input id="id_updated_at" type="text" name="updated_at" class="vTimeField">'); - $('#qunit-fixture').append(timeField); - $('body').attr('data-admin-utc-offset', new Date().getTimezoneOffset() * -60 + 3600); + const timeField = $( + '<input id="id_updated_at" type="text" name="updated_at" class="vTimeField">', + ); + $("#qunit-fixture").append(timeField); + $("body").attr( + "data-admin-utc-offset", + new Date().getTimezoneOffset() * -60 + 3600, + ); DateTimeShortcuts.init(); - $('body').attr('data-admin-utc-offset', savedOffset); - assert.equal($('.timezonewarning').text(), 'Note: You are 1 hour behind server time.'); - assert.equal($('.timezonewarning').attr("id"), "id_updated_at_timezone_warning_helptext"); + $("body").attr("data-admin-utc-offset", savedOffset); + assert.equal( + $(".timezonewarning").text(), + "Note: You are 1 hour behind server time.", + ); + assert.equal( + $(".timezonewarning").attr("id"), + "id_updated_at_timezone_warning_helptext", + ); }); -QUnit.test('time zone offset warning - date and time field', function(assert) { +QUnit.test("time zone offset warning - date and time field", function (assert) { const $ = django.jQuery; - const savedOffset = $('body').attr('data-admin-utc-offset'); + const savedOffset = $("body").attr("data-admin-utc-offset"); // DateTimeField with fieldset containing date and time inputs. - const dateTimeField = '<p class="datetime">' + - '<input id="id_updated_at_0" type="text" name="updated_at_0" class="vDateField">' + - '<input id="id_updated_at_1" type="text" name="updated_at_1" class="vTimeField">' + - '</p>'; - $('#qunit-fixture').append($(dateTimeField)); - $('body').attr('data-admin-utc-offset', new Date().getTimezoneOffset() * -60 + 3600); + const dateTimeField = + '<p class="datetime">' + + '<input id="id_updated_at_0" type="text" name="updated_at_0" class="vDateField">' + + '<input id="id_updated_at_1" type="text" name="updated_at_1" class="vTimeField">' + + "</p>"; + $("#qunit-fixture").append($(dateTimeField)); + $("body").attr( + "data-admin-utc-offset", + new Date().getTimezoneOffset() * -60 + 3600, + ); DateTimeShortcuts.init(); - $('body').attr('data-admin-utc-offset', savedOffset); - assert.equal($('.timezonewarning').attr("id"), "id_updated_at_timezone_warning_helptext"); + $("body").attr("data-admin-utc-offset", savedOffset); + assert.equal( + $(".timezonewarning").attr("id"), + "id_updated_at_timezone_warning_helptext", + ); }); diff --git a/js_tests/admin/RelatedObjectLookups.test.js b/js_tests/admin/RelatedObjectLookups.test.js index 0d71d88f2a..b7df8f181f 100644 --- a/js_tests/admin/RelatedObjectLookups.test.js +++ b/js_tests/admin/RelatedObjectLookups.test.js @@ -1,77 +1,98 @@ /* global QUnit, RelatedObjectLookups */ -'use strict'; +"use strict"; -QUnit.module('admin.RelatedObjectLookups', { - beforeEach: function() { +QUnit.module("admin.RelatedObjectLookups", { + beforeEach: function () { const $ = django.jQuery; - $('#qunit-fixture').append(` + $("#qunit-fixture").append(` <input type="text" id="test_id" name="test" /> <input type="text" id="many_test_id" name="many_test" class="vManyToManyRawIdAdminField" /> `); - } + }, }); -QUnit.test('dismissRelatedLookupPopup closes popup window', function(assert) { - const testId = 'test_id'; +QUnit.test("dismissRelatedLookupPopup closes popup window", function (assert) { + const testId = "test_id"; let windowClosed = false; const mockWin = { name: testId, - close: function() { + close: function () { windowClosed = true; - } + }, }; - window.dismissRelatedLookupPopup(mockWin, '123'); - assert.true(windowClosed, 'Popup window should be closed'); + window.dismissRelatedLookupPopup(mockWin, "123"); + assert.true(windowClosed, "Popup window should be closed"); }); -QUnit.test('dismissRelatedLookupPopup removes window from relatedWindows array', function(assert) { - const testId = 'test_id'; - const mockWin = { - name: testId, - close: function() {} - }; - window.relatedWindows.push(mockWin); - assert.equal(window.relatedWindows.indexOf(mockWin), 0, 'Window should be in relatedWindows array'); - window.dismissRelatedLookupPopup(mockWin, '123'); - assert.equal(window.relatedWindows.indexOf(mockWin), -1, 'Window should be removed from relatedWindows array'); -}); +QUnit.test( + "dismissRelatedLookupPopup removes window from relatedWindows array", + function (assert) { + const testId = "test_id"; + const mockWin = { + name: testId, + close: function () {}, + }; + window.relatedWindows.push(mockWin); + assert.equal( + window.relatedWindows.indexOf(mockWin), + 0, + "Window should be in relatedWindows array", + ); + window.dismissRelatedLookupPopup(mockWin, "123"); + assert.equal( + window.relatedWindows.indexOf(mockWin), + -1, + "Window should be removed from relatedWindows array", + ); + }, +); -QUnit.test('dismissRelatedLookupPopup triggers change event for single value field', function(assert) { - assert.timeout(1000); - const done = assert.async(); - const $ = django.jQuery; - const testId = 'test_id'; - const newValue = '123'; - const mockWin = { - name: testId, - close: function() {} - }; - let changeTriggered = false; - $('#test_id').on('change', function() { - changeTriggered = true; - assert.equal(this.value, newValue, 'Value should be updated'); - done(); - }); - window.dismissRelatedLookupPopup(mockWin, newValue); - assert.true(changeTriggered, 'Change event should be triggered'); -}); +QUnit.test( + "dismissRelatedLookupPopup triggers change event for single value field", + function (assert) { + assert.timeout(1000); + const done = assert.async(); + const $ = django.jQuery; + const testId = "test_id"; + const newValue = "123"; + const mockWin = { + name: testId, + close: function () {}, + }; + let changeTriggered = false; + $("#test_id").on("change", function () { + changeTriggered = true; + assert.equal(this.value, newValue, "Value should be updated"); + done(); + }); + window.dismissRelatedLookupPopup(mockWin, newValue); + assert.true(changeTriggered, "Change event should be triggered"); + }, +); -QUnit.test('dismissRelatedLookupPopup triggers change event for many-to-many field', function(assert) { - assert.timeout(1000); - const $ = django.jQuery; - const testId = 'many_test_id'; - const existingValue = '1,2'; - const newValue = '3'; - $('#many_test_id').val(existingValue); - const mockWin = { - name: testId, - close: function() {} - }; - let changeTriggered = false; - $('#many_test_id').on('change', function() { - changeTriggered = true; - assert.equal(this.value, existingValue + ',' + newValue, 'Value should be appended for many-to-many fields'); - }); - window.dismissRelatedLookupPopup(mockWin, newValue); - assert.true(changeTriggered, 'Change event should be triggered'); -}); +QUnit.test( + "dismissRelatedLookupPopup triggers change event for many-to-many field", + function (assert) { + assert.timeout(1000); + const $ = django.jQuery; + const testId = "many_test_id"; + const existingValue = "1,2"; + const newValue = "3"; + $("#many_test_id").val(existingValue); + const mockWin = { + name: testId, + close: function () {}, + }; + let changeTriggered = false; + $("#many_test_id").on("change", function () { + changeTriggered = true; + assert.equal( + this.value, + existingValue + "," + newValue, + "Value should be appended for many-to-many fields", + ); + }); + window.dismissRelatedLookupPopup(mockWin, newValue); + assert.true(changeTriggered, "Change event should be triggered"); + }, +); diff --git a/js_tests/admin/SelectBox.test.js b/js_tests/admin/SelectBox.test.js index 4915ba6b9b..e32fa4c353 100644 --- a/js_tests/admin/SelectBox.test.js +++ b/js_tests/admin/SelectBox.test.js @@ -1,207 +1,210 @@ /* global QUnit, SelectBox */ -'use strict'; +"use strict"; -QUnit.module('admin.SelectBox'); +QUnit.module("admin.SelectBox"); -QUnit.test('init: no options', function(assert) { +QUnit.test("init: no options", function (assert) { const $ = django.jQuery; - $('<select id="id"></select>').appendTo('#qunit-fixture'); - SelectBox.init('id'); + $('<select id="id"></select>').appendTo("#qunit-fixture"); + SelectBox.init("id"); assert.equal(SelectBox.cache.id.length, 0); }); -QUnit.test('filter', function(assert) { +QUnit.test("filter", function (assert) { const $ = django.jQuery; - $('<select id="id"></select>').appendTo('#qunit-fixture'); - $('<option value="0">A</option>').appendTo('#id'); - $('<option value="1">B</option>').appendTo('#id'); - SelectBox.init('id'); - assert.equal($('#id option').length, 2); - SelectBox.filter('id', "A"); - assert.equal($('#id option').length, 1); - assert.equal($('#id option').text(), "A"); + $('<select id="id"></select>').appendTo("#qunit-fixture"); + $('<option value="0">A</option>').appendTo("#id"); + $('<option value="1">B</option>').appendTo("#id"); + SelectBox.init("id"); + assert.equal($("#id option").length, 2); + SelectBox.filter("id", "A"); + assert.equal($("#id option").length, 1); + assert.equal($("#id option").text(), "A"); }); -QUnit.test('preserve scroll position', function(assert) { +QUnit.test("preserve scroll position", function (assert) { const $ = django.jQuery; const optionsCount = 100; - $('<select id="from_id" multiple></select>').appendTo('#qunit-fixture'); - $('<select id="to_id" multiple></select>').appendTo('#qunit-fixture'); - const fromSelectBox = document.getElementById('from_id'); - const toSelectBox = document.getElementById('to_id'); + $('<select id="from_id" multiple></select>').appendTo("#qunit-fixture"); + $('<select id="to_id" multiple></select>').appendTo("#qunit-fixture"); + const fromSelectBox = document.getElementById("from_id"); + const toSelectBox = document.getElementById("to_id"); for (let i = 0; i < optionsCount; i++) { fromSelectBox.appendChild(new Option()); } - SelectBox.init('from_id'); - SelectBox.init('to_id'); + SelectBox.init("from_id"); + SelectBox.init("to_id"); const selectedOptions = [97, 98, 99]; for (const index of selectedOptions) { fromSelectBox.options[index].selected = true; fromSelectBox.options[index].scrollIntoView(); } assert.equal(fromSelectBox.options.length, optionsCount); - SelectBox.move('from_id', 'to_id'); - assert.equal(fromSelectBox.options.length, optionsCount - selectedOptions.length); + SelectBox.move("from_id", "to_id"); + assert.equal( + fromSelectBox.options.length, + optionsCount - selectedOptions.length, + ); assert.equal(toSelectBox.options.length, selectedOptions.length); assert.notEqual(fromSelectBox.scrollTop, 0); }); -QUnit.test('retain optgroups', function(assert) { +QUnit.test("retain optgroups", function (assert) { const $ = django.jQuery; - $('<select id="id"></select>').appendTo('#qunit-fixture'); - const grp = $('<optgroup label="group one">').appendTo('#id'); + $('<select id="id"></select>').appendTo("#qunit-fixture"); + const grp = $('<optgroup label="group one">').appendTo("#id"); $('<option value="0">A</option>').appendTo(grp); - $('</optgroup>').appendTo('#id'); - $('<option value="1">B</option>').appendTo('#id'); - SelectBox.init('id'); - SelectBox.redisplay('id'); - assert.equal($('#id option').length, 2); - assert.equal($('#id optgroup').length, 1); + $("</optgroup>").appendTo("#id"); + $('<option value="1">B</option>').appendTo("#id"); + SelectBox.init("id"); + SelectBox.redisplay("id"); + assert.equal($("#id option").length, 2); + assert.equal($("#id optgroup").length, 1); }); -QUnit.test('sort optgroups', function(assert) { +QUnit.test("sort optgroups", function (assert) { const $ = django.jQuery; - $('<select id="id"></select>').appendTo('#qunit-fixture'); + $('<select id="id"></select>').appendTo("#qunit-fixture"); // Add optgroups in non-alphabetical order - const grp2 = $('<optgroup label="Group B">').appendTo('#id'); + const grp2 = $('<optgroup label="Group B">').appendTo("#id"); $('<option value="3">Item 3</option>').appendTo(grp2); $('<option value="4">Item 4</option>').appendTo(grp2); - const grp1 = $('<optgroup label="Group A">').appendTo('#id'); + const grp1 = $('<optgroup label="Group A">').appendTo("#id"); $('<option value="1">Item 1</option>').appendTo(grp1); $('<option value="2">Item 2</option>').appendTo(grp1); - SelectBox.init('id'); + SelectBox.init("id"); // Verify cache is sorted by group then by item assert.equal(SelectBox.cache.id.length, 4); - assert.equal(SelectBox.cache.id[0].group, 'Group A'); - assert.equal(SelectBox.cache.id[0].text, 'Item 1'); - assert.equal(SelectBox.cache.id[1].group, 'Group A'); - assert.equal(SelectBox.cache.id[1].text, 'Item 2'); - assert.equal(SelectBox.cache.id[2].group, 'Group B'); - assert.equal(SelectBox.cache.id[2].text, 'Item 3'); - assert.equal(SelectBox.cache.id[3].group, 'Group B'); - assert.equal(SelectBox.cache.id[3].text, 'Item 4'); + assert.equal(SelectBox.cache.id[0].group, "Group A"); + assert.equal(SelectBox.cache.id[0].text, "Item 1"); + assert.equal(SelectBox.cache.id[1].group, "Group A"); + assert.equal(SelectBox.cache.id[1].text, "Item 2"); + assert.equal(SelectBox.cache.id[2].group, "Group B"); + assert.equal(SelectBox.cache.id[2].text, "Item 3"); + assert.equal(SelectBox.cache.id[3].group, "Group B"); + assert.equal(SelectBox.cache.id[3].text, "Item 4"); }); -QUnit.test('do not sort when no optgroups', function(assert) { +QUnit.test("do not sort when no optgroups", function (assert) { const $ = django.jQuery; - $('<select id="id"></select>').appendTo('#qunit-fixture'); + $('<select id="id"></select>').appendTo("#qunit-fixture"); // Add options in non-alphabetical order - $('<option value="3">Zebra</option>').appendTo('#id'); - $('<option value="1">Apple</option>').appendTo('#id'); - $('<option value="2">Banana</option>').appendTo('#id'); + $('<option value="3">Zebra</option>').appendTo("#id"); + $('<option value="1">Apple</option>').appendTo("#id"); + $('<option value="2">Banana</option>').appendTo("#id"); - SelectBox.init('id'); + SelectBox.init("id"); // Verify cache preserves original order (not sorted) assert.equal(SelectBox.cache.id.length, 3); - assert.equal(SelectBox.cache.id[0].text, 'Zebra'); - assert.equal(SelectBox.cache.id[1].text, 'Apple'); - assert.equal(SelectBox.cache.id[2].text, 'Banana'); + assert.equal(SelectBox.cache.id[0].text, "Zebra"); + assert.equal(SelectBox.cache.id[1].text, "Apple"); + assert.equal(SelectBox.cache.id[2].text, "Banana"); }); -QUnit.test('move with optgroups sorts', function(assert) { +QUnit.test("move with optgroups sorts", function (assert) { const $ = django.jQuery; - $('<select id="from_id"></select>').appendTo('#qunit-fixture'); - $('<select id="to_id"></select>').appendTo('#qunit-fixture'); + $('<select id="from_id"></select>').appendTo("#qunit-fixture"); + $('<select id="to_id"></select>').appendTo("#qunit-fixture"); // Add options with optgroups to from_id in non-alphabetical order - const grp2 = $('<optgroup label="Group B">').appendTo('#from_id'); + const grp2 = $('<optgroup label="Group B">').appendTo("#from_id"); $('<option value="2">Item 2</option>').appendTo(grp2); - const grp1 = $('<optgroup label="Group A">').appendTo('#from_id'); + const grp1 = $('<optgroup label="Group A">').appendTo("#from_id"); $('<option value="1">Item 1</option>').appendTo(grp1); - SelectBox.init('from_id'); - SelectBox.init('to_id'); + SelectBox.init("from_id"); + SelectBox.init("to_id"); // Select and move item - document.getElementById('from_id').options[0].selected = true; - SelectBox.move('from_id', 'to_id'); + document.getElementById("from_id").options[0].selected = true; + SelectBox.move("from_id", "to_id"); // Verify to_id cache is sorted (even though we only added one item) assert.equal(SelectBox.cache.to_id.length, 1); - assert.equal(SelectBox.cache.to_id[0].group, 'Group B'); - assert.equal(SelectBox.cache.to_id[0].text, 'Item 2'); + assert.equal(SelectBox.cache.to_id[0].group, "Group B"); + assert.equal(SelectBox.cache.to_id[0].text, "Item 2"); }); -QUnit.test('move without optgroups does not sort', function(assert) { +QUnit.test("move without optgroups does not sort", function (assert) { const $ = django.jQuery; - $('<select id="from_id"></select>').appendTo('#qunit-fixture'); - $('<select id="to_id"></select>').appendTo('#qunit-fixture'); + $('<select id="from_id"></select>').appendTo("#qunit-fixture"); + $('<select id="to_id"></select>').appendTo("#qunit-fixture"); // Add options without optgroups in non-alphabetical order - $('<option value="3">Zebra</option>').appendTo('#from_id'); - $('<option value="1">Apple</option>').appendTo('#from_id'); + $('<option value="3">Zebra</option>').appendTo("#from_id"); + $('<option value="1">Apple</option>').appendTo("#from_id"); - SelectBox.init('from_id'); - SelectBox.init('to_id'); + SelectBox.init("from_id"); + SelectBox.init("to_id"); // Select and move first item (Zebra) - document.getElementById('from_id').options[0].selected = true; - SelectBox.move('from_id', 'to_id'); + document.getElementById("from_id").options[0].selected = true; + SelectBox.move("from_id", "to_id"); // Verify to_id cache preserves order (not sorted) assert.equal(SelectBox.cache.to_id.length, 1); - assert.equal(SelectBox.cache.to_id[0].text, 'Zebra'); + assert.equal(SelectBox.cache.to_id[0].text, "Zebra"); // Move second item (Apple) - document.getElementById('from_id').options[0].selected = true; - SelectBox.move('from_id', 'to_id'); + document.getElementById("from_id").options[0].selected = true; + SelectBox.move("from_id", "to_id"); // Verify items are in order they were added, not alphabetical assert.equal(SelectBox.cache.to_id.length, 2); - assert.equal(SelectBox.cache.to_id[0].text, 'Zebra'); - assert.equal(SelectBox.cache.to_id[1].text, 'Apple'); + assert.equal(SelectBox.cache.to_id[0].text, "Zebra"); + assert.equal(SelectBox.cache.to_id[1].text, "Apple"); }); -QUnit.test('move_all with optgroups sorts', function(assert) { +QUnit.test("move_all with optgroups sorts", function (assert) { const $ = django.jQuery; - $('<select id="from_id"></select>').appendTo('#qunit-fixture'); - $('<select id="to_id"></select>').appendTo('#qunit-fixture'); + $('<select id="from_id"></select>').appendTo("#qunit-fixture"); + $('<select id="to_id"></select>').appendTo("#qunit-fixture"); // Add options with optgroups in non-alphabetical order - const grp2 = $('<optgroup label="Group B">').appendTo('#from_id'); + const grp2 = $('<optgroup label="Group B">').appendTo("#from_id"); $('<option value="3">Zebra</option>').appendTo(grp2); - const grp1 = $('<optgroup label="Group A">').appendTo('#from_id'); + const grp1 = $('<optgroup label="Group A">').appendTo("#from_id"); $('<option value="1">Apple</option>').appendTo(grp1); $('<option value="2">Banana</option>').appendTo(grp1); - SelectBox.init('from_id'); - SelectBox.init('to_id'); + SelectBox.init("from_id"); + SelectBox.init("to_id"); // Move all items - SelectBox.move_all('from_id', 'to_id'); + SelectBox.move_all("from_id", "to_id"); // Verify to_id cache is sorted by group assert.equal(SelectBox.cache.to_id.length, 3); - assert.equal(SelectBox.cache.to_id[0].group, 'Group A'); - assert.equal(SelectBox.cache.to_id[0].text, 'Apple'); - assert.equal(SelectBox.cache.to_id[1].group, 'Group A'); - assert.equal(SelectBox.cache.to_id[1].text, 'Banana'); - assert.equal(SelectBox.cache.to_id[2].group, 'Group B'); - assert.equal(SelectBox.cache.to_id[2].text, 'Zebra'); + assert.equal(SelectBox.cache.to_id[0].group, "Group A"); + assert.equal(SelectBox.cache.to_id[0].text, "Apple"); + assert.equal(SelectBox.cache.to_id[1].group, "Group A"); + assert.equal(SelectBox.cache.to_id[1].text, "Banana"); + assert.equal(SelectBox.cache.to_id[2].group, "Group B"); + assert.equal(SelectBox.cache.to_id[2].text, "Zebra"); }); -QUnit.test('move_all without optgroups does not sort', function(assert) { +QUnit.test("move_all without optgroups does not sort", function (assert) { const $ = django.jQuery; - $('<select id="from_id"></select>').appendTo('#qunit-fixture'); - $('<select id="to_id"></select>').appendTo('#qunit-fixture'); + $('<select id="from_id"></select>').appendTo("#qunit-fixture"); + $('<select id="to_id"></select>').appendTo("#qunit-fixture"); // Add options without optgroups in non-alphabetical order - $('<option value="3">Zebra</option>').appendTo('#from_id'); - $('<option value="1">Apple</option>').appendTo('#from_id'); - $('<option value="2">Banana</option>').appendTo('#from_id'); + $('<option value="3">Zebra</option>').appendTo("#from_id"); + $('<option value="1">Apple</option>').appendTo("#from_id"); + $('<option value="2">Banana</option>').appendTo("#from_id"); - SelectBox.init('from_id'); - SelectBox.init('to_id'); + SelectBox.init("from_id"); + SelectBox.init("to_id"); // Move all items - SelectBox.move_all('from_id', 'to_id'); + SelectBox.move_all("from_id", "to_id"); // Verify to_id cache preserves original order (not sorted) assert.equal(SelectBox.cache.to_id.length, 3); - assert.equal(SelectBox.cache.to_id[0].text, 'Zebra'); - assert.equal(SelectBox.cache.to_id[1].text, 'Apple'); - assert.equal(SelectBox.cache.to_id[2].text, 'Banana'); + assert.equal(SelectBox.cache.to_id[0].text, "Zebra"); + assert.equal(SelectBox.cache.to_id[1].text, "Apple"); + assert.equal(SelectBox.cache.to_id[2].text, "Banana"); }); diff --git a/js_tests/admin/SelectFilter2.test.js b/js_tests/admin/SelectFilter2.test.js index 9a020d2c53..0d0283f9b6 100644 --- a/js_tests/admin/SelectFilter2.test.js +++ b/js_tests/admin/SelectFilter2.test.js @@ -1,174 +1,241 @@ /* global QUnit, SelectFilter */ -'use strict'; +"use strict"; -QUnit.module('admin.SelectFilter2'); +QUnit.module("admin.SelectFilter2"); -QUnit.test('init', function(assert) { +QUnit.test("init", function (assert) { const $ = django.jQuery; - $('<form id="test"></form>').appendTo('#qunit-fixture'); - $('<label for="id_id">Test</label>').appendTo('#test'); - $('<div class="helptext">This is helpful.</div>').appendTo('#test'); - $('<select id="id"><option value="0">A</option></select>').appendTo('#test'); - SelectFilter.init('id', 'things', 0); + $('<form id="test"></form>').appendTo("#qunit-fixture"); + $('<label for="id_id">Test</label>').appendTo("#test"); + $('<div class="helptext">This is helpful.</div>').appendTo("#test"); + $('<select id="id"><option value="0">A</option></select>').appendTo( + "#test", + ); + SelectFilter.init("id", "things", 0); assert.deepEqual( - Array.from($('#test')[0].children).map(child => child.tagName), - ["LABEL", "DIV", "DIV"] + Array.from($("#test")[0].children).map((child) => child.tagName), + ["LABEL", "DIV", "DIV"], + ); + assert.equal( + $(".helptext")[0].nextSibling.getAttribute("class"), + "selector", + ); + assert.equal( + $(".selector-available label").text().trim(), + "Available things", + ); + assert.equal($(".selector-available label").attr("id"), "id_from_label"); + assert.equal($(".selector-chosen label").text().trim(), "Chosen things"); + assert.equal($(".selector-chosen label").attr("id"), "id_to_label"); + assert.equal($(".selector-chosen select")[0].getAttribute("multiple"), ""); + assert.equal($(".selector-chooseall").text(), "Choose all things"); + assert.equal($(".selector-chooseall").prop("tagName"), "BUTTON"); + assert.equal($(".selector-add").text(), "Choose selected things"); + assert.equal($(".selector-add").prop("tagName"), "BUTTON"); + assert.equal($(".selector-remove").text(), "Remove selected things"); + assert.equal($(".selector-remove").prop("tagName"), "BUTTON"); + assert.equal($(".selector-clearall").text(), "Remove all things"); + assert.equal($(".selector-clearall").prop("tagName"), "BUTTON"); + assert.equal( + $(".selector-available .filtered").attr("aria-labelledby"), + "id_from_label", + ); + assert.equal( + $(".selector-available .filtered").attr("aria-describedby"), + "id_helptext id_choose_helptext", + ); + assert.equal( + $(".selector-available .selector-available-title label").text(), + "Available things ", + ); + assert.equal( + $(".selector-available .selector-available-title .helptext").text(), + 'Choose things by selecting them and then select the "Choose" arrow button.', + ); + assert.equal( + $(".selector-chosen .filtered").attr("aria-labelledby"), + "id_to_label", + ); + assert.equal( + $(".selector-chosen .filtered").attr("aria-describedby"), + "id_helptext id_remove_helptext", + ); + assert.equal( + $(".selector-chosen .selector-chosen-title label").text(), + "Chosen things ", + ); + assert.equal( + $(".selector-chosen .selector-chosen-title .helptext").text(), + 'Remove things by selecting them and then select the "Remove" arrow button.', + ); + assert.equal( + $(".selector-filter label .help-tooltip")[0].getAttribute("aria-label"), + "Type into this box to filter down the list of available things.", + ); + assert.equal( + $(".selector-filter label .help-tooltip")[1].getAttribute("aria-label"), + "Type into this box to filter down the list of selected things.", ); - assert.equal($('.helptext')[0].nextSibling.getAttribute("class"), "selector"); - assert.equal($('.selector-available label').text().trim(), "Available things"); - assert.equal($('.selector-available label').attr("id"), "id_from_label"); - assert.equal($('.selector-chosen label').text().trim(), "Chosen things"); - assert.equal($('.selector-chosen label').attr("id"), "id_to_label"); - assert.equal($('.selector-chosen select')[0].getAttribute('multiple'), ''); - assert.equal($('.selector-chooseall').text(), "Choose all things"); - assert.equal($('.selector-chooseall').prop("tagName"), "BUTTON"); - assert.equal($('.selector-add').text(), "Choose selected things"); - assert.equal($('.selector-add').prop("tagName"), "BUTTON"); - assert.equal($('.selector-remove').text(), "Remove selected things"); - assert.equal($('.selector-remove').prop("tagName"), "BUTTON"); - assert.equal($('.selector-clearall').text(), "Remove all things"); - assert.equal($('.selector-clearall').prop("tagName"), "BUTTON"); - assert.equal($('.selector-available .filtered').attr("aria-labelledby"), "id_from_label"); - assert.equal($('.selector-available .filtered').attr("aria-describedby"), "id_helptext id_choose_helptext"); - assert.equal($('.selector-available .selector-available-title label').text(), "Available things "); - assert.equal($('.selector-available .selector-available-title .helptext').text(), 'Choose things by selecting them and then select the "Choose" arrow button.'); - assert.equal($('.selector-chosen .filtered').attr("aria-labelledby"), "id_to_label"); - assert.equal($('.selector-chosen .filtered').attr("aria-describedby"), "id_helptext id_remove_helptext"); - assert.equal($('.selector-chosen .selector-chosen-title label').text(), "Chosen things "); - assert.equal($('.selector-chosen .selector-chosen-title .helptext').text(), 'Remove things by selecting them and then select the "Remove" arrow button.'); - assert.equal($('.selector-filter label .help-tooltip')[0].getAttribute("aria-label"), "Type into this box to filter down the list of available things."); - assert.equal($('.selector-filter label .help-tooltip')[1].getAttribute("aria-label"), "Type into this box to filter down the list of selected things."); assert.equal($('#test button:not([type="button"])').length, 0); }); -QUnit.test('filtering available options', function(assert) { +QUnit.test("filtering available options", function (assert) { const $ = django.jQuery; - $('<form><select multiple id="select"></select></form>').appendTo('#qunit-fixture'); - $('<option value="1" title="Red">Red</option>').appendTo('#select'); - $('<option value="2" title="Blue">Blue</option>').appendTo('#select'); - $('<option value="3" title="Green">Green</option>').appendTo('#select'); - SelectFilter.init('select', 'items', 0); - assert.equal($('#select_from option').length, 3); - assert.equal($('#select_to option').length, 0); + $('<form><select multiple id="select"></select></form>').appendTo( + "#qunit-fixture", + ); + $('<option value="1" title="Red">Red</option>').appendTo("#select"); + $('<option value="2" title="Blue">Blue</option>').appendTo("#select"); + $('<option value="3" title="Green">Green</option>').appendTo("#select"); + SelectFilter.init("select", "items", 0); + assert.equal($("#select_from option").length, 3); + assert.equal($("#select_to option").length, 0); const done = assert.async(); - const search_term = 'r'; - const event = new KeyboardEvent('keyup', {'key': search_term}); - $('#select_input').val(search_term); - SelectFilter.filter_key_up(event, 'select', '_from'); + const search_term = "r"; + const event = new KeyboardEvent("keyup", { key: search_term }); + $("#select_input").val(search_term); + SelectFilter.filter_key_up(event, "select", "_from"); setTimeout(() => { - assert.equal($('#select_from option').length, 2); - assert.equal($('#select_to option').length, 0); - assert.equal($('#select_from option')[0].value, '1'); - assert.equal($('#select_from option')[1].value, '3'); + assert.equal($("#select_from option").length, 2); + assert.equal($("#select_to option").length, 0); + assert.equal($("#select_from option")[0].value, "1"); + assert.equal($("#select_from option")[1].value, "3"); done(); }); }); -QUnit.test('filtering selected options', function(assert) { +QUnit.test("filtering selected options", function (assert) { const $ = django.jQuery; - $('<form><select multiple id="select"></select></form>').appendTo('#qunit-fixture'); - $('<option selected value="1" title="Red">Red</option>').appendTo('#select'); - $('<option selected value="2" title="Blue">Blue</option>').appendTo('#select'); - $('<option selected value="3" title="Green">Green</option>').appendTo('#select'); - SelectFilter.init('select', 'items', 0); - assert.equal($('#select_from option').length, 0); - assert.equal($('#select_to option').length, 3); + $('<form><select multiple id="select"></select></form>').appendTo( + "#qunit-fixture", + ); + $('<option selected value="1" title="Red">Red</option>').appendTo( + "#select", + ); + $('<option selected value="2" title="Blue">Blue</option>').appendTo( + "#select", + ); + $('<option selected value="3" title="Green">Green</option>').appendTo( + "#select", + ); + SelectFilter.init("select", "items", 0); + assert.equal($("#select_from option").length, 0); + assert.equal($("#select_to option").length, 3); const done = assert.async(); - const search_term = 'r'; - const event = new KeyboardEvent('keyup', {'key': search_term}); - $('#select_selected_input').val(search_term); - SelectFilter.filter_key_up(event, 'select', '_to', '_selected_input'); + const search_term = "r"; + const event = new KeyboardEvent("keyup", { key: search_term }); + $("#select_selected_input").val(search_term); + SelectFilter.filter_key_up(event, "select", "_to", "_selected_input"); setTimeout(() => { - assert.equal($('#select_from option').length, 0); - assert.equal($('#select_to option').length, 2); - assert.equal($('#select_to option')[0].value, '1'); - assert.equal($('#select_to option')[1].value, '3'); + assert.equal($("#select_from option").length, 0); + assert.equal($("#select_to option").length, 2); + assert.equal($("#select_to option")[0].value, "1"); + assert.equal($("#select_to option")[1].value, "3"); done(); }); }); -QUnit.test('filtering available options to nothing', function(assert) { +QUnit.test("filtering available options to nothing", function (assert) { const $ = django.jQuery; - $('<form><select multiple id="select"></select></form>').appendTo('#qunit-fixture'); - $('<option value="1" title="Red">Red</option>').appendTo('#select'); - $('<option value="2" title="Blue">Blue</option>').appendTo('#select'); - $('<option value="3" title="Green">Green</option>').appendTo('#select'); - SelectFilter.init('select', 'items', 0); - assert.equal($('#select_from option').length, 3); - assert.equal($('#select_to option').length, 0); + $('<form><select multiple id="select"></select></form>').appendTo( + "#qunit-fixture", + ); + $('<option value="1" title="Red">Red</option>').appendTo("#select"); + $('<option value="2" title="Blue">Blue</option>').appendTo("#select"); + $('<option value="3" title="Green">Green</option>').appendTo("#select"); + SelectFilter.init("select", "items", 0); + assert.equal($("#select_from option").length, 3); + assert.equal($("#select_to option").length, 0); const done = assert.async(); - const search_term = 'x'; - const event = new KeyboardEvent('keyup', {'key': search_term}); - $('#select_input').val(search_term); - SelectFilter.filter_key_up(event, 'select', '_from'); + const search_term = "x"; + const event = new KeyboardEvent("keyup", { key: search_term }); + $("#select_input").val(search_term); + SelectFilter.filter_key_up(event, "select", "_from"); setTimeout(() => { - assert.equal($('#select_from option').length, 0); - assert.equal($('#select_to option').length, 0); + assert.equal($("#select_from option").length, 0); + assert.equal($("#select_to option").length, 0); done(); }); }); -QUnit.test('filtering selected options to nothing', function(assert) { +QUnit.test("filtering selected options to nothing", function (assert) { const $ = django.jQuery; - $('<form><select multiple id="select"></select></form>').appendTo('#qunit-fixture'); - $('<option selected value="1" title="Red">Red</option>').appendTo('#select'); - $('<option selected value="2" title="Blue">Blue</option>').appendTo('#select'); - $('<option selected value="3" title="Green">Green</option>').appendTo('#select'); - SelectFilter.init('select', 'items', 0); - assert.equal($('#select_from option').length, 0); - assert.equal($('#select_to option').length, 3); + $('<form><select multiple id="select"></select></form>').appendTo( + "#qunit-fixture", + ); + $('<option selected value="1" title="Red">Red</option>').appendTo( + "#select", + ); + $('<option selected value="2" title="Blue">Blue</option>').appendTo( + "#select", + ); + $('<option selected value="3" title="Green">Green</option>').appendTo( + "#select", + ); + SelectFilter.init("select", "items", 0); + assert.equal($("#select_from option").length, 0); + assert.equal($("#select_to option").length, 3); const done = assert.async(); - const search_term = 'x'; - const event = new KeyboardEvent('keyup', {'key': search_term}); - $('#select_selected_input').val(search_term); - SelectFilter.filter_key_up(event, 'select', '_to', '_selected_input'); + const search_term = "x"; + const event = new KeyboardEvent("keyup", { key: search_term }); + $("#select_selected_input").val(search_term); + SelectFilter.filter_key_up(event, "select", "_to", "_selected_input"); setTimeout(() => { - assert.equal($('#select_from option').length, 0); - assert.equal($('#select_to option').length, 0); + assert.equal($("#select_from option").length, 0); + assert.equal($("#select_to option").length, 0); done(); }); }); -QUnit.test('selecting option', function(assert) { +QUnit.test("selecting option", function (assert) { const $ = django.jQuery; - $('<form><select multiple id="select"></select></form>').appendTo('#qunit-fixture'); - $('<option value="1" title="Red">Red</option>').appendTo('#select'); - $('<option value="2" title="Blue">Blue</option>').appendTo('#select'); - $('<option value="3" title="Green">Green</option>').appendTo('#select'); - SelectFilter.init('select', 'items', 0); - assert.equal($('#select_from option').length, 3); - assert.equal($('#select_to option').length, 0); + $('<form><select multiple id="select"></select></form>').appendTo( + "#qunit-fixture", + ); + $('<option value="1" title="Red">Red</option>').appendTo("#select"); + $('<option value="2" title="Blue">Blue</option>').appendTo("#select"); + $('<option value="3" title="Green">Green</option>').appendTo("#select"); + SelectFilter.init("select", "items", 0); + assert.equal($("#select_from option").length, 3); + assert.equal($("#select_to option").length, 0); // move to the right const done = assert.async(); - $('#select_from')[0].selectedIndex = 0; - const event = new KeyboardEvent('keydown', {'keyCode': 39, 'charCode': 39}); - SelectFilter.filter_key_down(event, 'select', '_from', '_to'); + $("#select_from")[0].selectedIndex = 0; + const event = new KeyboardEvent("keydown", { keyCode: 39, charCode: 39 }); + SelectFilter.filter_key_down(event, "select", "_from", "_to"); setTimeout(() => { - assert.equal($('#select_from option').length, 2); - assert.equal($('#select_to option').length, 1); - assert.equal($('#select_to option')[0].value, '1'); + assert.equal($("#select_from option").length, 2); + assert.equal($("#select_to option").length, 1); + assert.equal($("#select_to option")[0].value, "1"); done(); }); }); -QUnit.test('deselecting option', function(assert) { +QUnit.test("deselecting option", function (assert) { const $ = django.jQuery; - $('<form><select multiple id="select"></select></form>').appendTo('#qunit-fixture'); - $('<option selected value="1" title="Red">Red</option>').appendTo('#select'); - $('<option value="2" title="Blue">Blue</option>').appendTo('#select'); - $('<option value="3" title="Green">Green</option>').appendTo('#select'); - SelectFilter.init('select', 'items', 0); - assert.equal($('#select_from option').length, 2); - assert.equal($('#select_to option').length, 1); - assert.equal($('#select_to option')[0].value, '1'); + $('<form><select multiple id="select"></select></form>').appendTo( + "#qunit-fixture", + ); + $('<option selected value="1" title="Red">Red</option>').appendTo( + "#select", + ); + $('<option value="2" title="Blue">Blue</option>').appendTo("#select"); + $('<option value="3" title="Green">Green</option>').appendTo("#select"); + SelectFilter.init("select", "items", 0); + assert.equal($("#select_from option").length, 2); + assert.equal($("#select_to option").length, 1); + assert.equal($("#select_to option")[0].value, "1"); // move back to the left const done_left = assert.async(); - $('#select_to')[0].selectedIndex = 0; - const event_left = new KeyboardEvent('keydown', {'keyCode': 37, 'charCode': 37}); - SelectFilter.filter_key_down(event_left, 'select', '_to', '_from'); + $("#select_to")[0].selectedIndex = 0; + const event_left = new KeyboardEvent("keydown", { + keyCode: 37, + charCode: 37, + }); + SelectFilter.filter_key_down(event_left, "select", "_to", "_from"); setTimeout(() => { - assert.equal($('#select_from option').length, 3); - assert.equal($('#select_to option').length, 0); + assert.equal($("#select_from option").length, 3); + assert.equal($("#select_to option").length, 0); done_left(); }); }); diff --git a/js_tests/admin/URLify.test.js b/js_tests/admin/URLify.test.js index 471f2fbf05..36afd676c9 100644 --- a/js_tests/admin/URLify.test.js +++ b/js_tests/admin/URLify.test.js @@ -1,28 +1,28 @@ /* global QUnit, URLify */ -'use strict'; +"use strict"; -QUnit.module('admin.URLify'); +QUnit.module("admin.URLify"); -QUnit.test('empty string', function(assert) { - assert.strictEqual(URLify('', 8, true), ''); +QUnit.test("empty string", function (assert) { + assert.strictEqual(URLify("", 8, true), ""); }); -QUnit.test('preserve nonessential words', function(assert) { - assert.strictEqual(URLify('the D is silent', 15, true), 'the-d-is-silent'); +QUnit.test("preserve nonessential words", function (assert) { + assert.strictEqual(URLify("the D is silent", 15, true), "the-d-is-silent"); }); -QUnit.test('strip non-URL characters', function(assert) { - assert.strictEqual(URLify('D#silent@', 7, true), 'dsilent'); +QUnit.test("strip non-URL characters", function (assert) { + assert.strictEqual(URLify("D#silent@", 7, true), "dsilent"); }); -QUnit.test('merge adjacent whitespace', function(assert) { - assert.strictEqual(URLify('D silent', 8, true), 'd-silent'); +QUnit.test("merge adjacent whitespace", function (assert) { + assert.strictEqual(URLify("D silent", 8, true), "d-silent"); }); -QUnit.test('trim trailing hyphens', function(assert) { - assert.strictEqual(URLify('D silent always', 9, true), 'd-silent'); +QUnit.test("trim trailing hyphens", function (assert) { + assert.strictEqual(URLify("D silent always", 9, true), "d-silent"); }); -QUnit.test('non-ASCII string', function(assert) { - assert.strictEqual(URLify('Kaupa-miða', 255, true), 'kaupa-miða'); +QUnit.test("non-ASCII string", function (assert) { + assert.strictEqual(URLify("Kaupa-miða", 255, true), "kaupa-miða"); }); diff --git a/js_tests/admin/actions.test.js b/js_tests/admin/actions.test.js index 81364da681..cfe1b6a20a 100644 --- a/js_tests/admin/actions.test.js +++ b/js_tests/admin/actions.test.js @@ -1,21 +1,21 @@ /* global QUnit, Actions */ -'use strict'; +"use strict"; -QUnit.module('admin.actions', { - beforeEach: function() { +QUnit.module("admin.actions", { + beforeEach: function () { // Number of results shown on page - window._actions_icnt = '100'; + window._actions_icnt = "100"; const $ = django.jQuery; - $('#qunit-fixture').append($('#result-table').text()); + $("#qunit-fixture").append($("#result-table").text()); - Actions(document.querySelectorAll('tr input.action-select')); - } + Actions(document.querySelectorAll("tr input.action-select")); + }, }); -QUnit.test('check', function(assert) { +QUnit.test("check", function (assert) { const $ = django.jQuery; - assert.notOk($('.action-select').is(':checked')); - $('#action-toggle').click(); - assert.ok($('.action-select').is(':checked')); + assert.notOk($(".action-select").is(":checked")); + $("#action-toggle").click(); + assert.ok($(".action-select").is(":checked")); }); diff --git a/js_tests/admin/core.test.js b/js_tests/admin/core.test.js index c549ad99c9..8f59d120d6 100644 --- a/js_tests/admin/core.test.js +++ b/js_tests/admin/core.test.js @@ -1,97 +1,152 @@ /* global QUnit */ -'use strict'; +"use strict"; -QUnit.module('admin.core'); +QUnit.module("admin.core"); -QUnit.test('Date.getTwelveHours', function(assert) { - assert.equal(new Date(2011, 0, 1, 0, 0).getTwelveHours(), 12, '0:00'); - assert.equal(new Date(2011, 0, 1, 11, 0).getTwelveHours(), 11, '11:00'); - assert.equal(new Date(2011, 0, 1, 16, 0).getTwelveHours(), 4, '16:00'); +QUnit.test("Date.getTwelveHours", function (assert) { + assert.equal(new Date(2011, 0, 1, 0, 0).getTwelveHours(), 12, "0:00"); + assert.equal(new Date(2011, 0, 1, 11, 0).getTwelveHours(), 11, "11:00"); + assert.equal(new Date(2011, 0, 1, 16, 0).getTwelveHours(), 4, "16:00"); }); -QUnit.test('Date.getTwoDigitMonth', function(assert) { - assert.equal(new Date(2011, 0, 1).getTwoDigitMonth(), '01', 'jan 1'); - assert.equal(new Date(2011, 9, 1).getTwoDigitMonth(), '10', 'oct 1'); +QUnit.test("Date.getTwoDigitMonth", function (assert) { + assert.equal(new Date(2011, 0, 1).getTwoDigitMonth(), "01", "jan 1"); + assert.equal(new Date(2011, 9, 1).getTwoDigitMonth(), "10", "oct 1"); }); -QUnit.test('Date.getTwoDigitDate', function(assert) { - assert.equal(new Date(2011, 0, 1).getTwoDigitDate(), '01', 'jan 1'); - assert.equal(new Date(2011, 0, 15).getTwoDigitDate(), '15', 'jan 15'); +QUnit.test("Date.getTwoDigitDate", function (assert) { + assert.equal(new Date(2011, 0, 1).getTwoDigitDate(), "01", "jan 1"); + assert.equal(new Date(2011, 0, 15).getTwoDigitDate(), "15", "jan 15"); }); -QUnit.test('Date.getTwoDigitTwelveHour', function(assert) { - assert.equal(new Date(2011, 0, 1, 0, 0).getTwoDigitTwelveHour(), '12', '0:00'); - assert.equal(new Date(2011, 0, 1, 4, 0).getTwoDigitTwelveHour(), '04', '4:00'); - assert.equal(new Date(2011, 0, 1, 22, 0).getTwoDigitTwelveHour(), '10', '22:00'); +QUnit.test("Date.getTwoDigitTwelveHour", function (assert) { + assert.equal( + new Date(2011, 0, 1, 0, 0).getTwoDigitTwelveHour(), + "12", + "0:00", + ); + assert.equal( + new Date(2011, 0, 1, 4, 0).getTwoDigitTwelveHour(), + "04", + "4:00", + ); + assert.equal( + new Date(2011, 0, 1, 22, 0).getTwoDigitTwelveHour(), + "10", + "22:00", + ); }); -QUnit.test('Date.getTwoDigitHour', function(assert) { - assert.equal(new Date(2014, 6, 1, 9, 0).getTwoDigitHour(), '09', '9:00 am is 09'); - assert.equal(new Date(2014, 6, 1, 11, 0).getTwoDigitHour(), '11', '11:00 am is 11'); +QUnit.test("Date.getTwoDigitHour", function (assert) { + assert.equal( + new Date(2014, 6, 1, 9, 0).getTwoDigitHour(), + "09", + "9:00 am is 09", + ); + assert.equal( + new Date(2014, 6, 1, 11, 0).getTwoDigitHour(), + "11", + "11:00 am is 11", + ); }); -QUnit.test('Date.getTwoDigitMinute', function(assert) { - assert.equal(new Date(2014, 6, 1, 0, 5).getTwoDigitMinute(), '05', '12:05 am is 05'); - assert.equal(new Date(2014, 6, 1, 0, 15).getTwoDigitMinute(), '15', '12:15 am is 15'); +QUnit.test("Date.getTwoDigitMinute", function (assert) { + assert.equal( + new Date(2014, 6, 1, 0, 5).getTwoDigitMinute(), + "05", + "12:05 am is 05", + ); + assert.equal( + new Date(2014, 6, 1, 0, 15).getTwoDigitMinute(), + "15", + "12:15 am is 15", + ); }); -QUnit.test('Date.getTwoDigitSecond', function(assert) { - assert.equal(new Date(2014, 6, 1, 0, 0, 2).getTwoDigitSecond(), '02', '12:00:02 am is 02'); - assert.equal(new Date(2014, 6, 1, 0, 0, 20).getTwoDigitSecond(), '20', '12:00:20 am is 20'); +QUnit.test("Date.getTwoDigitSecond", function (assert) { + assert.equal( + new Date(2014, 6, 1, 0, 0, 2).getTwoDigitSecond(), + "02", + "12:00:02 am is 02", + ); + assert.equal( + new Date(2014, 6, 1, 0, 0, 20).getTwoDigitSecond(), + "20", + "12:00:20 am is 20", + ); }); -QUnit.test('Date.getAbbrevMonthName', function(assert) { - assert.equal(new Date(2020, 0, 26).getAbbrevMonthName(), 'Jan', 'jan 26'); - assert.equal(new Date(2020, 9, 26).getAbbrevMonthName(), 'Oct', 'oct 26'); +QUnit.test("Date.getAbbrevMonthName", function (assert) { + assert.equal(new Date(2020, 0, 26).getAbbrevMonthName(), "Jan", "jan 26"); + assert.equal(new Date(2020, 9, 26).getAbbrevMonthName(), "Oct", "oct 26"); }); -QUnit.test('Date.getFullMonthName', function(assert) { - assert.equal(new Date(2020, 0, 26).getFullMonthName(), 'January', 'jan 26'); - assert.equal(new Date(2020, 9, 26).getFullMonthName(), 'October', 'oct 26'); +QUnit.test("Date.getFullMonthName", function (assert) { + assert.equal(new Date(2020, 0, 26).getFullMonthName(), "January", "jan 26"); + assert.equal(new Date(2020, 9, 26).getFullMonthName(), "October", "oct 26"); }); -QUnit.test('Date.getAbbrevDayName', function(assert) { - assert.equal(new Date(2020, 0, 26).getAbbrevDayName(), 'Sun', 'jan 26 2020 is a Sunday'); - assert.equal(new Date(2020, 9, 26).getAbbrevDayName(), 'Mon', 'oct 26 2020 is a Monday'); +QUnit.test("Date.getAbbrevDayName", function (assert) { + assert.equal( + new Date(2020, 0, 26).getAbbrevDayName(), + "Sun", + "jan 26 2020 is a Sunday", + ); + assert.equal( + new Date(2020, 9, 26).getAbbrevDayName(), + "Mon", + "oct 26 2020 is a Monday", + ); }); -QUnit.test('Date.getFullDayName', function(assert) { - assert.equal(new Date(2020, 0, 26).getFullDayName(), 'Sunday', 'jan 26 2020 is a Sunday'); - assert.equal(new Date(2020, 9, 26).getFullDayName(), 'Monday', 'oct 26 2020 is a Monday'); +QUnit.test("Date.getFullDayName", function (assert) { + assert.equal( + new Date(2020, 0, 26).getFullDayName(), + "Sunday", + "jan 26 2020 is a Sunday", + ); + assert.equal( + new Date(2020, 9, 26).getFullDayName(), + "Monday", + "oct 26 2020 is a Monday", + ); }); -QUnit.test('Date.strftime', function(assert) { +QUnit.test("Date.strftime", function (assert) { const date = new Date(2014, 6, 1, 11, 0, 5); - assert.equal(date.strftime('%Y-%m-%d %H:%M:%S'), '2014-07-01 11:00:05'); - assert.equal(date.strftime('%B %d, %Y'), 'July 01, 2014'); - assert.equal(date.strftime('%b %d, %Y'), 'Jul 01, 2014'); - assert.equal(date.strftime('%a %d %m %y'), 'Tue 01 07 14'); - assert.equal(date.strftime('%A (day %w of week) %I %p'), 'Tuesday (day 02 of week) 11 AM'); + assert.equal(date.strftime("%Y-%m-%d %H:%M:%S"), "2014-07-01 11:00:05"); + assert.equal(date.strftime("%B %d, %Y"), "July 01, 2014"); + assert.equal(date.strftime("%b %d, %Y"), "Jul 01, 2014"); + assert.equal(date.strftime("%a %d %m %y"), "Tue 01 07 14"); + assert.equal( + date.strftime("%A (day %w of week) %I %p"), + "Tuesday (day 02 of week) 11 AM", + ); }); -QUnit.test('String.strptime', function(assert) { +QUnit.test("String.strptime", function (assert) { // Use UTC functions for extracting dates since the calendar uses them as // well. Month numbering starts with 0 (January). - const firstParsedDate = '1988-02-26'.strptime('%Y-%m-%d'); + const firstParsedDate = "1988-02-26".strptime("%Y-%m-%d"); assert.equal(firstParsedDate.getUTCDate(), 26); assert.equal(firstParsedDate.getUTCMonth(), 1); assert.equal(firstParsedDate.getUTCFullYear(), 1988); // A %y value in the range of [69, 99] is in the previous century. - const secondParsedDate = '26/02/88'.strptime('%d/%m/%y'); + const secondParsedDate = "26/02/88".strptime("%d/%m/%y"); assert.equal(secondParsedDate.getUTCDate(), 26); assert.equal(secondParsedDate.getUTCMonth(), 1); assert.equal(secondParsedDate.getUTCFullYear(), 1988); - const format = django.get_format('DATE_INPUT_FORMATS')[0]; - const thirdParsedDate = '1983-11-20'.strptime(format); + const format = django.get_format("DATE_INPUT_FORMATS")[0]; + const thirdParsedDate = "1983-11-20".strptime(format); assert.equal(thirdParsedDate.getUTCDate(), 20); assert.equal(thirdParsedDate.getUTCMonth(), 10); assert.equal(thirdParsedDate.getUTCFullYear(), 1983); // A %y value in the range of [00, 68] is in the current century. - const fourthParsedDate = '27/09/68'.strptime('%d/%m/%y'); + const fourthParsedDate = "27/09/68".strptime("%d/%m/%y"); assert.equal(fourthParsedDate.getUTCDate(), 27); assert.equal(fourthParsedDate.getUTCMonth(), 8); assert.equal(fourthParsedDate.getUTCFullYear(), 2068); @@ -103,8 +158,10 @@ QUnit.test('String.strptime', function(assert) { // Checking timezones from GMT+0100 to GMT+1200 for (let i = 1; i <= 12; i++) { - const tz = i > 9 ? '' + i : '0' + i; - const date = new Date(Date.parse('Feb 26, 1988 00:00:00 GMT+' + tz + '00')); + const tz = i > 9 ? "" + i : "0" + i; + const date = new Date( + Date.parse("Feb 26, 1988 00:00:00 GMT+" + tz + "00"), + ); assert.notEqual(date.getUTCDate(), 26); assert.equal(date.getUTCDate(), 25); assert.equal(date.getUTCMonth(), 1); @@ -113,8 +170,10 @@ QUnit.test('String.strptime', function(assert) { // Checking timezones from GMT+0000 to GMT-1100 for (let i = 0; i <= 11; i++) { - const tz = i > 9 ? '' + i : '0' + i; - const date = new Date(Date.parse('Feb 26, 1988 00:00:00 GMT-' + tz + '00')); + const tz = i > 9 ? "" + i : "0" + i; + const date = new Date( + Date.parse("Feb 26, 1988 00:00:00 GMT-" + tz + "00"), + ); assert.equal(date.getUTCDate(), 26); assert.equal(date.getUTCMonth(), 1); assert.equal(date.getUTCFullYear(), 1988); diff --git a/js_tests/admin/inlines.test.js b/js_tests/admin/inlines.test.js index ee8567dbf4..28de67cf65 100644 --- a/js_tests/admin/inlines.test.js +++ b/js_tests/admin/inlines.test.js @@ -1,174 +1,197 @@ /* global QUnit */ -'use strict'; +"use strict"; -QUnit.module('admin.inlines: tabular formsets', { - beforeEach: function() { +QUnit.module("admin.inlines: tabular formsets", { + beforeEach: function () { const $ = django.jQuery; - const that = this; - this.addText = 'Add another'; - $('#qunit-fixture').append($('#tabular-formset').text()); - this.table = $('table.inline'); - this.inlineRow = this.table.find('tr'); - this.inlineRow.tabularFormset('table.inline tr.form-row', { - prefix: 'first', - addText: that.addText, - deleteText: 'Remove' + this.addText = "Add another"; + + $("#qunit-fixture").append($("#tabular-formset").text()); + this.table = $("table.inline"); + this.inlineRow = this.table.find("tr"); + this.inlineRow.tabularFormset("table.inline tr.form-row", { + prefix: "first", + addText: this.addText, + deleteText: "Remove", }); - } + }, }); -QUnit.test('no forms', function(assert) { - assert.ok(this.inlineRow.hasClass('dynamic-first')); - assert.equal(this.table.find('.add-row a').text(), this.addText); +QUnit.test("no forms", function (assert) { + assert.ok(this.inlineRow.hasClass("dynamic-first")); + assert.equal(this.table.find(".add-row a").text(), this.addText); }); -QUnit.test('add form', function(assert) { - const addButton = this.table.find('.add-row a'); +QUnit.test("add form", function (assert) { + const addButton = this.table.find(".add-row a"); assert.equal(addButton.text(), this.addText); addButton.click(); - assert.ok(this.table.find('#first-1')); + assert.ok(this.table.find("#first-1")); }); -QUnit.test('added form has remove button', function(assert) { - const addButton = this.table.find('.add-row a'); +QUnit.test("added form has remove button", function (assert) { + const addButton = this.table.find(".add-row a"); assert.equal(addButton.text(), this.addText); addButton.click(); - assert.equal(this.table.find('#first-1 .inline-deletelink').length, 1); + assert.equal(this.table.find("#first-1 .inline-deletelink").length, 1); }); -QUnit.test('add/remove form events', function(assert) { +QUnit.test("add/remove form events", function (assert) { assert.expect(5); - const addButton = this.table.find('.add-row a'); - document.addEventListener('formset:added', (event) => { - assert.ok(true, 'event `formset:added` triggered'); - assert.equal(true, event.target.matches('#first-1')); - assert.equal(event.detail.formsetName, 'first'); - }, {once: true}); + const addButton = this.table.find(".add-row a"); + document.addEventListener( + "formset:added", + (event) => { + assert.ok(true, "event `formset:added` triggered"); + assert.equal(true, event.target.matches("#first-1")); + assert.equal(event.detail.formsetName, "first"); + }, + { once: true }, + ); addButton.click(); - const deleteLink = this.table.find('.inline-deletelink'); - document.addEventListener('formset:removed', (event) => { - assert.ok(true, 'event `formset:removed` triggered'); - assert.equal(event.detail.formsetName, 'first'); - }, {once: true}); + const deleteLink = this.table.find(".inline-deletelink"); + document.addEventListener( + "formset:removed", + (event) => { + assert.ok(true, "event `formset:removed` triggered"); + assert.equal(event.detail.formsetName, "first"); + }, + { once: true }, + ); deleteLink.click(); }); -QUnit.test('existing add button', function(assert) { +QUnit.test("existing add button", function (assert) { const $ = django.jQuery; - $('#qunit-fixture').empty(); // Clear the table added in beforeEach - $('#qunit-fixture').append($('#tabular-formset').text()); - this.table = $('table.inline'); - this.inlineRow = this.table.find('tr'); + $("#qunit-fixture").empty(); // Clear the table added in beforeEach + $("#qunit-fixture").append($("#tabular-formset").text()); + this.table = $("table.inline"); + this.inlineRow = this.table.find("tr"); this.table.append('<i class="add-button"></i>'); - const addButton = this.table.find('.add-button'); - this.inlineRow.tabularFormset('table.inline tr', { - prefix: 'first', - deleteText: 'Remove', - addButton: addButton + const addButton = this.table.find(".add-button"); + this.inlineRow.tabularFormset("table.inline tr", { + prefix: "first", + deleteText: "Remove", + addButton: addButton, }); - assert.equal(this.table.find('.add-row a').length, 0); + assert.equal(this.table.find(".add-row a").length, 0); addButton.click(); - assert.ok(this.table.find('#first-1')); + assert.ok(this.table.find("#first-1")); }); - -QUnit.module('admin.inlines: tabular formsets with validation errors', { - beforeEach: function() { +QUnit.module("admin.inlines: tabular formsets with validation errors", { + beforeEach: function () { const $ = django.jQuery; - $('#qunit-fixture').append($('#tabular-formset-with-validation-error').text()); - this.table = $('table.inline'); - this.inlineRows = this.table.find('tr.form-row'); - this.inlineRows.tabularFormset('table.inline tr.form-row', { - prefix: 'second' + $("#qunit-fixture").append( + $("#tabular-formset-with-validation-error").text(), + ); + this.table = $("table.inline"); + this.inlineRows = this.table.find("tr.form-row"); + this.inlineRows.tabularFormset("table.inline tr.form-row", { + prefix: "second", }); - } + }, }); -QUnit.test('first form has delete checkbox and no button', function(assert) { +QUnit.test("first form has delete checkbox and no button", function (assert) { const tr = this.inlineRows.slice(0, 1); - assert.ok(tr.hasClass('dynamic-second')); - assert.ok(tr.hasClass('has_original')); - assert.equal(tr.find('td.delete input').length, 1); - assert.equal(tr.find('td.delete .inline-deletelink').length, 0); + assert.ok(tr.hasClass("dynamic-second")); + assert.ok(tr.hasClass("has_original")); + assert.equal(tr.find("td.delete input").length, 1); + assert.equal(tr.find("td.delete .inline-deletelink").length, 0); }); -QUnit.test('dynamic form has remove button', function(assert) { +QUnit.test("dynamic form has remove button", function (assert) { const tr = this.inlineRows.slice(1, 2); - assert.ok(tr.hasClass('dynamic-second')); - assert.notOk(tr.hasClass('has_original')); - assert.equal(tr.find('.inline-deletelink').length, 1); + assert.ok(tr.hasClass("dynamic-second")); + assert.notOk(tr.hasClass("has_original")); + assert.equal(tr.find(".inline-deletelink").length, 1); }); -QUnit.test('dynamic template has nothing', function(assert) { +QUnit.test("dynamic template has nothing", function (assert) { const tr = this.inlineRows.slice(2, 3); - assert.ok(tr.hasClass('empty-form')); - assert.notOk(tr.hasClass('dynamic-second')); - assert.notOk(tr.hasClass('has_original')); - assert.equal(tr.find('td.delete')[0].innerHTML, ''); + assert.ok(tr.hasClass("empty-form")); + assert.notOk(tr.hasClass("dynamic-second")); + assert.notOk(tr.hasClass("has_original")); + assert.equal(tr.find("td.delete")[0].innerHTML, ""); }); -QUnit.test('removing a form-row also removed related row with non-field errors', function(assert) { - const $ = django.jQuery; - assert.ok(this.table.find('.row-form-errors').length); - const tr = this.inlineRows.slice(1, 2); - const trWithErrors = tr.prev(); - assert.ok(trWithErrors.hasClass('row-form-errors')); - const deleteLink = tr.find('a.inline-deletelink'); - deleteLink.trigger($.Event('click', {target: deleteLink})); - assert.notOk(this.table.find('.row-form-errors').length); -}); +QUnit.test( + "removing a form-row also removed related row with non-field errors", + function (assert) { + const $ = django.jQuery; + assert.ok(this.table.find(".row-form-errors").length); + const tr = this.inlineRows.slice(1, 2); + const trWithErrors = tr.prev(); + assert.ok(trWithErrors.hasClass("row-form-errors")); + const deleteLink = tr.find("a.inline-deletelink"); + deleteLink.trigger($.Event("click", { target: deleteLink })); + assert.notOk(this.table.find(".row-form-errors").length); + }, +); -QUnit.module('admin.inlines: tabular formsets with max_num', { - beforeEach: function() { +QUnit.module("admin.inlines: tabular formsets with max_num", { + beforeEach: function () { const $ = django.jQuery; - $('#qunit-fixture').append($('#tabular-formset-with-validation-error').text()); - this.table = $('table.inline'); - this.maxNum = $('input.id_second-MAX_NUM_FORMS'); + $("#qunit-fixture").append( + $("#tabular-formset-with-validation-error").text(), + ); + this.table = $("table.inline"); + this.maxNum = $("input.id_second-MAX_NUM_FORMS"); this.maxNum.val(2); - this.inlineRows = this.table.find('tr.form-row'); - this.inlineRows.tabularFormset('table.inline tr.form-row', { - prefix: 'second' + this.inlineRows = this.table.find("tr.form-row"); + this.inlineRows.tabularFormset("table.inline tr.form-row", { + prefix: "second", }); - } + }, }); -QUnit.test('does not show the add button if already at max_num', function(assert) { - const addButton = this.table.find('tr.add_row > td > a'); - assert.notOk(addButton.is(':visible')); -}); +QUnit.test( + "does not show the add button if already at max_num", + function (assert) { + const addButton = this.table.find("tr.add_row > td > a"); + assert.notOk(addButton.is(":visible")); + }, +); -QUnit.test('make addButton visible again', function(assert) { +QUnit.test("make addButton visible again", function (assert) { const $ = django.jQuery; - const addButton = this.table.find('tr.add_row > td > a'); - const removeButton = this.table.find('tr.form-row:first').find('a.inline-deletelink'); - removeButton.trigger($.Event( "click", { target: removeButton } )); - assert.notOk(addButton.is(':visible')); + const addButton = this.table.find("tr.add_row > td > a"); + const removeButton = this.table + .find("tr.form-row:first") + .find("a.inline-deletelink"); + removeButton.trigger($.Event("click", { target: removeButton })); + assert.notOk(addButton.is(":visible")); }); - -QUnit.module('admin.inlines: tabular formsets with min_num', { - beforeEach: function() { +QUnit.module("admin.inlines: tabular formsets with min_num", { + beforeEach: function () { const $ = django.jQuery; - $('#qunit-fixture').append($('#tabular-formset-with-validation-error').text()); - this.table = $('table.inline'); - this.minNum = $('input#id_second-MIN_NUM_FORMS'); + $("#qunit-fixture").append( + $("#tabular-formset-with-validation-error").text(), + ); + this.table = $("table.inline"); + this.minNum = $("input#id_second-MIN_NUM_FORMS"); this.minNum.val(2); - this.inlineRows = this.table.find('tr.form-row'); - this.inlineRows.tabularFormset('table.inline tr.form-row', { - prefix: 'second' + this.inlineRows = this.table.find("tr.form-row"); + this.inlineRows.tabularFormset("table.inline tr.form-row", { + prefix: "second", }); - } + }, }); -QUnit.test('does not show the remove buttons if already at min_num', function(assert) { - assert.notOk(this.table.find('.inline-deletelink:visible').length); -}); +QUnit.test( + "does not show the remove buttons if already at min_num", + function (assert) { + assert.notOk(this.table.find(".inline-deletelink:visible").length); + }, +); -QUnit.test('make removeButtons visible again', function(assert) { +QUnit.test("make removeButtons visible again", function (assert) { const $ = django.jQuery; - const addButton = this.table.find('tr.add-row > td > a'); - addButton.trigger($.Event( "click", { target: addButton } )); - assert.equal(this.table.find('.inline-deletelink:visible').length, 2); + const addButton = this.table.find("tr.add-row > td > a"); + addButton.trigger($.Event("click", { target: addButton })); + assert.equal(this.table.find(".inline-deletelink:visible").length, 2); }); diff --git a/js_tests/admin/jsi18n-mocks.test.js b/js_tests/admin/jsi18n-mocks.test.js index 6609c28e43..058bb3df25 100644 --- a/js_tests/admin/jsi18n-mocks.test.js +++ b/js_tests/admin/jsi18n-mocks.test.js @@ -1,29 +1,36 @@ -'use strict'; +"use strict"; { - const globals = this; - const django = globals.django; + const django = this.django; - django.pluralidx = function(count) { return (count === 1) ? 0 : 1; }; + django.pluralidx = function (count) { + return count === 1 ? 0 : 1; + }; /* gettext identity library */ - django.gettext = function(msgid) { return msgid; }; - django.ngettext = function(singular, plural, count) { - return (count === 1) ? singular : plural; + django.gettext = function (msgid) { + return msgid; + }; + django.ngettext = function (singular, plural, count) { + return count === 1 ? singular : plural; + }; + django.gettext_noop = function (msgid) { + return msgid; + }; + django.pgettext = function (context, msgid) { + return msgid; }; - django.gettext_noop = function(msgid) { return msgid; }; - django.pgettext = function(context, msgid) { return msgid; }; - django.npgettext = function(context, singular, plural, count) { - return (count === 1) ? singular : plural; + django.npgettext = function (context, singular, plural, count) { + return count === 1 ? singular : plural; }; - django.interpolate = function(fmt, obj, named) { + django.interpolate = function (fmt, obj, named) { if (named) { - return fmt.replace(/%\(\w+\)s/g, function(match) { + return fmt.replace(/%\(\w+\)s/g, function (match) { return String(obj[match.slice(2, -2)]); }); } else { - return fmt.replace(/%s/g, function(match) { + return fmt.replace(/%s/g, function (match) { return String(obj.shift()); }); } @@ -32,8 +39,8 @@ /* formatting library */ django.formats = { - "DATETIME_FORMAT": "N j, Y, P", - "DATETIME_INPUT_FORMATS": [ + DATETIME_FORMAT: "N j, Y, P", + DATETIME_INPUT_FORMATS: [ "%Y-%m-%d %H:%M:%S", "%Y-%m-%d %H:%M:%S.%f", "%Y-%m-%d %H:%M", @@ -45,33 +52,25 @@ "%m/%d/%y %H:%M:%S", "%m/%d/%y %H:%M:%S.%f", "%m/%d/%y %H:%M", - "%m/%d/%y" - ], - "DATE_FORMAT": "N j, Y", - "DATE_INPUT_FORMATS": [ - "%Y-%m-%d", - "%m/%d/%Y", - "%m/%d/%y" - ], - "DECIMAL_SEPARATOR": ".", - "FIRST_DAY_OF_WEEK": 0, - "MONTH_DAY_FORMAT": "F j", - "NUMBER_GROUPING": 3, - "SHORT_DATETIME_FORMAT": "m/d/Y P", - "SHORT_DATE_FORMAT": "m/d/Y", - "THOUSAND_SEPARATOR": ",", - "TIME_FORMAT": "P", - "TIME_INPUT_FORMATS": [ - "%H:%M:%S", - "%H:%M:%S.%f", - "%H:%M" + "%m/%d/%y", ], - "YEAR_MONTH_FORMAT": "F Y" + DATE_FORMAT: "N j, Y", + DATE_INPUT_FORMATS: ["%Y-%m-%d", "%m/%d/%Y", "%m/%d/%y"], + DECIMAL_SEPARATOR: ".", + FIRST_DAY_OF_WEEK: 0, + MONTH_DAY_FORMAT: "F j", + NUMBER_GROUPING: 3, + SHORT_DATETIME_FORMAT: "m/d/Y P", + SHORT_DATE_FORMAT: "m/d/Y", + THOUSAND_SEPARATOR: ",", + TIME_FORMAT: "P", + TIME_INPUT_FORMATS: ["%H:%M:%S", "%H:%M:%S.%f", "%H:%M"], + YEAR_MONTH_FORMAT: "F Y", }; - django.get_format = function(format_type) { + django.get_format = function (format_type) { const value = django.formats[format_type]; - if (typeof value === 'undefined') { + if (typeof value === "undefined") { return format_type; } else { return value; @@ -79,12 +78,12 @@ }; /* add to global namespace */ - globals.pluralidx = django.pluralidx; - globals.gettext = django.gettext; - globals.ngettext = django.ngettext; - globals.gettext_noop = django.gettext_noop; - globals.pgettext = django.pgettext; - globals.npgettext = django.npgettext; - globals.interpolate = django.interpolate; - globals.get_format = django.get_format; -}; + this.pluralidx = django.pluralidx; + this.gettext = django.gettext; + this.ngettext = django.ngettext; + this.gettext_noop = django.gettext_noop; + this.pgettext = django.pgettext; + this.npgettext = django.npgettext; + this.interpolate = django.interpolate; + this.get_format = django.get_format; +} diff --git a/js_tests/admin/navigation.test.js b/js_tests/admin/navigation.test.js index 0da50e757c..a53dd79747 100644 --- a/js_tests/admin/navigation.test.js +++ b/js_tests/admin/navigation.test.js @@ -1,24 +1,24 @@ /* global QUnit, initSidebarQuickFilter */ -'use strict'; +"use strict"; -QUnit.module('admin.sidebar: filter', { - beforeEach: function() { +QUnit.module("admin.sidebar: filter", { + beforeEach: function () { const $ = django.jQuery; - $('#qunit-fixture').append($('#nav-sidebar-filter').text()); - this.navSidebar = $('#nav-sidebar'); - this.navFilter = $('#nav-filter'); + $("#qunit-fixture").append($("#nav-sidebar-filter").text()); + this.navSidebar = $("#nav-sidebar"); + this.navFilter = $("#nav-filter"); initSidebarQuickFilter(); - } + }, }); -QUnit.test('filter by a model name', function(assert) { - assert.equal(this.navSidebar.find('th[scope=row] a').length, 2); +QUnit.test("filter by a model name", function (assert) { + assert.equal(this.navSidebar.find("th[scope=row] a").length, 2); - this.navFilter.val('us'); // Matches 'users'. - this.navFilter[0].dispatchEvent(new Event('change')); + this.navFilter.val("us"); // Matches 'users'. + this.navFilter[0].dispatchEvent(new Event("change")); assert.equal(this.navSidebar.find('tr[class^="model-"]:visible').length, 1); - this.navFilter.val('nonexistent'); - this.navFilter[0].dispatchEvent(new Event('change')); + this.navFilter.val("nonexistent"); + this.navFilter[0].dispatchEvent(new Event("change")); assert.equal(this.navSidebar.find('tr[class^="model-"]:visible').length, 0); }); diff --git a/js_tests/gis/mapwidget.test.js b/js_tests/gis/mapwidget.test.js index 4f2f3bb91c..838cf22219 100644 --- a/js_tests/gis/mapwidget.test.js +++ b/js_tests/gis/mapwidget.test.js @@ -1,157 +1,232 @@ /* global QUnit, MapWidget, ol */ -'use strict'; +"use strict"; -QUnit.module('gis.OLMapWidget'); +QUnit.module("gis.OLMapWidget"); -QUnit.test('MapWidget.featureAdded', function(assert) { - const options = {id: 'id_point', map_id: 'id_point_map', geom_name: 'Point'}; +QUnit.test("MapWidget.featureAdded", function (assert) { + const options = { + id: "id_point", + map_id: "id_point_map", + geom_name: "Point", + }; const widget = new MapWidget(options); assert.equal(widget.featureCollection.getLength(), 1); widget.serializeFeatures(); assert.equal( - document.getElementById('id_point').value, + document.getElementById("id_point").value, '{"type":"Point","coordinates":[7.8177,47.397]}', - 'Point added to vector layer' + "Point added to vector layer", ); }); -QUnit.test('MapWidget.map_srid', function(assert) { - const options = {id: 'id_point', map_id: 'id_point_map', geom_name: 'Point'}; +QUnit.test("MapWidget.map_srid", function (assert) { + const options = { + id: "id_point", + map_id: "id_point_map", + geom_name: "Point", + }; const widget = new MapWidget(options); - assert.equal(widget.map.getView().getProjection().getCode(), 'EPSG:3857', 'SRID 3857'); + assert.equal( + widget.map.getView().getProjection().getCode(), + "EPSG:3857", + "SRID 3857", + ); }); -QUnit.test('MapWidget.defaultCenter', function(assert) { - const options = {id: 'id_point', map_id: 'id_point_map', geom_name: 'Point'}; +QUnit.test("MapWidget.defaultCenter", function (assert) { + const options = { + id: "id_point", + map_id: "id_point_map", + geom_name: "Point", + }; let widget = new MapWidget(options); - assert.equal(widget.defaultCenter().toString(), '0,0', 'Default center at 0, 0'); + assert.equal( + widget.defaultCenter().toString(), + "0,0", + "Default center at 0, 0", + ); options.default_lat = 47.08; options.default_lon = 6.81; widget = new MapWidget(options); assert.equal( widget.defaultCenter().toString(), - '6.81,47.08', - 'Default center at 6.81, 47.08' + "6.81,47.08", + "Default center at 6.81, 47.08", ); assert.equal(Math.round(widget.map.getView().getZoom()), 17); }); -QUnit.test('MapWidget.interactions', function(assert) { - const options = {id: 'id_point', map_id: 'id_point_map', geom_name: 'Point'}; +QUnit.test("MapWidget.interactions", function (assert) { + const options = { + id: "id_point", + map_id: "id_point_map", + geom_name: "Point", + }; const widget = new MapWidget(options); assert.equal(Object.keys(widget.interactions).length, 2); - assert.equal(widget.interactions.draw.getActive(), false, "Draw is inactive with an existing point"); - assert.equal(widget.interactions.modify.getActive(), true, "Modify is active with an existing point"); + assert.equal( + widget.interactions.draw.getActive(), + false, + "Draw is inactive with an existing point", + ); + assert.equal( + widget.interactions.modify.getActive(), + true, + "Modify is active with an existing point", + ); }); -QUnit.test('MapWidget.clearFeatures', function(assert) { - const options = {id: 'id_point', map_id: 'id_point_map', geom_name: 'Point'}; +QUnit.test("MapWidget.clearFeatures", function (assert) { + const options = { + id: "id_point", + map_id: "id_point_map", + geom_name: "Point", + }; const widget = new MapWidget(options); - const initial_value = document.getElementById('id_point').value; + const initial_value = document.getElementById("id_point").value; widget.clearFeatures(); - assert.equal(document.getElementById('id_point').value, ""); - document.getElementById('id_point').value = initial_value; + assert.equal(document.getElementById("id_point").value, ""); + document.getElementById("id_point").value = initial_value; }); -QUnit.test('MapWidget.multipolygon', function(assert) { - const options = {id: 'id_multipolygon', map_id: 'id_multipolygon_map', geom_name: 'MultiPolygon'}; +QUnit.test("MapWidget.multipolygon", function (assert) { + const options = { + id: "id_multipolygon", + map_id: "id_multipolygon_map", + geom_name: "MultiPolygon", + }; const widget = new MapWidget(options); assert.ok(widget.options.is_collection); - assert.equal(widget.interactions.draw.getActive(), true, "Draw is active with no existing content"); + assert.equal( + widget.interactions.draw.getActive(), + true, + "Draw is active with no existing content", + ); }); -QUnit.test('MapWidget.IsCollection', function(assert) { - const options = {id: 'id_point', map_id: 'id_point_map', geom_name: 'Point'}; +QUnit.test("MapWidget.IsCollection", function (assert) { + const options = { + id: "id_point", + map_id: "id_point_map", + geom_name: "Point", + }; let widget = new MapWidget(options); assert.notOk(widget.options.is_collection); // Empty the default initial Point - document.getElementById('id_point').value = ""; + document.getElementById("id_point").value = ""; - options.geom_name = 'Polygon'; + options.geom_name = "Polygon"; widget = new MapWidget(options); assert.notOk(widget.options.is_collection); - options.geom_name = 'LineString'; + options.geom_name = "LineString"; widget = new MapWidget(options); assert.notOk(widget.options.is_collection); - options.geom_name = 'MultiPoint'; + options.geom_name = "MultiPoint"; widget = new MapWidget(options); assert.ok(widget.options.is_collection); - options.geom_name = 'MultiPolygon'; + options.geom_name = "MultiPolygon"; widget = new MapWidget(options); assert.ok(widget.options.is_collection); - options.geom_name = 'MultiLineString'; + options.geom_name = "MultiLineString"; widget = new MapWidget(options); assert.ok(widget.options.is_collection); - options.geom_name = 'GeometryCollection'; + options.geom_name = "GeometryCollection"; widget = new MapWidget(options); assert.ok(widget.options.is_collection); }); -QUnit.test('MapWidget.layerBuilder.osm returns OSM layer', function(assert) { +QUnit.test("MapWidget.layerBuilder.osm returns OSM layer", function (assert) { const layer = MapWidget.layerBuilder.osm(); - assert.ok(layer instanceof ol.layer.Tile, 'Layer is Tile'); - assert.ok(layer.getSource() instanceof ol.source.OSM, 'Source is OSM'); + assert.ok(layer instanceof ol.layer.Tile, "Layer is Tile"); + assert.ok(layer.getSource() instanceof ol.source.OSM, "Source is OSM"); }); -QUnit.test('MapWidget.layerBuilder.nasaWorldview returns XYZ layer', function(assert) { - const layer = MapWidget.layerBuilder.nasaWorldview(); - assert.ok(layer instanceof ol.layer.Tile, 'Layer is Tile'); - assert.ok(layer.getSource() instanceof ol.source.XYZ, 'Source is XYZ'); - assert.ok(layer.getSource().getUrls()[0].includes('earthdata.nasa.gov'), 'URL is NASA-hosted'); -}); +QUnit.test( + "MapWidget.layerBuilder.nasaWorldview returns XYZ layer", + function (assert) { + const layer = MapWidget.layerBuilder.nasaWorldview(); + assert.ok(layer instanceof ol.layer.Tile, "Layer is Tile"); + assert.ok(layer.getSource() instanceof ol.source.XYZ, "Source is XYZ"); + assert.ok( + layer.getSource().getUrls()[0].includes("earthdata.nasa.gov"), + "URL is NASA-hosted", + ); + }, +); -QUnit.test('MapWidget uses default OSM base layer when none specified', function(assert) { - const widget = new MapWidget({ - id: 'id_point', - map_id: 'id_point_map', - geom_name: 'Point' - }); - assert.ok(widget.baseLayer.getSource() instanceof ol.source.OSM, 'Default base layer is OSM'); -}); +QUnit.test( + "MapWidget uses default OSM base layer when none specified", + function (assert) { + const widget = new MapWidget({ + id: "id_point", + map_id: "id_point_map", + geom_name: "Point", + }); + assert.ok( + widget.baseLayer.getSource() instanceof ol.source.OSM, + "Default base layer is OSM", + ); + }, +); -QUnit.test('MapWidget uses named base layer from layerBuilder', function(assert) { - const widget = new MapWidget({ - id: 'id_point', - map_id: 'id_point_map', - geom_name: 'Point', - base_layer: 'nasaWorldview' - }); - assert.ok(widget.baseLayer.getSource() instanceof ol.source.XYZ, 'Uses named base layer from builder'); -}); +QUnit.test( + "MapWidget uses named base layer from layerBuilder", + function (assert) { + const widget = new MapWidget({ + id: "id_point", + map_id: "id_point_map", + geom_name: "Point", + base_layer: "nasaWorldview", + }); + assert.ok( + widget.baseLayer.getSource() instanceof ol.source.XYZ, + "Uses named base layer from builder", + ); + }, +); -QUnit.test('MapWidget uses passed-in base layer object directly', function(assert) { - const customLayer = new ol.layer.Tile({source: new ol.source.OSM()}); - const widget = new MapWidget({ - id: 'id_point', - map_id: 'id_point_map', - geom_name: 'Point', - base_layer: customLayer - }); - assert.strictEqual(widget.baseLayer, customLayer, 'Uses provided layer object'); -}); +QUnit.test( + "MapWidget uses passed-in base layer object directly", + function (assert) { + const customLayer = new ol.layer.Tile({ source: new ol.source.OSM() }); + const widget = new MapWidget({ + id: "id_point", + map_id: "id_point_map", + geom_name: "Point", + base_layer: customLayer, + }); + assert.strictEqual( + widget.baseLayer, + customLayer, + "Uses provided layer object", + ); + }, +); -QUnit.test('initMapWidgetInSection initializes widgets and skips __prefix__', function(assert) { - const wrapper1 = document.createElement('div'); - wrapper1.className = 'dj_map_wrapper'; - wrapper1.id = 'id_point_map_wrapper'; - wrapper1.innerHTML = ` +QUnit.test( + "initMapWidgetInSection initializes widgets and skips __prefix__", + function (assert) { + const wrapper1 = document.createElement("div"); + wrapper1.className = "dj_map_wrapper"; + wrapper1.id = "id_point_map_wrapper"; + wrapper1.innerHTML = ` <textarea id="id_point"></textarea> <div class="dj_map" id="id_point_map"></div> <script type="application/json" id="id_point_mapwidget_options"> { "geom_name": "Point" } </script> `; - document.body.appendChild(wrapper1); + document.body.appendChild(wrapper1); - const wrapper2 = document.createElement('div'); - wrapper2.className = 'dj_map_wrapper'; - wrapper2.id = 'form-__prefix__-map_wrapper'; - wrapper2.innerHTML = ` + const wrapper2 = document.createElement("div"); + wrapper2.className = "dj_map_wrapper"; + wrapper2.id = "form-__prefix__-map_wrapper"; + wrapper2.innerHTML = ` <textarea id="id_fake"></textarea> <div class="dj_map" id="id_fake_map"></div> <script type="application/json" id="id_fake_mapwidget_options"> @@ -159,16 +234,25 @@ QUnit.test('initMapWidgetInSection initializes widgets and skips __prefix__', fu </script> `; - document.body.appendChild(wrapper2); + document.body.appendChild(wrapper2); - const maps = window.initMapWidgetInSection(document); + const maps = window.initMapWidgetInSection(document); - assert.equal(maps.length, 1, 'Only one map widget is initialized'); - assert.ok(maps[0] instanceof MapWidget, 'Map is instance of MapWidget'); - assert.equal(maps[0].options.id, 'id_point', 'Correct widget was initialized'); - assert.equal(maps[0].options.map_id, 'id_point_map', 'Map ID is correct'); + assert.equal(maps.length, 1, "Only one map widget is initialized"); + assert.ok(maps[0] instanceof MapWidget, "Map is instance of MapWidget"); + assert.equal( + maps[0].options.id, + "id_point", + "Correct widget was initialized", + ); + assert.equal( + maps[0].options.map_id, + "id_point_map", + "Map ID is correct", + ); - // Clean up - wrapper1.remove(); - wrapper2.remove(); -}); + // Clean up + wrapper1.remove(); + wrapper2.remove(); + }, +); |
