Ei kuvausta

actions.js 7.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /*global gettext, interpolate, ngettext*/
  2. 'use strict';
  3. {
  4. function show(selector) {
  5. document.querySelectorAll(selector).forEach(function(el) {
  6. el.classList.remove('hidden');
  7. });
  8. }
  9. function hide(selector) {
  10. document.querySelectorAll(selector).forEach(function(el) {
  11. el.classList.add('hidden');
  12. });
  13. }
  14. function showQuestion(options) {
  15. hide(options.acrossClears);
  16. show(options.acrossQuestions);
  17. hide(options.allContainer);
  18. }
  19. function showClear(options) {
  20. show(options.acrossClears);
  21. hide(options.acrossQuestions);
  22. document.querySelector(options.actionContainer).classList.remove(options.selectedClass);
  23. show(options.allContainer);
  24. hide(options.counterContainer);
  25. }
  26. function reset(options) {
  27. hide(options.acrossClears);
  28. hide(options.acrossQuestions);
  29. hide(options.allContainer);
  30. show(options.counterContainer);
  31. }
  32. function clearAcross(options) {
  33. reset(options);
  34. document.querySelector(options.acrossInput).value = 0;
  35. document.querySelector(options.actionContainer).classList.remove(options.selectedClass);
  36. }
  37. function checker(actionCheckboxes, options, checked) {
  38. if (checked) {
  39. showQuestion(options);
  40. } else {
  41. reset(options);
  42. }
  43. actionCheckboxes.forEach(function(el) {
  44. el.checked = checked;
  45. el.closest('tr').classList.toggle(options.selectedClass, checked);
  46. });
  47. }
  48. function updateCounter(actionCheckboxes, options) {
  49. const sel = Array.from(actionCheckboxes).filter(function(el) {
  50. return el.checked;
  51. }).length;
  52. const counter = document.querySelector(options.counterContainer);
  53. // data-actions-icnt is defined in the generated HTML
  54. // and contains the total amount of objects in the queryset
  55. const actions_icnt = Number(counter.dataset.actionsIcnt);
  56. counter.textContent = interpolate(
  57. ngettext('%(sel)s of %(cnt)s selected', '%(sel)s of %(cnt)s selected', sel), {
  58. sel: sel,
  59. cnt: actions_icnt
  60. }, true);
  61. const allToggle = document.getElementById(options.allToggleId);
  62. allToggle.checked = sel === actionCheckboxes.length;
  63. if (allToggle.checked) {
  64. showQuestion(options);
  65. } else {
  66. clearAcross(options);
  67. }
  68. }
  69. const defaults = {
  70. actionContainer: "div.actions",
  71. counterContainer: "span.action-counter",
  72. allContainer: "div.actions span.all",
  73. acrossInput: "div.actions input.select-across",
  74. acrossQuestions: "div.actions span.question",
  75. acrossClears: "div.actions span.clear",
  76. allToggleId: "action-toggle",
  77. selectedClass: "selected"
  78. };
  79. window.Actions = function(actionCheckboxes, options) {
  80. options = Object.assign({}, defaults, options);
  81. let list_editable_changed = false;
  82. let lastChecked = null;
  83. let shiftPressed = false;
  84. document.addEventListener('keydown', (event) => {
  85. shiftPressed = event.shiftKey;
  86. });
  87. document.addEventListener('keyup', (event) => {
  88. shiftPressed = event.shiftKey;
  89. });
  90. document.getElementById(options.allToggleId).addEventListener('click', function(event) {
  91. checker(actionCheckboxes, options, this.checked);
  92. updateCounter(actionCheckboxes, options);
  93. });
  94. document.querySelectorAll(options.acrossQuestions + " a").forEach(function(el) {
  95. el.addEventListener('click', function(event) {
  96. event.preventDefault();
  97. const acrossInput = document.querySelector(options.acrossInput);
  98. acrossInput.value = 1;
  99. showClear(options);
  100. });
  101. });
  102. document.querySelectorAll(options.acrossClears + " a").forEach(function(el) {
  103. el.addEventListener('click', function(event) {
  104. event.preventDefault();
  105. document.getElementById(options.allToggleId).checked = false;
  106. clearAcross(options);
  107. checker(actionCheckboxes, options, false);
  108. updateCounter(actionCheckboxes, options);
  109. });
  110. });
  111. function affectedCheckboxes(target, withModifier) {
  112. const multiSelect = (lastChecked && withModifier && lastChecked !== target);
  113. if (!multiSelect) {
  114. return [target];
  115. }
  116. const checkboxes = Array.from(actionCheckboxes);
  117. const targetIndex = checkboxes.findIndex(el => el === target);
  118. const lastCheckedIndex = checkboxes.findIndex(el => el === lastChecked);
  119. const startIndex = Math.min(targetIndex, lastCheckedIndex);
  120. const endIndex = Math.max(targetIndex, lastCheckedIndex);
  121. const filtered = checkboxes.filter((el, index) => (startIndex <= index) && (index <= endIndex));
  122. return filtered;
  123. };
  124. Array.from(document.getElementById('result_list').tBodies).forEach(function(el) {
  125. el.addEventListener('change', function(event) {
  126. const target = event.target;
  127. if (target.classList.contains('action-select')) {
  128. const checkboxes = affectedCheckboxes(target, shiftPressed);
  129. checker(checkboxes, options, target.checked);
  130. updateCounter(actionCheckboxes, options);
  131. lastChecked = target;
  132. } else {
  133. list_editable_changed = true;
  134. }
  135. });
  136. });
  137. document.querySelector('#changelist-form button[name=index]').addEventListener('click', function() {
  138. if (list_editable_changed) {
  139. const confirmed = confirm(gettext("You have unsaved changes on individual editable fields. If you run an action, your unsaved changes will be lost."));
  140. if (!confirmed) {
  141. event.preventDefault();
  142. }
  143. }
  144. });
  145. const el = document.querySelector('#changelist-form input[name=_save]');
  146. // The button does not exist if no fields are editable.
  147. if (el) {
  148. el.addEventListener('click', function(event) {
  149. if (document.querySelector('[name=action]').value) {
  150. const text = list_editable_changed
  151. ? 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.")
  152. : 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.");
  153. if (!confirm(text)) {
  154. event.preventDefault();
  155. }
  156. }
  157. });
  158. }
  159. };
  160. // Call function fn when the DOM is loaded and ready. If it is already
  161. // loaded, call the function now.
  162. // http://youmightnotneedjquery.com/#ready
  163. function ready(fn) {
  164. if (document.readyState !== 'loading') {
  165. fn();
  166. } else {
  167. document.addEventListener('DOMContentLoaded', fn);
  168. }
  169. }
  170. ready(function() {
  171. const actionsEls = document.querySelectorAll('tr input.action-select');
  172. if (actionsEls.length > 0) {
  173. Actions(actionsEls);
  174. }
  175. });
  176. }