123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- /*global SelectBox, interpolate*/
- // Handles related-objects functionality: lookup link for raw_id_fields
- // and Add Another links.
- 'use strict';
- {
- const $ = django.jQuery;
- let popupIndex = 0;
- const relatedWindows = [];
- function dismissChildPopups() {
- relatedWindows.forEach(function(win) {
- if(!win.closed) {
- win.dismissChildPopups();
- win.close();
- }
- });
- }
- function setPopupIndex() {
- if(document.getElementsByName("_popup").length > 0) {
- const index = window.name.lastIndexOf("__") + 2;
- popupIndex = parseInt(window.name.substring(index));
- } else {
- popupIndex = 0;
- }
- }
- function addPopupIndex(name) {
- name = name + "__" + (popupIndex + 1);
- return name;
- }
- function removePopupIndex(name) {
- name = name.replace(new RegExp("__" + (popupIndex + 1) + "$"), '');
- return name;
- }
- function showAdminPopup(triggeringLink, name_regexp, add_popup) {
- const name = addPopupIndex(triggeringLink.id.replace(name_regexp, ''));
- const href = new URL(triggeringLink.href);
- if (add_popup) {
- href.searchParams.set('_popup', 1);
- }
- const win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');
- relatedWindows.push(win);
- win.focus();
- return false;
- }
- function showRelatedObjectLookupPopup(triggeringLink) {
- return showAdminPopup(triggeringLink, /^lookup_/, true);
- }
- function dismissRelatedLookupPopup(win, chosenId) {
- const name = removePopupIndex(win.name);
- const elem = document.getElementById(name);
- if (elem.classList.contains('vManyToManyRawIdAdminField') && elem.value) {
- elem.value += ',' + chosenId;
- } else {
- document.getElementById(name).value = chosenId;
- }
- const index = relatedWindows.indexOf(win);
- if (index > -1) {
- relatedWindows.splice(index, 1);
- }
- win.close();
- }
- function showRelatedObjectPopup(triggeringLink) {
- return showAdminPopup(triggeringLink, /^(change|add|delete)_/, false);
- }
- function updateRelatedObjectLinks(triggeringLink) {
- const $this = $(triggeringLink);
- const siblings = $this.nextAll('.view-related, .change-related, .delete-related');
- if (!siblings.length) {
- return;
- }
- const value = $this.val();
- if (value) {
- siblings.each(function() {
- const elm = $(this);
- elm.attr('href', elm.attr('data-href-template').replace('__fk__', value));
- });
- } else {
- siblings.removeAttr('href');
- }
- }
- function updateRelatedSelectsOptions(currentSelect, win, objId, newRepr, newId) {
- // 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.
- 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)];
- // Exclude autocomplete selects.
- const selectsRelated = document.querySelectorAll(`[data-model-ref="${modelName}"] select:not(.admin-autocomplete)`);
- selectsRelated.forEach(function(select) {
- if (currentSelect === select) {
- return;
- }
- let option = select.querySelector(`option[value="${objId}"]`);
- if (!option) {
- option = new Option(newRepr, newId);
- select.options.add(option);
- return;
- }
- option.textContent = newRepr;
- option.value = newId;
- });
- }
- function dismissAddRelatedObjectPopup(win, newId, newRepr) {
- const name = removePopupIndex(win.name);
- 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);
- updateRelatedSelectsOptions(elem, win, null, newRepr, 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');
- } else {
- const toId = name + "_to";
- const o = new Option(newRepr, newId);
- SelectBox.add_to_cache(toId, o);
- SelectBox.redisplay(toId);
- }
- const index = relatedWindows.indexOf(win);
- if (index > -1) {
- relatedWindows.splice(index, 1);
- }
- win.close();
- }
- 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 selects = $(selectsSelector);
- 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;
- });
- const index = relatedWindows.indexOf(win);
- if (index > -1) {
- relatedWindows.splice(index, 1);
- }
- win.close();
- }
- function dismissDeleteRelatedObjectPopup(win, objId) {
- 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');
- const index = relatedWindows.indexOf(win);
- if (index > -1) {
- relatedWindows.splice(index, 1);
- }
- win.close();
- }
- window.showRelatedObjectLookupPopup = showRelatedObjectLookupPopup;
- window.dismissRelatedLookupPopup = dismissRelatedLookupPopup;
- window.showRelatedObjectPopup = showRelatedObjectPopup;
- window.updateRelatedObjectLinks = updateRelatedObjectLinks;
- window.dismissAddRelatedObjectPopup = dismissAddRelatedObjectPopup;
- window.dismissChangeRelatedObjectPopup = dismissChangeRelatedObjectPopup;
- window.dismissDeleteRelatedObjectPopup = dismissDeleteRelatedObjectPopup;
- window.dismissChildPopups = dismissChildPopups;
- // Kept for backward compatibility
- window.showAddAnotherPopup = showRelatedObjectPopup;
- window.dismissAddAnotherPopup = dismissAddRelatedObjectPopup;
- window.addEventListener('unload', function(evt) {
- window.dismissChildPopups();
- });
- $(document).ready(function() {
- setPopupIndex();
- $("a[data-popup-opener]").on('click', function(event) {
- event.preventDefault();
- 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('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) {
- e.preventDefault();
- const event = $.Event('django:lookup-related');
- $(this).trigger(event);
- if (!event.isDefaultPrevented()) {
- showRelatedObjectLookupPopup(this);
- }
- });
- });
- }
|