comparison core/misc/tabledrag.es6.js @ 14:1fec387a4317

Update Drupal core to 8.5.2 via Composer
author Chris Cannam
date Mon, 23 Apr 2018 09:46:53 +0100
parents 4c8ae668cc8c
children 129ea1e6d783
comparison
equal deleted inserted replaced
13:5fb285c0d0e3 14:1fec387a4317
39 // to allow other scripts access to the object. 39 // to allow other scripts access to the object.
40 Drupal.tableDrag[base] = new Drupal.tableDrag(table[0], settings.tableDrag[base]); 40 Drupal.tableDrag[base] = new Drupal.tableDrag(table[0], settings.tableDrag[base]);
41 } 41 }
42 } 42 }
43 43
44 for (const base in settings.tableDrag) { 44 Object.keys(settings.tableDrag || {}).forEach((base) => {
45 if (settings.tableDrag.hasOwnProperty(base)) { 45 initTableDrag($(context).find(`#${base}`).once('tabledrag'), base);
46 initTableDrag($(context).find(`#${base}`).once('tabledrag'), base); 46 });
47 }
48 }
49 }, 47 },
50 }; 48 };
51 49
52 /** 50 /**
53 * Provides table and field manipulation. 51 * Provides table and field manipulation.
170 * track horizontal movement and indentations. 168 * track horizontal movement and indentations.
171 * 169 *
172 * @type {bool} 170 * @type {bool}
173 */ 171 */
174 this.indentEnabled = false; 172 this.indentEnabled = false;
175 for (const group in tableSettings) { 173 Object.keys(tableSettings || {}).forEach((group) => {
176 if (tableSettings.hasOwnProperty(group)) { 174 Object.keys(tableSettings[group] || {}).forEach((n) => {
177 for (const n in tableSettings[group]) { 175 if (tableSettings[group][n].relationship === 'parent') {
178 if (tableSettings[group].hasOwnProperty(n)) { 176 this.indentEnabled = true;
179 if (tableSettings[group][n].relationship === 'parent') { 177 }
180 this.indentEnabled = true; 178 if (tableSettings[group][n].limit > 0) {
181 } 179 this.maxDepth = tableSettings[group][n].limit;
182 if (tableSettings[group][n].limit > 0) { 180 }
183 this.maxDepth = tableSettings[group][n].limit; 181 });
184 } 182 });
185 }
186 }
187 }
188 }
189 if (this.indentEnabled) { 183 if (this.indentEnabled) {
190 /** 184 /**
191 * Total width of indents, set in makeDraggable. 185 * Total width of indents, set in makeDraggable.
192 * 186 *
193 * @type {number} 187 * @type {number}
262 Drupal.tableDrag.prototype.initColumns = function () { 256 Drupal.tableDrag.prototype.initColumns = function () {
263 const $table = this.$table; 257 const $table = this.$table;
264 let hidden; 258 let hidden;
265 let cell; 259 let cell;
266 let columnIndex; 260 let columnIndex;
267 for (const group in this.tableSettings) { 261 Object.keys(this.tableSettings || {}).forEach((group) => {
268 if (this.tableSettings.hasOwnProperty(group)) { 262 // Find the first field in this group.
269 // Find the first field in this group. 263 // eslint-disable-next-line no-restricted-syntax
270 for (const d in this.tableSettings[group]) { 264 for (const d in this.tableSettings[group]) {
271 if (this.tableSettings[group].hasOwnProperty(d)) { 265 if (this.tableSettings[group].hasOwnProperty(d)) {
272 const field = $table.find(`.${this.tableSettings[group][d].target}`).eq(0); 266 const field = $table.find(`.${this.tableSettings[group][d].target}`).eq(0);
273 if (field.length && this.tableSettings[group][d].hidden) { 267 if (field.length && this.tableSettings[group][d].hidden) {
274 hidden = this.tableSettings[group][d].hidden; 268 hidden = this.tableSettings[group][d].hidden;
275 cell = field.closest('td'); 269 cell = field.closest('td');
276 break; 270 break;
277 } 271 }
278 } 272 }
279 } 273 }
280 274
281 // Mark the column containing this field so it can be hidden. 275 // Mark the column containing this field so it can be hidden.
282 if (hidden && cell[0]) { 276 if (hidden && cell[0]) {
283 // Add 1 to our indexes. The nth-child selector is 1 based, not 0 277 // Add 1 to our indexes. The nth-child selector is 1 based, not 0
284 // based. Match immediate children of the parent element to allow 278 // based. Match immediate children of the parent element to allow
285 // nesting. 279 // nesting.
286 columnIndex = cell.parent().find('> td').index(cell.get(0)) + 1; 280 columnIndex = cell.parent().find('> td').index(cell.get(0)) + 1;
287 $table.find('> thead > tr, > tbody > tr, > tr').each(this.addColspanClass(columnIndex)); 281 $table.find('> thead > tr, > tbody > tr, > tr').each(this.addColspanClass(columnIndex));
288 } 282 }
289 } 283 });
290 }
291 this.displayColumns(showWeight); 284 this.displayColumns(showWeight);
292 }; 285 };
293 286
294 /** 287 /**
295 * Mark cells that have colspan. 288 * Mark cells that have colspan.
417 * The table row settings. 410 * The table row settings.
418 */ 411 */
419 Drupal.tableDrag.prototype.rowSettings = function (group, row) { 412 Drupal.tableDrag.prototype.rowSettings = function (group, row) {
420 const field = $(row).find(`.${group}`); 413 const field = $(row).find(`.${group}`);
421 const tableSettingsGroup = this.tableSettings[group]; 414 const tableSettingsGroup = this.tableSettings[group];
415 // eslint-disable-next-line no-restricted-syntax
422 for (const delta in tableSettingsGroup) { 416 for (const delta in tableSettingsGroup) {
423 if (tableSettingsGroup.hasOwnProperty(delta)) { 417 if (tableSettingsGroup.hasOwnProperty(delta)) {
424 const targetClass = tableSettingsGroup[delta].target; 418 const targetClass = tableSettingsGroup[delta].target;
425 if (field.is(`.${targetClass}`)) { 419 if (field.is(`.${targetClass}`)) {
426 // Return a copy of the row settings. 420 // Return a copy of the row settings.
427 const rowSettings = {}; 421 const rowSettings = {};
422 // eslint-disable-next-line no-restricted-syntax
428 for (const n in tableSettingsGroup[delta]) { 423 for (const n in tableSettingsGroup[delta]) {
429 if (tableSettingsGroup[delta].hasOwnProperty(n)) { 424 if (tableSettingsGroup[delta].hasOwnProperty(n)) {
430 rowSettings[n] = tableSettingsGroup[delta][n]; 425 rowSettings[n] = tableSettingsGroup[delta][n];
431 } 426 }
432 } 427 }
508 break; 503 break;
509 504
510 // Up arrow. 505 // Up arrow.
511 case 38: 506 case 38:
512 // Safari up arrow. 507 // Safari up arrow.
513 case 63232: 508 case 63232: {
514 var $previousRow = $(self.rowObject.element).prev('tr:first-of-type'); 509 let $previousRow = $(self.rowObject.element).prev('tr:first-of-type');
515 var previousRow = $previousRow.get(0); 510 let previousRow = $previousRow.get(0);
516 while (previousRow && $previousRow.is(':hidden')) { 511 while (previousRow && $previousRow.is(':hidden')) {
517 $previousRow = $(previousRow).prev('tr:first-of-type'); 512 $previousRow = $(previousRow).prev('tr:first-of-type');
518 previousRow = $previousRow.get(0); 513 previousRow = $previousRow.get(0);
519 } 514 }
520 if (previousRow) { 515 if (previousRow) {
547 } 542 }
548 // Regain focus after the DOM manipulation. 543 // Regain focus after the DOM manipulation.
549 handle.trigger('focus'); 544 handle.trigger('focus');
550 } 545 }
551 break; 546 break;
552 547 }
553 // Right arrow. 548 // Right arrow.
554 case 39: 549 case 39:
555 // Safari right arrow. 550 // Safari right arrow.
556 case 63235: 551 case 63235:
557 keyChange = true; 552 keyChange = true;
559 break; 554 break;
560 555
561 // Down arrow. 556 // Down arrow.
562 case 40: 557 case 40:
563 // Safari down arrow. 558 // Safari down arrow.
564 case 63233: 559 case 63233: {
565 var $nextRow = $(self.rowObject.group).eq(-1).next('tr:first-of-type'); 560 let $nextRow = $(self.rowObject.group).eq(-1).next('tr:first-of-type');
566 var nextRow = $nextRow.get(0); 561 let nextRow = $nextRow.get(0);
567 while (nextRow && $nextRow.is(':hidden')) { 562 while (nextRow && $nextRow.is(':hidden')) {
568 $nextRow = $(nextRow).next('tr:first-of-type'); 563 $nextRow = $(nextRow).next('tr:first-of-type');
569 nextRow = $nextRow.get(0); 564 nextRow = $nextRow.get(0);
570 } 565 }
571 if (nextRow) { 566 if (nextRow) {
597 } 592 }
598 // Regain focus after the DOM manipulation. 593 // Regain focus after the DOM manipulation.
599 handle.trigger('focus'); 594 handle.trigger('focus');
600 } 595 }
601 break; 596 break;
597 }
602 } 598 }
603 599
604 /* eslint-enable no-fallthrough */ 600 /* eslint-enable no-fallthrough */
605 601
606 if (self.rowObject && self.rowObject.changed === true) { 602 if (self.rowObject && self.rowObject.changed === true) {
710 // Check if the window should be scrolled (and how fast). 706 // Check if the window should be scrolled (and how fast).
711 const scrollAmount = self.checkScroll(self.currentPointerCoords.y); 707 const scrollAmount = self.checkScroll(self.currentPointerCoords.y);
712 // Stop any current scrolling. 708 // Stop any current scrolling.
713 clearInterval(self.scrollInterval); 709 clearInterval(self.scrollInterval);
714 // Continue scrolling if the mouse has moved in the scroll direction. 710 // Continue scrolling if the mouse has moved in the scroll direction.
715 if (scrollAmount > 0 && self.rowObject.direction === 'down' || scrollAmount < 0 && self.rowObject.direction === 'up') { 711 if ((scrollAmount > 0 && self.rowObject.direction === 'down')
712 || (scrollAmount < 0 && self.rowObject.direction === 'up')) {
716 self.setScroll(scrollAmount); 713 self.setScroll(scrollAmount);
717 } 714 }
718 715
719 // If we have a valid target, perform the swap and restripe the table. 716 // If we have a valid target, perform the swap and restripe the table.
720 const currentRow = self.findDropTargetRow(x, y); 717 const currentRow = self.findDropTargetRow(x, y);
770 // Update the fields in the dropped row. 767 // Update the fields in the dropped row.
771 self.updateFields(droppedRow); 768 self.updateFields(droppedRow);
772 769
773 // If a setting exists for affecting the entire group, update all the 770 // If a setting exists for affecting the entire group, update all the
774 // fields in the entire dragged group. 771 // fields in the entire dragged group.
775 for (const group in self.tableSettings) { 772 Object.keys(self.tableSettings || {}).forEach((group) => {
776 if (self.tableSettings.hasOwnProperty(group)) { 773 const rowSettings = self.rowSettings(group, droppedRow);
777 const rowSettings = self.rowSettings(group, droppedRow); 774 if (rowSettings.relationship === 'group') {
778 if (rowSettings.relationship === 'group') { 775 Object.keys(self.rowObject.children || {}).forEach((n) => {
779 for (const n in self.rowObject.children) { 776 self.updateField(self.rowObject.children[n], group);
780 if (self.rowObject.children.hasOwnProperty(n)) { 777 });
781 self.updateField(self.rowObject.children[n], group); 778 }
782 } 779 });
783 }
784 }
785 }
786 }
787 780
788 self.rowObject.markChanged(); 781 self.rowObject.markChanged();
789 if (self.changed === false) { 782 if (self.changed === false) {
790 $(Drupal.theme('tableDragChangedWarning')).insertBefore(self.table).hide().fadeIn('slow'); 783 $(Drupal.theme('tableDragChangedWarning')).insertBefore(self.table).hide().fadeIn('slow');
791 self.changed = true; 784 self.changed = true;
824 Drupal.tableDrag.prototype.pointerCoords = function (event) { 817 Drupal.tableDrag.prototype.pointerCoords = function (event) {
825 if (event.pageX || event.pageY) { 818 if (event.pageX || event.pageY) {
826 return { x: event.pageX, y: event.pageY }; 819 return { x: event.pageX, y: event.pageY };
827 } 820 }
828 return { 821 return {
829 x: event.clientX + document.body.scrollLeft - document.body.clientLeft, 822 x: (event.clientX + document.body.scrollLeft) - document.body.clientLeft,
830 y: event.clientY + document.body.scrollTop - document.body.clientTop, 823 y: (event.clientY + document.body.scrollTop) - document.body.clientTop,
831 }; 824 };
832 }; 825 };
833 826
834 /** 827 /**
835 * Get the event offset from the target element. 828 * Get the event offset from the target element.
868 const rows = $(this.table.tBodies[0].rows).not(':hidden'); 861 const rows = $(this.table.tBodies[0].rows).not(':hidden');
869 for (let n = 0; n < rows.length; n++) { 862 for (let n = 0; n < rows.length; n++) {
870 let row = rows[n]; 863 let row = rows[n];
871 let $row = $(row); 864 let $row = $(row);
872 const rowY = $row.offset().top; 865 const rowY = $row.offset().top;
873 var rowHeight; 866 let rowHeight;
874 // Because Safari does not report offsetHeight on table rows, but does on 867 // Because Safari does not report offsetHeight on table rows, but does on
875 // table cells, grab the firstChild of the row and use that instead. 868 // table cells, grab the firstChild of the row and use that instead.
876 // http://jacob.peargrove.com/blog/2006/technical/table-row-offsettop-bug-in-safari. 869 // http://jacob.peargrove.com/blog/2006/technical/table-row-offsettop-bug-in-safari.
877 if (row.offsetHeight === 0) { 870 if (row.offsetHeight === 0) {
878 rowHeight = parseInt(row.firstChild.offsetHeight, 10) / 2; 871 rowHeight = parseInt(row.firstChild.offsetHeight, 10) / 2;
884 877
885 // Because we always insert before, we need to offset the height a bit. 878 // Because we always insert before, we need to offset the height a bit.
886 if ((y > (rowY - rowHeight)) && (y < (rowY + rowHeight))) { 879 if ((y > (rowY - rowHeight)) && (y < (rowY + rowHeight))) {
887 if (this.indentEnabled) { 880 if (this.indentEnabled) {
888 // Check that this row is not a child of the row being dragged. 881 // Check that this row is not a child of the row being dragged.
882 // eslint-disable-next-line no-restricted-syntax
889 for (n in this.rowObject.group) { 883 for (n in this.rowObject.group) {
890 if (this.rowObject.group[n] === row) { 884 if (this.rowObject.group[n] === row) {
891 return null; 885 return null;
892 } 886 }
893 } 887 }
894 } 888 }
895 else { 889 // Do not allow a row to be swapped with itself.
896 // Do not allow a row to be swapped with itself. 890 else if (row === this.rowObject.element) {
897 if (row === this.rowObject.element) { 891 return null;
898 return null;
899 }
900 } 892 }
901 893
902 // Check that swapping with this row is allowed. 894 // Check that swapping with this row is allowed.
903 if (!this.rowObject.isValidSwap(row)) { 895 if (!this.rowObject.isValidSwap(row)) {
904 return null; 896 return null;
922 * 914 *
923 * @param {HTMLElement} changedRow 915 * @param {HTMLElement} changedRow
924 * DOM object for the row that was just dropped. 916 * DOM object for the row that was just dropped.
925 */ 917 */
926 Drupal.tableDrag.prototype.updateFields = function (changedRow) { 918 Drupal.tableDrag.prototype.updateFields = function (changedRow) {
927 for (const group in this.tableSettings) { 919 Object.keys(this.tableSettings || {}).forEach((group) => {
928 if (this.tableSettings.hasOwnProperty(group)) { 920 // Each group may have a different setting for relationship, so we find
929 // Each group may have a different setting for relationship, so we find 921 // the source rows for each separately.
930 // the source rows for each separately. 922 this.updateField(changedRow, group);
931 this.updateField(changedRow, group); 923 });
932 }
933 }
934 }; 924 };
935 925
936 /** 926 /**
937 * After the row is dropped, update a single table field. 927 * After the row is dropped, update a single table field.
938 * 928 *
1035 case 'match': 1025 case 'match':
1036 // Update the value. 1026 // Update the value.
1037 targetElement.value = sourceElement.value; 1027 targetElement.value = sourceElement.value;
1038 break; 1028 break;
1039 1029
1040 case 'order': 1030 case 'order': {
1041 var siblings = this.rowObject.findSiblings(rowSettings); 1031 const siblings = this.rowObject.findSiblings(rowSettings);
1042 if ($(targetElement).is('select')) { 1032 if ($(targetElement).is('select')) {
1043 // Get a list of acceptable values. 1033 // Get a list of acceptable values.
1044 const values = []; 1034 const values = [];
1045 $(targetElement).find('option').each(function () { 1035 $(targetElement).find('option').each(function () {
1046 values.push(this.value); 1036 values.push(this.value);
1065 this.value = weight; 1055 this.value = weight;
1066 weight++; 1056 weight++;
1067 }); 1057 });
1068 } 1058 }
1069 break; 1059 break;
1060 }
1070 } 1061 }
1071 } 1062 }
1072 }; 1063 };
1073 1064
1074 /** 1065 /**
1104 */ 1095 */
1105 Drupal.tableDrag.prototype.checkScroll = function (cursorY) { 1096 Drupal.tableDrag.prototype.checkScroll = function (cursorY) {
1106 const de = document.documentElement; 1097 const de = document.documentElement;
1107 const b = document.body; 1098 const b = document.body;
1108 1099
1109 const windowHeight = this.windowHeight = window.innerHeight || (de.clientHeight && de.clientWidth !== 0 ? de.clientHeight : b.offsetHeight); 1100 const windowHeight = window.innerHeight || (de.clientHeight && de.clientWidth !== 0 ? de.clientHeight : b.offsetHeight);
1101 this.windowHeight = windowHeight;
1110 let scrollY; 1102 let scrollY;
1111 if (document.all) { 1103 if (document.all) {
1112 scrollY = this.scrollY = !de.scrollTop ? b.scrollTop : de.scrollTop; 1104 scrollY = !de.scrollTop ? b.scrollTop : de.scrollTop;
1113 } 1105 }
1114 else { 1106 else {
1115 scrollY = this.scrollY = window.pageYOffset ? window.pageYOffset : window.scrollY; 1107 scrollY = window.pageYOffset ? window.pageYOffset : window.scrollY;
1116 } 1108 }
1109 this.scrollY = scrollY;
1117 const trigger = this.scrollSettings.trigger; 1110 const trigger = this.scrollSettings.trigger;
1118 let delta = 0; 1111 let delta = 0;
1119 1112
1120 // Return a scroll speed relative to the edge of the screen. 1113 // Return a scroll speed relative to the edge of the screen.
1121 if (cursorY - scrollY > windowHeight - trigger) { 1114 if (cursorY - scrollY > windowHeight - trigger) {
1122 delta = trigger / (windowHeight + scrollY - cursorY); 1115 delta = trigger / ((windowHeight + scrollY) - cursorY);
1123 delta = (delta > 0 && delta < trigger) ? delta : trigger; 1116 delta = (delta > 0 && delta < trigger) ? delta : trigger;
1124 return delta * this.scrollSettings.amount; 1117 return delta * this.scrollSettings.amount;
1125 } 1118 }
1126 else if (cursorY - scrollY < trigger) { 1119 else if (cursorY - scrollY < trigger) {
1127 delta = trigger / (cursorY - scrollY); 1120 delta = trigger / (cursorY - scrollY);
1142 this.scrollInterval = setInterval(() => { 1135 this.scrollInterval = setInterval(() => {
1143 // Update the scroll values stored in the object. 1136 // Update the scroll values stored in the object.
1144 self.checkScroll(self.currentPointerCoords.y); 1137 self.checkScroll(self.currentPointerCoords.y);
1145 const aboveTable = self.scrollY > self.table.topY; 1138 const aboveTable = self.scrollY > self.table.topY;
1146 const belowTable = self.scrollY + self.windowHeight < self.table.bottomY; 1139 const belowTable = self.scrollY + self.windowHeight < self.table.bottomY;
1147 if (scrollAmount > 0 && belowTable || scrollAmount < 0 && aboveTable) { 1140 if ((scrollAmount > 0 && belowTable)
1141 || (scrollAmount < 0 && aboveTable)) {
1148 window.scrollBy(0, scrollAmount); 1142 window.scrollBy(0, scrollAmount);
1149 } 1143 }
1150 }, this.scrollSettings.interval); 1144 }, this.scrollSettings.interval);
1151 }; 1145 };
1152 1146
1155 */ 1149 */
1156 Drupal.tableDrag.prototype.restripeTable = function () { 1150 Drupal.tableDrag.prototype.restripeTable = function () {
1157 // :even and :odd are reversed because jQuery counts from 0 and 1151 // :even and :odd are reversed because jQuery counts from 0 and
1158 // we count from 1, so we're out of sync. 1152 // we count from 1, so we're out of sync.
1159 // Match immediate children of the parent element to allow nesting. 1153 // Match immediate children of the parent element to allow nesting.
1160 $(this.table).find('> tbody > tr.draggable, > tr.draggable') 1154 $(this.table)
1155 .find('> tbody > tr.draggable, > tr.draggable')
1161 .filter(':visible') 1156 .filter(':visible')
1162 .filter(':odd').removeClass('odd').addClass('even').end() 1157 .filter(':odd')
1163 .filter(':even').removeClass('even').addClass('odd'); 1158 .removeClass('odd')
1159 .addClass('even')
1160 .end()
1161 .filter(':even')
1162 .removeClass('even')
1163 .addClass('odd');
1164 }; 1164 };
1165 1165
1166 /** 1166 /**
1167 * Stub function. Allows a custom handler when a row begins dragging. 1167 * Stub function. Allows a custom handler when a row begins dragging.
1168 * 1168 *
1346 * An object with the keys `min` and `max` to indicate the valid indent 1346 * An object with the keys `min` and `max` to indicate the valid indent
1347 * interval. 1347 * interval.
1348 */ 1348 */
1349 Drupal.tableDrag.prototype.row.prototype.validIndentInterval = function (prevRow, nextRow) { 1349 Drupal.tableDrag.prototype.row.prototype.validIndentInterval = function (prevRow, nextRow) {
1350 const $prevRow = $(prevRow); 1350 const $prevRow = $(prevRow);
1351 let minIndent;
1352 let maxIndent; 1351 let maxIndent;
1353 1352
1354 // Minimum indentation: 1353 // Minimum indentation:
1355 // Do not orphan the next row. 1354 // Do not orphan the next row.
1356 minIndent = nextRow ? $(nextRow).find('.js-indentation').length : 0; 1355 const minIndent = nextRow ? $(nextRow).find('.js-indentation').length : 0;
1357 1356
1358 // Maximum indentation: 1357 // Maximum indentation:
1359 if (!prevRow || $prevRow.is(':not(.draggable)') || $(this.element).is('.tabledrag-root')) { 1358 if (!prevRow || $prevRow.is(':not(.draggable)') || $(this.element).is('.tabledrag-root')) {
1360 // Do not indent: 1359 // Do not indent:
1361 // - the first row in the table, 1360 // - the first row in the table,
1475 1474
1476 /** 1475 /**
1477 * Remove indentation helper classes from the current row group. 1476 * Remove indentation helper classes from the current row group.
1478 */ 1477 */
1479 Drupal.tableDrag.prototype.row.prototype.removeIndentClasses = function () { 1478 Drupal.tableDrag.prototype.row.prototype.removeIndentClasses = function () {
1480 for (const n in this.children) { 1479 Object.keys(this.children || {}).forEach((n) => {
1481 if (this.children.hasOwnProperty(n)) { 1480 $(this.children[n]).find('.js-indentation')
1482 $(this.children[n]).find('.js-indentation') 1481 .removeClass('tree-child')
1483 .removeClass('tree-child') 1482 .removeClass('tree-child-first')
1484 .removeClass('tree-child-first') 1483 .removeClass('tree-child-last')
1485 .removeClass('tree-child-last') 1484 .removeClass('tree-child-horizontal');
1486 .removeClass('tree-child-horizontal'); 1485 });
1487 }
1488 }
1489 }; 1486 };
1490 1487
1491 /** 1488 /**
1492 * Add an asterisk or other marker to the changed row. 1489 * Add an asterisk or other marker to the changed row.
1493 */ 1490 */