RelatedObjectLookups.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /*global SelectBox, interpolate*/
  2. // Handles related-objects functionality: lookup link for raw_id_fields
  3. // and Add Another links.
  4. (function($) {
  5. 'use strict';
  6. // IE doesn't accept periods or dashes in the window name, but the element IDs
  7. // we use to generate popup window names may contain them, therefore we map them
  8. // to allowed characters in a reversible way so that we can locate the correct
  9. // element when the popup window is dismissed.
  10. function id_to_windowname(text) {
  11. text = text.replace(/\./g, '__dot__');
  12. text = text.replace(/\-/g, '__dash__');
  13. return text;
  14. }
  15. function windowname_to_id(text) {
  16. text = text.replace(/__dot__/g, '.');
  17. text = text.replace(/__dash__/g, '-');
  18. return text;
  19. }
  20. function showAdminPopup(triggeringLink, name_regexp, add_popup) {
  21. var name = triggeringLink.id.replace(name_regexp, '');
  22. name = id_to_windowname(name);
  23. var href = triggeringLink.href;
  24. if (add_popup) {
  25. if (href.indexOf('?') === -1) {
  26. href += '?_popup=1';
  27. } else {
  28. href += '&_popup=1';
  29. }
  30. }
  31. var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');
  32. win.focus();
  33. return false;
  34. }
  35. function showRelatedObjectLookupPopup(triggeringLink) {
  36. return showAdminPopup(triggeringLink, /^lookup_/, true);
  37. }
  38. function dismissRelatedLookupPopup(win, chosenId) {
  39. var name = windowname_to_id(win.name);
  40. var elem = document.getElementById(name);
  41. if (elem.className.indexOf('vManyToManyRawIdAdminField') !== -1 && elem.value) {
  42. elem.value += ',' + chosenId;
  43. } else {
  44. document.getElementById(name).value = chosenId;
  45. }
  46. win.close();
  47. }
  48. function showRelatedObjectPopup(triggeringLink) {
  49. return showAdminPopup(triggeringLink, /^(change|add|delete)_/, false);
  50. }
  51. function updateRelatedObjectLinks(triggeringLink) {
  52. var $this = $(triggeringLink);
  53. var siblings = $this.nextAll('.view-related, .change-related, .delete-related');
  54. if (!siblings.length) {
  55. return;
  56. }
  57. var value = $this.val();
  58. if (value) {
  59. siblings.each(function() {
  60. var elm = $(this);
  61. elm.attr('href', elm.attr('data-href-template').replace('__fk__', value));
  62. });
  63. } else {
  64. siblings.removeAttr('href');
  65. }
  66. }
  67. function dismissAddRelatedObjectPopup(win, newId, newRepr) {
  68. var name = windowname_to_id(win.name);
  69. var elem = document.getElementById(name);
  70. if (elem) {
  71. var elemName = elem.nodeName.toUpperCase();
  72. if (elemName === 'SELECT') {
  73. elem.options[elem.options.length] = new Option(newRepr, newId, true, true);
  74. } else if (elemName === 'INPUT') {
  75. if (elem.className.indexOf('vManyToManyRawIdAdminField') !== -1 && elem.value) {
  76. elem.value += ',' + newId;
  77. } else {
  78. elem.value = newId;
  79. }
  80. }
  81. // Trigger a change event to update related links if required.
  82. $(elem).trigger('change');
  83. } else {
  84. var toId = name + "_to";
  85. var o = new Option(newRepr, newId);
  86. SelectBox.add_to_cache(toId, o);
  87. SelectBox.redisplay(toId);
  88. }
  89. win.close();
  90. }
  91. function dismissChangeRelatedObjectPopup(win, objId, newRepr, newId) {
  92. var id = windowname_to_id(win.name).replace(/^edit_/, '');
  93. var selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]);
  94. var selects = $(selectsSelector);
  95. selects.find('option').each(function() {
  96. if (this.value === objId) {
  97. this.textContent = newRepr;
  98. this.value = newId;
  99. }
  100. });
  101. selects.next().find('.select2-selection__rendered').each(function() {
  102. // The element can have a clear button as a child.
  103. // Use the lastChild to modify only the displayed value.
  104. this.lastChild.textContent = newRepr;
  105. this.title = newRepr;
  106. });
  107. win.close();
  108. }
  109. function dismissDeleteRelatedObjectPopup(win, objId) {
  110. var id = windowname_to_id(win.name).replace(/^delete_/, '');
  111. var selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]);
  112. var selects = $(selectsSelector);
  113. selects.find('option').each(function() {
  114. if (this.value === objId) {
  115. $(this).remove();
  116. }
  117. }).trigger('change');
  118. win.close();
  119. }
  120. // Global for testing purposes
  121. window.id_to_windowname = id_to_windowname;
  122. window.windowname_to_id = windowname_to_id;
  123. window.showRelatedObjectLookupPopup = showRelatedObjectLookupPopup;
  124. window.dismissRelatedLookupPopup = dismissRelatedLookupPopup;
  125. window.showRelatedObjectPopup = showRelatedObjectPopup;
  126. window.updateRelatedObjectLinks = updateRelatedObjectLinks;
  127. window.dismissAddRelatedObjectPopup = dismissAddRelatedObjectPopup;
  128. window.dismissChangeRelatedObjectPopup = dismissChangeRelatedObjectPopup;
  129. window.dismissDeleteRelatedObjectPopup = dismissDeleteRelatedObjectPopup;
  130. // Kept for backward compatibility
  131. window.showAddAnotherPopup = showRelatedObjectPopup;
  132. window.dismissAddAnotherPopup = dismissAddRelatedObjectPopup;
  133. $(document).ready(function() {
  134. $("a[data-popup-opener]").on('click', function(event) {
  135. event.preventDefault();
  136. opener.dismissRelatedLookupPopup(window, $(this).data("popup-opener"));
  137. });
  138. $('body').on('click', '.related-widget-wrapper-link', function(e) {
  139. e.preventDefault();
  140. if (this.href) {
  141. var event = $.Event('django:show-related', {href: this.href});
  142. $(this).trigger(event);
  143. if (!event.isDefaultPrevented()) {
  144. showRelatedObjectPopup(this);
  145. }
  146. }
  147. });
  148. $('body').on('change', '.related-widget-wrapper select', function(e) {
  149. var event = $.Event('django:update-related');
  150. $(this).trigger(event);
  151. if (!event.isDefaultPrevented()) {
  152. updateRelatedObjectLinks(this);
  153. }
  154. });
  155. $('.related-widget-wrapper select').trigger('change');
  156. $('body').on('click', '.related-lookup', function(e) {
  157. e.preventDefault();
  158. var event = $.Event('django:lookup-related');
  159. $(this).trigger(event);
  160. if (!event.isDefaultPrevented()) {
  161. showRelatedObjectLookupPopup(this);
  162. }
  163. });
  164. });
  165. })(django.jQuery);