comparison core/misc/tabledrag.es6.js @ 17:129ea1e6d783

Update, including to Drupal core 8.6.10
author Chris Cannam
date Thu, 28 Feb 2019 13:21:36 +0000
parents 1fec387a4317
children af1871eacc83
comparison
equal deleted inserted replaced
16:c2387f117808 17:129ea1e6d783
7 * Triggers when weights columns are toggled. 7 * Triggers when weights columns are toggled.
8 * 8 *
9 * @event columnschange 9 * @event columnschange
10 */ 10 */
11 11
12 (function ($, Drupal, drupalSettings) { 12 (function($, Drupal, drupalSettings) {
13 /** 13 /**
14 * Store the state of weight columns display for all tables. 14 * Store the state of weight columns display for all tables.
15 * 15 *
16 * Default value is to hide weight columns. 16 * Default value is to hide weight columns.
17 */ 17 */
18 let showWeight = JSON.parse(localStorage.getItem('Drupal.tableDrag.showWeight')); 18 let showWeight = JSON.parse(
19 localStorage.getItem('Drupal.tableDrag.showWeight'),
20 );
19 21
20 /** 22 /**
21 * Drag and drop table rows with field manipulation. 23 * Drag and drop table rows with field manipulation.
22 * 24 *
23 * Using the drupal_attach_tabledrag() function, any table with weights or 25 * Using the drupal_attach_tabledrag() function, any table with weights or
35 attach(context, settings) { 37 attach(context, settings) {
36 function initTableDrag(table, base) { 38 function initTableDrag(table, base) {
37 if (table.length) { 39 if (table.length) {
38 // Create the new tableDrag instance. Save in the Drupal variable 40 // Create the new tableDrag instance. Save in the Drupal variable
39 // to allow other scripts access to the object. 41 // to allow other scripts access to the object.
40 Drupal.tableDrag[base] = new Drupal.tableDrag(table[0], settings.tableDrag[base]); 42 Drupal.tableDrag[base] = new Drupal.tableDrag(
41 } 43 table[0],
42 } 44 settings.tableDrag[base],
43 45 );
44 Object.keys(settings.tableDrag || {}).forEach((base) => { 46 }
45 initTableDrag($(context).find(`#${base}`).once('tabledrag'), base); 47 }
48
49 Object.keys(settings.tableDrag || {}).forEach(base => {
50 initTableDrag(
51 $(context)
52 .find(`#${base}`)
53 .once('tabledrag'),
54 base,
55 );
46 }); 56 });
47 }, 57 },
48 }; 58 };
49 59
50 /** 60 /**
55 * @param {HTMLElement} table 65 * @param {HTMLElement} table
56 * DOM object for the table to be made draggable. 66 * DOM object for the table to be made draggable.
57 * @param {object} tableSettings 67 * @param {object} tableSettings
58 * Settings for the table added via drupal_add_dragtable(). 68 * Settings for the table added via drupal_add_dragtable().
59 */ 69 */
60 Drupal.tableDrag = function (table, tableSettings) { 70 Drupal.tableDrag = function(table, tableSettings) {
61 const self = this; 71 const self = this;
62 const $table = $(table); 72 const $table = $(table);
63 73
64 /** 74 /**
65 * @type {jQuery} 75 * @type {jQuery}
168 * track horizontal movement and indentations. 178 * track horizontal movement and indentations.
169 * 179 *
170 * @type {bool} 180 * @type {bool}
171 */ 181 */
172 this.indentEnabled = false; 182 this.indentEnabled = false;
173 Object.keys(tableSettings || {}).forEach((group) => { 183 Object.keys(tableSettings || {}).forEach(group => {
174 Object.keys(tableSettings[group] || {}).forEach((n) => { 184 Object.keys(tableSettings[group] || {}).forEach(n => {
175 if (tableSettings[group][n].relationship === 'parent') { 185 if (tableSettings[group][n].relationship === 'parent') {
176 this.indentEnabled = true; 186 this.indentEnabled = true;
177 } 187 }
178 if (tableSettings[group][n].limit > 0) { 188 if (tableSettings[group][n].limit > 0) {
179 this.maxDepth = tableSettings[group][n].limit; 189 this.maxDepth = tableSettings[group][n].limit;
190 // Find the width of indentations to measure mouse movements against. 200 // Find the width of indentations to measure mouse movements against.
191 // Because the table doesn't need to start with any indentations, we 201 // Because the table doesn't need to start with any indentations, we
192 // manually append 2 indentations in the first draggable row, measure 202 // manually append 2 indentations in the first draggable row, measure
193 // the offset, then remove. 203 // the offset, then remove.
194 const indent = Drupal.theme('tableDragIndentation'); 204 const indent = Drupal.theme('tableDragIndentation');
195 const testRow = $('<tr/>').addClass('draggable').appendTo(table); 205 const testRow = $('<tr/>')
196 const testCell = $('<td/>').appendTo(testRow).prepend(indent).prepend(indent); 206 .addClass('draggable')
207 .appendTo(table);
208 const testCell = $('<td/>')
209 .appendTo(testRow)
210 .prepend(indent)
211 .prepend(indent);
197 const $indentation = testCell.find('.js-indentation'); 212 const $indentation = testCell.find('.js-indentation');
198 213
199 /** 214 /**
200 * 215 *
201 * @type {number} 216 * @type {number}
202 */ 217 */
203 this.indentAmount = $indentation.get(1).offsetLeft - $indentation.get(0).offsetLeft; 218 this.indentAmount =
219 $indentation.get(1).offsetLeft - $indentation.get(0).offsetLeft;
204 testRow.remove(); 220 testRow.remove();
205 } 221 }
206 222
207 // Make each applicable row draggable. 223 // Make each applicable row draggable.
208 // Match immediate children of the parent element to allow nesting. 224 // Match immediate children of the parent element to allow nesting.
209 $table.find('> tr.draggable, > tbody > tr.draggable').each(function () { 225 $table.find('> tr.draggable, > tbody > tr.draggable').each(function() {
210 self.makeDraggable(this); 226 self.makeDraggable(this);
211 }); 227 });
212 228
213 // Add a link before the table for users to show or hide weight columns. 229 // Add a link before the table for users to show or hide weight columns.
214 $table.before($('<button type="button" class="link tabledrag-toggle-weight"></button>') 230 $table.before(
215 .attr('title', Drupal.t('Re-order rows by numerical weight instead of dragging.')) 231 $('<button type="button" class="link tabledrag-toggle-weight"></button>')
216 .on('click', $.proxy(function (e) { 232 .attr(
217 e.preventDefault(); 233 'title',
218 this.toggleColumns(); 234 Drupal.t('Re-order rows by numerical weight instead of dragging.'),
219 }, this)) 235 )
220 .wrap('<div class="tabledrag-toggle-weight-wrapper"></div>') 236 .on(
221 .parent(), 237 'click',
238 $.proxy(function(e) {
239 e.preventDefault();
240 this.toggleColumns();
241 }, this),
242 )
243 .wrap('<div class="tabledrag-toggle-weight-wrapper"></div>')
244 .parent(),
222 ); 245 );
223 246
224 // Initialize the specified columns (for example, weight or parent columns) 247 // Initialize the specified columns (for example, weight or parent columns)
225 // to show or hide according to user preference. This aids accessibility 248 // to show or hide according to user preference. This aids accessibility
226 // so that, e.g., screen reader users can choose to enter weight values and 249 // so that, e.g., screen reader users can choose to enter weight values and
227 // manipulate form elements directly, rather than using drag-and-drop.. 250 // manipulate form elements directly, rather than using drag-and-drop..
228 self.initColumns(); 251 self.initColumns();
229 252
230 // Add event bindings to the document. The self variable is passed along 253 // Add event bindings to the document. The self variable is passed along
231 // as event handlers do not have direct access to the tableDrag object. 254 // as event handlers do not have direct access to the tableDrag object.
232 $(document).on('touchmove', event => self.dragRow(event.originalEvent.touches[0], self)); 255 $(document).on('touchmove', event =>
233 $(document).on('touchend', event => self.dropRow(event.originalEvent.touches[0], self)); 256 self.dragRow(event.originalEvent.touches[0], self),
257 );
258 $(document).on('touchend', event =>
259 self.dropRow(event.originalEvent.touches[0], self),
260 );
234 $(document).on('mousemove pointermove', event => self.dragRow(event, self)); 261 $(document).on('mousemove pointermove', event => self.dragRow(event, self));
235 $(document).on('mouseup pointerup', event => self.dropRow(event, self)); 262 $(document).on('mouseup pointerup', event => self.dropRow(event, self));
236 263
237 // React to localStorage event showing or hiding weight columns. 264 // React to localStorage event showing or hiding weight columns.
238 $(window).on('storage', $.proxy(function (e) { 265 $(window).on(
239 // Only react to 'Drupal.tableDrag.showWeight' value change. 266 'storage',
240 if (e.originalEvent.key === 'Drupal.tableDrag.showWeight') { 267 $.proxy(function(e) {
241 // This was changed in another window, get the new value for this 268 // Only react to 'Drupal.tableDrag.showWeight' value change.
242 // window. 269 if (e.originalEvent.key === 'Drupal.tableDrag.showWeight') {
243 showWeight = JSON.parse(e.originalEvent.newValue); 270 // This was changed in another window, get the new value for this
244 this.displayColumns(showWeight); 271 // window.
245 } 272 showWeight = JSON.parse(e.originalEvent.newValue);
246 }, this)); 273 this.displayColumns(showWeight);
274 }
275 }, this),
276 );
247 }; 277 };
248 278
249 /** 279 /**
250 * Initialize columns containing form elements to be hidden by default. 280 * Initialize columns containing form elements to be hidden by default.
251 * 281 *
252 * Identify and mark each cell with a CSS class so we can easily toggle 282 * Identify and mark each cell with a CSS class so we can easily toggle
253 * show/hide it. Finally, hide columns if user does not have a 283 * show/hide it. Finally, hide columns if user does not have a
254 * 'Drupal.tableDrag.showWeight' localStorage value. 284 * 'Drupal.tableDrag.showWeight' localStorage value.
255 */ 285 */
256 Drupal.tableDrag.prototype.initColumns = function () { 286 Drupal.tableDrag.prototype.initColumns = function() {
257 const $table = this.$table; 287 const $table = this.$table;
258 let hidden; 288 let hidden;
259 let cell; 289 let cell;
260 let columnIndex; 290 let columnIndex;
261 Object.keys(this.tableSettings || {}).forEach((group) => { 291 Object.keys(this.tableSettings || {}).forEach(group => {
262 // Find the first field in this group. 292 // Find the first field in this group.
263 // eslint-disable-next-line no-restricted-syntax 293 Object.keys(this.tableSettings[group]).some(tableSetting => {
264 for (const d in this.tableSettings[group]) { 294 const field = $table
265 if (this.tableSettings[group].hasOwnProperty(d)) { 295 .find(`.${this.tableSettings[group][tableSetting].target}`)
266 const field = $table.find(`.${this.tableSettings[group][d].target}`).eq(0); 296 .eq(0);
267 if (field.length && this.tableSettings[group][d].hidden) { 297 if (field.length && this.tableSettings[group][tableSetting].hidden) {
268 hidden = this.tableSettings[group][d].hidden; 298 hidden = this.tableSettings[group][tableSetting].hidden;
269 cell = field.closest('td'); 299 cell = field.closest('td');
270 break; 300 return true;
271 } 301 }
272 } 302 return false;
273 } 303 });
274 304
275 // Mark the column containing this field so it can be hidden. 305 // Mark the column containing this field so it can be hidden.
276 if (hidden && cell[0]) { 306 if (hidden && cell[0]) {
277 // Add 1 to our indexes. The nth-child selector is 1 based, not 0 307 // Add 1 to our indexes. The nth-child selector is 1 based, not 0
278 // based. Match immediate children of the parent element to allow 308 // based. Match immediate children of the parent element to allow
279 // nesting. 309 // nesting.
280 columnIndex = cell.parent().find('> td').index(cell.get(0)) + 1; 310 columnIndex =
281 $table.find('> thead > tr, > tbody > tr, > tr').each(this.addColspanClass(columnIndex)); 311 cell
312 .parent()
313 .find('> td')
314 .index(cell.get(0)) + 1;
315 $table
316 .find('> thead > tr, > tbody > tr, > tr')
317 .each(this.addColspanClass(columnIndex));
282 } 318 }
283 }); 319 });
284 this.displayColumns(showWeight); 320 this.displayColumns(showWeight);
285 }; 321 };
286 322
293 * The column index to add colspan class to. 329 * The column index to add colspan class to.
294 * 330 *
295 * @return {function} 331 * @return {function}
296 * Function to add colspan class. 332 * Function to add colspan class.
297 */ 333 */
298 Drupal.tableDrag.prototype.addColspanClass = function (columnIndex) { 334 Drupal.tableDrag.prototype.addColspanClass = function(columnIndex) {
299 return function () { 335 return function() {
300 // Get the columnIndex and adjust for any colspans in this row. 336 // Get the columnIndex and adjust for any colspans in this row.
301 const $row = $(this); 337 const $row = $(this);
302 let index = columnIndex; 338 let index = columnIndex;
303 const cells = $row.children(); 339 const cells = $row.children();
304 let cell; 340 let cell;
305 cells.each(function (n) { 341 cells.each(function(n) {
306 if (n < index && this.colSpan && this.colSpan > 1) { 342 if (n < index && this.colSpan && this.colSpan > 1) {
307 index -= this.colSpan - 1; 343 index -= this.colSpan - 1;
308 } 344 }
309 }); 345 });
310 if (index > 0) { 346 if (index > 0) {
311 cell = cells.filter(`:nth-child(${index})`); 347 cell = cells.filter(`:nth-child(${index})`);
312 if (cell[0].colSpan && cell[0].colSpan > 1) { 348 if (cell[0].colSpan && cell[0].colSpan > 1) {
313 // If this cell has a colspan, mark it so we can reduce the colspan. 349 // If this cell has a colspan, mark it so we can reduce the colspan.
314 cell.addClass('tabledrag-has-colspan'); 350 cell.addClass('tabledrag-has-colspan');
315 } 351 } else {
316 else {
317 // Mark this cell so we can hide it. 352 // Mark this cell so we can hide it.
318 cell.addClass('tabledrag-hide'); 353 cell.addClass('tabledrag-hide');
319 } 354 }
320 } 355 }
321 }; 356 };
327 * @fires event:columnschange 362 * @fires event:columnschange
328 * 363 *
329 * @param {bool} displayWeight 364 * @param {bool} displayWeight
330 * 'true' will show weight columns. 365 * 'true' will show weight columns.
331 */ 366 */
332 Drupal.tableDrag.prototype.displayColumns = function (displayWeight) { 367 Drupal.tableDrag.prototype.displayColumns = function(displayWeight) {
333 if (displayWeight) { 368 if (displayWeight) {
334 this.showColumns(); 369 this.showColumns();
335 } 370 }
336 // Default action is to hide columns. 371 // Default action is to hide columns.
337 else { 372 else {
338 this.hideColumns(); 373 this.hideColumns();
339 } 374 }
340 // Trigger an event to allow other scripts to react to this display change. 375 // Trigger an event to allow other scripts to react to this display change.
341 // Force the extra parameter as a bool. 376 // Force the extra parameter as a bool.
342 $('table').findOnce('tabledrag').trigger('columnschange', !!displayWeight); 377 $('table')
378 .findOnce('tabledrag')
379 .trigger('columnschange', !!displayWeight);
343 }; 380 };
344 381
345 /** 382 /**
346 * Toggle the weight column depending on 'showWeight' value. 383 * Toggle the weight column depending on 'showWeight' value.
347 * 384 *
348 * Store only default override. 385 * Store only default override.
349 */ 386 */
350 Drupal.tableDrag.prototype.toggleColumns = function () { 387 Drupal.tableDrag.prototype.toggleColumns = function() {
351 showWeight = !showWeight; 388 showWeight = !showWeight;
352 this.displayColumns(showWeight); 389 this.displayColumns(showWeight);
353 if (showWeight) { 390 if (showWeight) {
354 // Save default override. 391 // Save default override.
355 localStorage.setItem('Drupal.tableDrag.showWeight', showWeight); 392 localStorage.setItem('Drupal.tableDrag.showWeight', showWeight);
356 } 393 } else {
357 else {
358 // Reset the value to its default. 394 // Reset the value to its default.
359 localStorage.removeItem('Drupal.tableDrag.showWeight'); 395 localStorage.removeItem('Drupal.tableDrag.showWeight');
360 } 396 }
361 }; 397 };
362 398
363 /** 399 /**
364 * Hide the columns containing weight/parent form elements. 400 * Hide the columns containing weight/parent form elements.
365 * 401 *
366 * Undo showColumns(). 402 * Undo showColumns().
367 */ 403 */
368 Drupal.tableDrag.prototype.hideColumns = function () { 404 Drupal.tableDrag.prototype.hideColumns = function() {
369 const $tables = $('table').findOnce('tabledrag'); 405 const $tables = $('table').findOnce('tabledrag');
370 // Hide weight/parent cells and headers. 406 // Hide weight/parent cells and headers.
371 $tables.find('.tabledrag-hide').css('display', 'none'); 407 $tables.find('.tabledrag-hide').css('display', 'none');
372 // Show TableDrag handles. 408 // Show TableDrag handles.
373 $tables.find('.tabledrag-handle').css('display', ''); 409 $tables.find('.tabledrag-handle').css('display', '');
374 // Reduce the colspan of any effected multi-span columns. 410 // Reduce the colspan of any effected multi-span columns.
375 $tables.find('.tabledrag-has-colspan').each(function () { 411 $tables.find('.tabledrag-has-colspan').each(function() {
376 this.colSpan = this.colSpan - 1; 412 this.colSpan = this.colSpan - 1;
377 }); 413 });
378 // Change link text. 414 // Change link text.
379 $('.tabledrag-toggle-weight').text(Drupal.t('Show row weights')); 415 $('.tabledrag-toggle-weight').text(Drupal.t('Show row weights'));
380 }; 416 };
382 /** 418 /**
383 * Show the columns containing weight/parent form elements. 419 * Show the columns containing weight/parent form elements.
384 * 420 *
385 * Undo hideColumns(). 421 * Undo hideColumns().
386 */ 422 */
387 Drupal.tableDrag.prototype.showColumns = function () { 423 Drupal.tableDrag.prototype.showColumns = function() {
388 const $tables = $('table').findOnce('tabledrag'); 424 const $tables = $('table').findOnce('tabledrag');
389 // Show weight/parent cells and headers. 425 // Show weight/parent cells and headers.
390 $tables.find('.tabledrag-hide').css('display', ''); 426 $tables.find('.tabledrag-hide').css('display', '');
391 // Hide TableDrag handles. 427 // Hide TableDrag handles.
392 $tables.find('.tabledrag-handle').css('display', 'none'); 428 $tables.find('.tabledrag-handle').css('display', 'none');
393 // Increase the colspan for any columns where it was previously reduced. 429 // Increase the colspan for any columns where it was previously reduced.
394 $tables.find('.tabledrag-has-colspan').each(function () { 430 $tables.find('.tabledrag-has-colspan').each(function() {
395 this.colSpan = this.colSpan + 1; 431 this.colSpan = this.colSpan + 1;
396 }); 432 });
397 // Change link text. 433 // Change link text.
398 $('.tabledrag-toggle-weight').text(Drupal.t('Hide row weights')); 434 $('.tabledrag-toggle-weight').text(Drupal.t('Hide row weights'));
399 }; 435 };
407 * The row HTML element. 443 * The row HTML element.
408 * 444 *
409 * @return {object} 445 * @return {object}
410 * The table row settings. 446 * The table row settings.
411 */ 447 */
412 Drupal.tableDrag.prototype.rowSettings = function (group, row) { 448 Drupal.tableDrag.prototype.rowSettings = function(group, row) {
413 const field = $(row).find(`.${group}`); 449 const field = $(row).find(`.${group}`);
414 const tableSettingsGroup = this.tableSettings[group]; 450 const tableSettingsGroup = this.tableSettings[group];
415 // eslint-disable-next-line no-restricted-syntax 451 return Object.keys(tableSettingsGroup)
416 for (const delta in tableSettingsGroup) { 452 .map(delta => {
417 if (tableSettingsGroup.hasOwnProperty(delta)) {
418 const targetClass = tableSettingsGroup[delta].target; 453 const targetClass = tableSettingsGroup[delta].target;
454 let rowSettings;
419 if (field.is(`.${targetClass}`)) { 455 if (field.is(`.${targetClass}`)) {
420 // Return a copy of the row settings. 456 // Return a copy of the row settings.
421 const rowSettings = {}; 457 rowSettings = {};
422 // eslint-disable-next-line no-restricted-syntax 458 Object.keys(tableSettingsGroup[delta]).forEach(n => {
423 for (const n in tableSettingsGroup[delta]) { 459 rowSettings[n] = tableSettingsGroup[delta][n];
424 if (tableSettingsGroup[delta].hasOwnProperty(n)) { 460 });
425 rowSettings[n] = tableSettingsGroup[delta][n]; 461 }
426 } 462 return rowSettings;
427 } 463 })
428 return rowSettings; 464 .filter(rowSetting => rowSetting)[0];
429 }
430 }
431 }
432 }; 465 };
433 466
434 /** 467 /**
435 * Take an item and add event handlers to make it become draggable. 468 * Take an item and add event handlers to make it become draggable.
436 * 469 *
437 * @param {HTMLElement} item 470 * @param {HTMLElement} item
438 * The item to add event handlers to. 471 * The item to add event handlers to.
439 */ 472 */
440 Drupal.tableDrag.prototype.makeDraggable = function (item) { 473 Drupal.tableDrag.prototype.makeDraggable = function(item) {
441 const self = this; 474 const self = this;
442 const $item = $(item); 475 const $item = $(item);
443 // Add a class to the title link. 476 // Add a class to the title link.
444 $item.find('td:first-of-type').find('a').addClass('menu-item__link'); 477 $item
478 .find('td:first-of-type')
479 .find('a')
480 .addClass('menu-item__link');
445 // Create the handle. 481 // Create the handle.
446 const handle = $('<a href="#" class="tabledrag-handle"><div class="handle">&nbsp;</div></a>').attr('title', Drupal.t('Drag to re-order')); 482 const handle = $(
483 '<a href="#" class="tabledrag-handle"><div class="handle">&nbsp;</div></a>',
484 ).attr('title', Drupal.t('Drag to re-order'));
447 // Insert the handle after indentations (if any). 485 // Insert the handle after indentations (if any).
448 const $indentationLast = $item.find('td:first-of-type').find('.js-indentation').eq(-1); 486 const $indentationLast = $item
487 .find('td:first-of-type')
488 .find('.js-indentation')
489 .eq(-1);
449 if ($indentationLast.length) { 490 if ($indentationLast.length) {
450 $indentationLast.after(handle); 491 $indentationLast.after(handle);
451 // Update the total width of indentation in this entire table. 492 // Update the total width of indentation in this entire table.
452 self.indentCount = Math.max($item.find('.js-indentation').length, self.indentCount); 493 self.indentCount = Math.max(
453 } 494 $item.find('.js-indentation').length,
454 else { 495 self.indentCount,
455 $item.find('td').eq(0).prepend(handle); 496 );
456 } 497 } else {
457 498 $item
458 handle.on('mousedown touchstart pointerdown', (event) => { 499 .find('td')
500 .eq(0)
501 .prepend(handle);
502 }
503
504 handle.on('mousedown touchstart pointerdown', event => {
459 event.preventDefault(); 505 event.preventDefault();
460 if (event.originalEvent.type === 'touchstart') { 506 if (event.originalEvent.type === 'touchstart') {
461 event = event.originalEvent.touches[0]; 507 event = event.originalEvent.touches[0];
462 } 508 }
463 self.dragStart(event, self, item); 509 self.dragStart(event, self, item);
464 }); 510 });
465 511
466 // Prevent the anchor tag from jumping us to the top of the page. 512 // Prevent the anchor tag from jumping us to the top of the page.
467 handle.on('click', (e) => { 513 handle.on('click', e => {
468 e.preventDefault(); 514 e.preventDefault();
469 }); 515 });
470 516
471 // Set blur cleanup when a handle is focused. 517 // Set blur cleanup when a handle is focused.
472 handle.on('focus', () => { 518 handle.on('focus', () => {
473 self.safeBlur = true; 519 self.safeBlur = true;
474 }); 520 });
475 521
476 // On blur, fire the same function as a touchend/mouseup. This is used to 522 // On blur, fire the same function as a touchend/mouseup. This is used to
477 // update values after a row has been moved through the keyboard support. 523 // update values after a row has been moved through the keyboard support.
478 handle.on('blur', (event) => { 524 handle.on('blur', event => {
479 if (self.rowObject && self.safeBlur) { 525 if (self.rowObject && self.safeBlur) {
480 self.dropRow(event, self); 526 self.dropRow(event, self);
481 } 527 }
482 }); 528 });
483 529
484 // Add arrow-key support to the handle. 530 // Add arrow-key support to the handle.
485 handle.on('keydown', (event) => { 531 handle.on('keydown', event => {
486 // If a rowObject doesn't yet exist and this isn't the tab key. 532 // If a rowObject doesn't yet exist and this isn't the tab key.
487 if (event.keyCode !== 9 && !self.rowObject) { 533 if (event.keyCode !== 9 && !self.rowObject) {
488 self.rowObject = new self.row(item, 'keyboard', self.indentEnabled, self.maxDepth, true); 534 self.rowObject = new self.row(
535 item,
536 'keyboard',
537 self.indentEnabled,
538 self.maxDepth,
539 true,
540 );
489 } 541 }
490 542
491 let keyChange = false; 543 let keyChange = false;
492 let groupHeight; 544 let groupHeight;
493 545
504 556
505 // Up arrow. 557 // Up arrow.
506 case 38: 558 case 38:
507 // Safari up arrow. 559 // Safari up arrow.
508 case 63232: { 560 case 63232: {
509 let $previousRow = $(self.rowObject.element).prev('tr:first-of-type'); 561 let $previousRow = $(self.rowObject.element)
562 .prev('tr')
563 .eq(0);
510 let previousRow = $previousRow.get(0); 564 let previousRow = $previousRow.get(0);
511 while (previousRow && $previousRow.is(':hidden')) { 565 while (previousRow && $previousRow.is(':hidden')) {
512 $previousRow = $(previousRow).prev('tr:first-of-type'); 566 $previousRow = $(previousRow)
567 .prev('tr')
568 .eq(0);
513 previousRow = $previousRow.get(0); 569 previousRow = $previousRow.get(0);
514 } 570 }
515 if (previousRow) { 571 if (previousRow) {
516 // Do not allow the onBlur cleanup. 572 // Do not allow the onBlur cleanup.
517 self.safeBlur = false; 573 self.safeBlur = false;
519 keyChange = true; 575 keyChange = true;
520 576
521 if ($(item).is('.tabledrag-root')) { 577 if ($(item).is('.tabledrag-root')) {
522 // Swap with the previous top-level row. 578 // Swap with the previous top-level row.
523 groupHeight = 0; 579 groupHeight = 0;
524 while (previousRow && $previousRow.find('.js-indentation').length) { 580 while (
525 $previousRow = $(previousRow).prev('tr:first-of-type'); 581 previousRow &&
582 $previousRow.find('.js-indentation').length
583 ) {
584 $previousRow = $(previousRow)
585 .prev('tr')
586 .eq(0);
526 previousRow = $previousRow.get(0); 587 previousRow = $previousRow.get(0);
527 groupHeight += $previousRow.is(':hidden') ? 0 : previousRow.offsetHeight; 588 groupHeight += $previousRow.is(':hidden')
589 ? 0
590 : previousRow.offsetHeight;
528 } 591 }
529 if (previousRow) { 592 if (previousRow) {
530 self.rowObject.swap('before', previousRow); 593 self.rowObject.swap('before', previousRow);
531 // No need to check for indentation, 0 is the only valid one. 594 // No need to check for indentation, 0 is the only valid one.
532 window.scrollBy(0, -groupHeight); 595 window.scrollBy(0, -groupHeight);
533 } 596 }
534 } 597 } else if (
535 else if (self.table.tBodies[0].rows[0] !== previousRow || $previousRow.is('.draggable')) { 598 self.table.tBodies[0].rows[0] !== previousRow ||
599 $previousRow.is('.draggable')
600 ) {
536 // Swap with the previous row (unless previous row is the first 601 // Swap with the previous row (unless previous row is the first
537 // one and undraggable). 602 // one and undraggable).
538 self.rowObject.swap('before', previousRow); 603 self.rowObject.swap('before', previousRow);
539 self.rowObject.interval = null; 604 self.rowObject.interval = null;
540 self.rowObject.indent(0); 605 self.rowObject.indent(0);
555 620
556 // Down arrow. 621 // Down arrow.
557 case 40: 622 case 40:
558 // Safari down arrow. 623 // Safari down arrow.
559 case 63233: { 624 case 63233: {
560 let $nextRow = $(self.rowObject.group).eq(-1).next('tr:first-of-type'); 625 let $nextRow = $(self.rowObject.group)
626 .eq(-1)
627 .next('tr')
628 .eq(0);
561 let nextRow = $nextRow.get(0); 629 let nextRow = $nextRow.get(0);
562 while (nextRow && $nextRow.is(':hidden')) { 630 while (nextRow && $nextRow.is(':hidden')) {
563 $nextRow = $(nextRow).next('tr:first-of-type'); 631 $nextRow = $(nextRow)
632 .next('tr')
633 .eq(0);
564 nextRow = $nextRow.get(0); 634 nextRow = $nextRow.get(0);
565 } 635 }
566 if (nextRow) { 636 if (nextRow) {
567 // Do not allow the onBlur cleanup. 637 // Do not allow the onBlur cleanup.
568 self.safeBlur = false; 638 self.safeBlur = false;
570 keyChange = true; 640 keyChange = true;
571 641
572 if ($(item).is('.tabledrag-root')) { 642 if ($(item).is('.tabledrag-root')) {
573 // Swap with the next group (necessarily a top-level one). 643 // Swap with the next group (necessarily a top-level one).
574 groupHeight = 0; 644 groupHeight = 0;
575 const nextGroup = new self.row(nextRow, 'keyboard', self.indentEnabled, self.maxDepth, false); 645 const nextGroup = new self.row(
646 nextRow,
647 'keyboard',
648 self.indentEnabled,
649 self.maxDepth,
650 false,
651 );
576 if (nextGroup) { 652 if (nextGroup) {
577 $(nextGroup.group).each(function () { 653 $(nextGroup.group).each(function() {
578 groupHeight += $(this).is(':hidden') ? 0 : this.offsetHeight; 654 groupHeight += $(this).is(':hidden') ? 0 : this.offsetHeight;
579 }); 655 });
580 const nextGroupRow = $(nextGroup.group).eq(-1).get(0); 656 const nextGroupRow = $(nextGroup.group)
657 .eq(-1)
658 .get(0);
581 self.rowObject.swap('after', nextGroupRow); 659 self.rowObject.swap('after', nextGroupRow);
582 // No need to check for indentation, 0 is the only valid one. 660 // No need to check for indentation, 0 is the only valid one.
583 window.scrollBy(0, parseInt(groupHeight, 10)); 661 window.scrollBy(0, parseInt(groupHeight, 10));
584 } 662 }
585 } 663 } else {
586 else {
587 // Swap with the next row. 664 // Swap with the next row.
588 self.rowObject.swap('after', nextRow); 665 self.rowObject.swap('after', nextRow);
589 self.rowObject.interval = null; 666 self.rowObject.interval = null;
590 self.rowObject.indent(0); 667 self.rowObject.indent(0);
591 window.scrollBy(0, parseInt(item.offsetHeight, 10)); 668 window.scrollBy(0, parseInt(item.offsetHeight, 10));
619 696
620 // Compatibility addition, return false on keypress to prevent unwanted 697 // Compatibility addition, return false on keypress to prevent unwanted
621 // scrolling. IE and Safari will suppress scrolling on keydown, but all 698 // scrolling. IE and Safari will suppress scrolling on keydown, but all
622 // other browsers need to return false on keypress. 699 // other browsers need to return false on keypress.
623 // http://www.quirksmode.org/js/keys.html 700 // http://www.quirksmode.org/js/keys.html
624 handle.on('keypress', (event) => { 701 handle.on('keypress', event => {
625 /* eslint-disable no-fallthrough */ 702 /* eslint-disable no-fallthrough */
626 703
627 switch (event.keyCode) { 704 switch (event.keyCode) {
628 // Left arrow. 705 // Left arrow.
629 case 37: 706 case 37:
648 * @param {Drupal.tableDrag} self 725 * @param {Drupal.tableDrag} self
649 * The drag handle. 726 * The drag handle.
650 * @param {HTMLElement} item 727 * @param {HTMLElement} item
651 * The item that that is being dragged. 728 * The item that that is being dragged.
652 */ 729 */
653 Drupal.tableDrag.prototype.dragStart = function (event, self, item) { 730 Drupal.tableDrag.prototype.dragStart = function(event, self, item) {
654 // Create a new dragObject recording the pointer information. 731 // Create a new dragObject recording the pointer information.
655 self.dragObject = {}; 732 self.dragObject = {};
656 self.dragObject.initOffset = self.getPointerOffset(item, event); 733 self.dragObject.initOffset = self.getPointerOffset(item, event);
657 self.dragObject.initPointerCoords = self.pointerCoords(event); 734 self.dragObject.initPointerCoords = self.pointerCoords(event);
658 if (self.indentEnabled) { 735 if (self.indentEnabled) {
659 self.dragObject.indentPointerPos = self.dragObject.initPointerCoords; 736 self.dragObject.indentPointerPos = self.dragObject.initPointerCoords;
660 } 737 }
661 738
662 // If there's a lingering row object from the keyboard, remove its focus. 739 // If there's a lingering row object from the keyboard, remove its focus.
663 if (self.rowObject) { 740 if (self.rowObject) {
664 $(self.rowObject.element).find('a.tabledrag-handle').trigger('blur'); 741 $(self.rowObject.element)
742 .find('a.tabledrag-handle')
743 .trigger('blur');
665 } 744 }
666 745
667 // Create a new rowObject for manipulation of this row. 746 // Create a new rowObject for manipulation of this row.
668 self.rowObject = new self.row(item, 'pointer', self.indentEnabled, self.maxDepth, true); 747 self.rowObject = new self.row(
748 item,
749 'pointer',
750 self.indentEnabled,
751 self.maxDepth,
752 true,
753 );
669 754
670 // Save the position of the table. 755 // Save the position of the table.
671 self.table.topY = $(self.table).offset().top; 756 self.table.topY = $(self.table).offset().top;
672 self.table.bottomY = self.table.topY + self.table.offsetHeight; 757 self.table.bottomY = self.table.topY + self.table.offsetHeight;
673 758
690 * The tableDrag instance. 775 * The tableDrag instance.
691 * 776 *
692 * @return {bool|undefined} 777 * @return {bool|undefined}
693 * Undefined if no dragObject is defined, false otherwise. 778 * Undefined if no dragObject is defined, false otherwise.
694 */ 779 */
695 Drupal.tableDrag.prototype.dragRow = function (event, self) { 780 Drupal.tableDrag.prototype.dragRow = function(event, self) {
696 if (self.dragObject) { 781 if (self.dragObject) {
697 self.currentPointerCoords = self.pointerCoords(event); 782 self.currentPointerCoords = self.pointerCoords(event);
698 const y = self.currentPointerCoords.y - self.dragObject.initOffset.y; 783 const y = self.currentPointerCoords.y - self.dragObject.initOffset.y;
699 const x = self.currentPointerCoords.x - self.dragObject.initOffset.x; 784 const x = self.currentPointerCoords.x - self.dragObject.initOffset.x;
700 785
706 // Check if the window should be scrolled (and how fast). 791 // Check if the window should be scrolled (and how fast).
707 const scrollAmount = self.checkScroll(self.currentPointerCoords.y); 792 const scrollAmount = self.checkScroll(self.currentPointerCoords.y);
708 // Stop any current scrolling. 793 // Stop any current scrolling.
709 clearInterval(self.scrollInterval); 794 clearInterval(self.scrollInterval);
710 // Continue scrolling if the mouse has moved in the scroll direction. 795 // Continue scrolling if the mouse has moved in the scroll direction.
711 if ((scrollAmount > 0 && self.rowObject.direction === 'down') 796 if (
712 || (scrollAmount < 0 && self.rowObject.direction === 'up')) { 797 (scrollAmount > 0 && self.rowObject.direction === 'down') ||
798 (scrollAmount < 0 && self.rowObject.direction === 'up')
799 ) {
713 self.setScroll(scrollAmount); 800 self.setScroll(scrollAmount);
714 } 801 }
715 802
716 // If we have a valid target, perform the swap and restripe the table. 803 // If we have a valid target, perform the swap and restripe the table.
717 const currentRow = self.findDropTargetRow(x, y); 804 const currentRow = self.findDropTargetRow(x, y);
718 if (currentRow) { 805 if (currentRow) {
719 if (self.rowObject.direction === 'down') { 806 if (self.rowObject.direction === 'down') {
720 self.rowObject.swap('after', currentRow, self); 807 self.rowObject.swap('after', currentRow, self);
721 } 808 } else {
722 else {
723 self.rowObject.swap('before', currentRow, self); 809 self.rowObject.swap('before', currentRow, self);
724 } 810 }
725 if (self.striping === true) { 811 if (self.striping === true) {
726 self.restripeTable(); 812 self.restripeTable();
727 } 813 }
728 } 814 }
729 } 815 }
730 816
731 // Similar to row swapping, handle indentations. 817 // Similar to row swapping, handle indentations.
732 if (self.indentEnabled) { 818 if (self.indentEnabled) {
733 const xDiff = self.currentPointerCoords.x - self.dragObject.indentPointerPos.x; 819 const xDiff =
820 self.currentPointerCoords.x - self.dragObject.indentPointerPos.x;
734 // Set the number of indentations the pointer has been moved left or 821 // Set the number of indentations the pointer has been moved left or
735 // right. 822 // right.
736 const indentDiff = Math.round(xDiff / self.indentAmount); 823 const indentDiff = Math.round(xDiff / self.indentAmount);
737 // Indent the row with our estimated diff, which may be further 824 // Indent the row with our estimated diff, which may be further
738 // restricted according to the rows around this row. 825 // restricted according to the rows around this row.
739 const indentChange = self.rowObject.indent(indentDiff); 826 const indentChange = self.rowObject.indent(indentDiff);
740 // Update table and pointer indentations. 827 // Update table and pointer indentations.
741 self.dragObject.indentPointerPos.x += self.indentAmount * indentChange * self.rtl; 828 self.dragObject.indentPointerPos.x +=
829 self.indentAmount * indentChange * self.rtl;
742 self.indentCount = Math.max(self.indentCount, self.rowObject.indents); 830 self.indentCount = Math.max(self.indentCount, self.rowObject.indents);
743 } 831 }
744 832
745 return false; 833 return false;
746 } 834 }
752 * @param {jQuery.Event} event 840 * @param {jQuery.Event} event
753 * The pointer event. 841 * The pointer event.
754 * @param {Drupal.tableDrag} self 842 * @param {Drupal.tableDrag} self
755 * The tableDrag instance. 843 * The tableDrag instance.
756 */ 844 */
757 Drupal.tableDrag.prototype.dropRow = function (event, self) { 845 Drupal.tableDrag.prototype.dropRow = function(event, self) {
758 let droppedRow; 846 let droppedRow;
759 let $droppedRow; 847 let $droppedRow;
760 848
761 // Drop row functionality. 849 // Drop row functionality.
762 if (self.rowObject !== null) { 850 if (self.rowObject !== null) {
767 // Update the fields in the dropped row. 855 // Update the fields in the dropped row.
768 self.updateFields(droppedRow); 856 self.updateFields(droppedRow);
769 857
770 // If a setting exists for affecting the entire group, update all the 858 // If a setting exists for affecting the entire group, update all the
771 // fields in the entire dragged group. 859 // fields in the entire dragged group.
772 Object.keys(self.tableSettings || {}).forEach((group) => { 860 Object.keys(self.tableSettings || {}).forEach(group => {
773 const rowSettings = self.rowSettings(group, droppedRow); 861 const rowSettings = self.rowSettings(group, droppedRow);
774 if (rowSettings.relationship === 'group') { 862 if (rowSettings.relationship === 'group') {
775 Object.keys(self.rowObject.children || {}).forEach((n) => { 863 Object.keys(self.rowObject.children || {}).forEach(n => {
776 self.updateField(self.rowObject.children[n], group); 864 self.updateField(self.rowObject.children[n], group);
777 }); 865 });
778 } 866 }
779 }); 867 });
780 868
781 self.rowObject.markChanged(); 869 self.rowObject.markChanged();
782 if (self.changed === false) { 870 if (self.changed === false) {
783 $(Drupal.theme('tableDragChangedWarning')).insertBefore(self.table).hide().fadeIn('slow'); 871 $(Drupal.theme('tableDragChangedWarning'))
872 .insertBefore(self.table)
873 .hide()
874 .fadeIn('slow');
784 self.changed = true; 875 self.changed = true;
785 } 876 }
786 } 877 }
787 878
788 if (self.indentEnabled) { 879 if (self.indentEnabled) {
812 * The pointer event. 903 * The pointer event.
813 * 904 *
814 * @return {object} 905 * @return {object}
815 * An object with `x` and `y` keys indicating the position. 906 * An object with `x` and `y` keys indicating the position.
816 */ 907 */
817 Drupal.tableDrag.prototype.pointerCoords = function (event) { 908 Drupal.tableDrag.prototype.pointerCoords = function(event) {
818 if (event.pageX || event.pageY) { 909 if (event.pageX || event.pageY) {
819 return { x: event.pageX, y: event.pageY }; 910 return { x: event.pageX, y: event.pageY };
820 } 911 }
821 return { 912 return {
822 x: (event.clientX + document.body.scrollLeft) - document.body.clientLeft, 913 x: event.clientX + document.body.scrollLeft - document.body.clientLeft,
823 y: (event.clientY + document.body.scrollTop) - document.body.clientTop, 914 y: event.clientY + document.body.scrollTop - document.body.clientTop,
824 }; 915 };
825 }; 916 };
826 917
827 /** 918 /**
828 * Get the event offset from the target element. 919 * Get the event offset from the target element.
836 * The pointer event. 927 * The pointer event.
837 * 928 *
838 * @return {object} 929 * @return {object}
839 * An object with `x` and `y` keys indicating the position. 930 * An object with `x` and `y` keys indicating the position.
840 */ 931 */
841 Drupal.tableDrag.prototype.getPointerOffset = function (target, event) { 932 Drupal.tableDrag.prototype.getPointerOffset = function(target, event) {
842 const docPos = $(target).offset(); 933 const docPos = $(target).offset();
843 const pointerPos = this.pointerCoords(event); 934 const pointerPos = this.pointerCoords(event);
844 return { x: pointerPos.x - docPos.left, y: pointerPos.y - docPos.top }; 935 return { x: pointerPos.x - docPos.left, y: pointerPos.y - docPos.top };
845 }; 936 };
846 937
855 * The y coordinate of the mouse on the page (not the screen). 946 * The y coordinate of the mouse on the page (not the screen).
856 * 947 *
857 * @return {*} 948 * @return {*}
858 * The drop target row, if found. 949 * The drop target row, if found.
859 */ 950 */
860 Drupal.tableDrag.prototype.findDropTargetRow = function (x, y) { 951 Drupal.tableDrag.prototype.findDropTargetRow = function(x, y) {
861 const rows = $(this.table.tBodies[0].rows).not(':hidden'); 952 const rows = $(this.table.tBodies[0].rows).not(':hidden');
862 for (let n = 0; n < rows.length; n++) { 953 for (let n = 0; n < rows.length; n++) {
863 let row = rows[n]; 954 let row = rows[n];
864 let $row = $(row); 955 let $row = $(row);
865 const rowY = $row.offset().top; 956 const rowY = $row.offset().top;
874 else { 965 else {
875 rowHeight = parseInt(row.offsetHeight, 10) / 2; 966 rowHeight = parseInt(row.offsetHeight, 10) / 2;
876 } 967 }
877 968
878 // Because we always insert before, we need to offset the height a bit. 969 // Because we always insert before, we need to offset the height a bit.
879 if ((y > (rowY - rowHeight)) && (y < (rowY + rowHeight))) { 970 if (y > rowY - rowHeight && y < rowY + rowHeight) {
880 if (this.indentEnabled) { 971 if (this.indentEnabled) {
881 // Check that this row is not a child of the row being dragged. 972 // Check that this row is not a child of the row being dragged.
882 // eslint-disable-next-line no-restricted-syntax 973 if (
883 for (n in this.rowObject.group) { 974 Object.keys(this.rowObject.group).some(
884 if (this.rowObject.group[n] === row) { 975 o => this.rowObject.group[o] === row,
885 return null; 976 )
886 } 977 ) {
978 return null;
887 } 979 }
888 } 980 }
889 // Do not allow a row to be swapped with itself. 981 // Do not allow a row to be swapped with itself.
890 else if (row === this.rowObject.element) { 982 else if (row === this.rowObject.element) {
891 return null; 983 return null;
913 * After the row is dropped, update the table fields. 1005 * After the row is dropped, update the table fields.
914 * 1006 *
915 * @param {HTMLElement} changedRow 1007 * @param {HTMLElement} changedRow
916 * DOM object for the row that was just dropped. 1008 * DOM object for the row that was just dropped.
917 */ 1009 */
918 Drupal.tableDrag.prototype.updateFields = function (changedRow) { 1010 Drupal.tableDrag.prototype.updateFields = function(changedRow) {
919 Object.keys(this.tableSettings || {}).forEach((group) => { 1011 Object.keys(this.tableSettings || {}).forEach(group => {
920 // Each group may have a different setting for relationship, so we find 1012 // Each group may have a different setting for relationship, so we find
921 // the source rows for each separately. 1013 // the source rows for each separately.
922 this.updateField(changedRow, group); 1014 this.updateField(changedRow, group);
923 }); 1015 });
924 }; 1016 };
929 * @param {HTMLElement} changedRow 1021 * @param {HTMLElement} changedRow
930 * DOM object for the row that was just dropped. 1022 * DOM object for the row that was just dropped.
931 * @param {string} group 1023 * @param {string} group
932 * The settings group on which field updates will occur. 1024 * The settings group on which field updates will occur.
933 */ 1025 */
934 Drupal.tableDrag.prototype.updateField = function (changedRow, group) { 1026 Drupal.tableDrag.prototype.updateField = function(changedRow, group) {
935 let rowSettings = this.rowSettings(group, changedRow); 1027 let rowSettings = this.rowSettings(group, changedRow);
936 const $changedRow = $(changedRow); 1028 const $changedRow = $(changedRow);
937 let sourceRow; 1029 let sourceRow;
938 let $previousRow; 1030 let $previousRow;
939 let previousRow; 1031 let previousRow;
940 let useSibling; 1032 let useSibling;
941 // Set the row as its own target. 1033 // Set the row as its own target.
942 if (rowSettings.relationship === 'self' || rowSettings.relationship === 'group') { 1034 if (
1035 rowSettings.relationship === 'self' ||
1036 rowSettings.relationship === 'group'
1037 ) {
943 sourceRow = changedRow; 1038 sourceRow = changedRow;
944 } 1039 }
945 // Siblings are easy, check previous and next rows. 1040 // Siblings are easy, check previous and next rows.
946 else if (rowSettings.relationship === 'sibling') { 1041 else if (rowSettings.relationship === 'sibling') {
947 $previousRow = $changedRow.prev('tr:first-of-type'); 1042 $previousRow = $changedRow.prev('tr:first-of-type');
948 previousRow = $previousRow.get(0); 1043 previousRow = $previousRow.get(0);
949 const $nextRow = $changedRow.next('tr:first-of-type'); 1044 const $nextRow = $changedRow.next('tr:first-of-type');
950 const nextRow = $nextRow.get(0); 1045 const nextRow = $nextRow.get(0);
951 sourceRow = changedRow; 1046 sourceRow = changedRow;
952 if ($previousRow.is('.draggable') && $previousRow.find(`.${group}`).length) { 1047 if (
1048 $previousRow.is('.draggable') &&
1049 $previousRow.find(`.${group}`).length
1050 ) {
953 if (this.indentEnabled) { 1051 if (this.indentEnabled) {
954 if ($previousRow.find('.js-indentations').length === $changedRow.find('.js-indentations').length) { 1052 if (
1053 $previousRow.find('.js-indentations').length ===
1054 $changedRow.find('.js-indentations').length
1055 ) {
955 sourceRow = previousRow; 1056 sourceRow = previousRow;
956 } 1057 }
957 } 1058 } else {
958 else {
959 sourceRow = previousRow; 1059 sourceRow = previousRow;
960 } 1060 }
961 } 1061 } else if (
962 else if ($nextRow.is('.draggable') && $nextRow.find(`.${group}`).length) { 1062 $nextRow.is('.draggable') &&
1063 $nextRow.find(`.${group}`).length
1064 ) {
963 if (this.indentEnabled) { 1065 if (this.indentEnabled) {
964 if ($nextRow.find('.js-indentations').length === $changedRow.find('.js-indentations').length) { 1066 if (
1067 $nextRow.find('.js-indentations').length ===
1068 $changedRow.find('.js-indentations').length
1069 ) {
965 sourceRow = nextRow; 1070 sourceRow = nextRow;
966 } 1071 }
967 } 1072 } else {
968 else {
969 sourceRow = nextRow; 1073 sourceRow = nextRow;
970 } 1074 }
971 } 1075 }
972 } 1076 }
973 // Parents, look up the tree until we find a field not in this group. 1077 // Parents, look up the tree until we find a field not in this group.
974 // Go up as many parents as indentations in the changed row. 1078 // Go up as many parents as indentations in the changed row.
975 else if (rowSettings.relationship === 'parent') { 1079 else if (rowSettings.relationship === 'parent') {
976 $previousRow = $changedRow.prev('tr'); 1080 $previousRow = $changedRow.prev('tr');
977 previousRow = $previousRow; 1081 previousRow = $previousRow;
978 while ($previousRow.length && $previousRow.find('.js-indentation').length >= this.rowObject.indents) { 1082 while (
1083 $previousRow.length &&
1084 $previousRow.find('.js-indentation').length >= this.rowObject.indents
1085 ) {
979 $previousRow = $previousRow.prev('tr'); 1086 $previousRow = $previousRow.prev('tr');
980 previousRow = $previousRow; 1087 previousRow = $previousRow;
981 } 1088 }
982 // If we found a row. 1089 // If we found a row.
983 if ($previousRow.length) { 1090 if ($previousRow.length) {
987 // a parent, meaning this item has been placed at the root level. 1094 // a parent, meaning this item has been placed at the root level.
988 else { 1095 else {
989 // Use the first row in the table as source, because it's guaranteed to 1096 // Use the first row in the table as source, because it's guaranteed to
990 // be at the root level. Find the first item, then compare this row 1097 // be at the root level. Find the first item, then compare this row
991 // against it as a sibling. 1098 // against it as a sibling.
992 sourceRow = $(this.table).find('tr.draggable:first-of-type').get(0); 1099 sourceRow = $(this.table)
1100 .find('tr.draggable:first-of-type')
1101 .get(0);
993 if (sourceRow === this.rowObject.element) { 1102 if (sourceRow === this.rowObject.element) {
994 sourceRow = $(this.rowObject.group[this.rowObject.group.length - 1]).next('tr.draggable').get(0); 1103 sourceRow = $(this.rowObject.group[this.rowObject.group.length - 1])
1104 .next('tr.draggable')
1105 .get(0);
995 } 1106 }
996 useSibling = true; 1107 useSibling = true;
997 } 1108 }
998 } 1109 }
999 1110
1017 const sourceClass = `.${rowSettings.source}`; 1128 const sourceClass = `.${rowSettings.source}`;
1018 const sourceElement = $(sourceClass, sourceRow).get(0); 1129 const sourceElement = $(sourceClass, sourceRow).get(0);
1019 switch (rowSettings.action) { 1130 switch (rowSettings.action) {
1020 case 'depth': 1131 case 'depth':
1021 // Get the depth of the target row. 1132 // Get the depth of the target row.
1022 targetElement.value = $(sourceElement).closest('tr').find('.js-indentation').length; 1133 targetElement.value = $(sourceElement)
1134 .closest('tr')
1135 .find('.js-indentation').length;
1023 break; 1136 break;
1024 1137
1025 case 'match': 1138 case 'match':
1026 // Update the value. 1139 // Update the value.
1027 targetElement.value = sourceElement.value; 1140 targetElement.value = sourceElement.value;
1030 case 'order': { 1143 case 'order': {
1031 const siblings = this.rowObject.findSiblings(rowSettings); 1144 const siblings = this.rowObject.findSiblings(rowSettings);
1032 if ($(targetElement).is('select')) { 1145 if ($(targetElement).is('select')) {
1033 // Get a list of acceptable values. 1146 // Get a list of acceptable values.
1034 const values = []; 1147 const values = [];
1035 $(targetElement).find('option').each(function () { 1148 $(targetElement)
1036 values.push(this.value); 1149 .find('option')
1037 }); 1150 .each(function() {
1151 values.push(this.value);
1152 });
1038 const maxVal = values[values.length - 1]; 1153 const maxVal = values[values.length - 1];
1039 // Populate the values in the siblings. 1154 // Populate the values in the siblings.
1040 $(siblings).find(targetClass).each(function () { 1155 $(siblings)
1041 // If there are more items than possible values, assign the 1156 .find(targetClass)
1042 // maximum value to the row. 1157 .each(function() {
1043 if (values.length > 0) { 1158 // If there are more items than possible values, assign the
1044 this.value = values.shift(); 1159 // maximum value to the row.
1045 } 1160 if (values.length > 0) {
1046 else { 1161 this.value = values.shift();
1047 this.value = maxVal; 1162 } else {
1048 } 1163 this.value = maxVal;
1049 }); 1164 }
1050 } 1165 });
1051 else { 1166 } else {
1052 // Assume a numeric input field. 1167 // Assume a numeric input field.
1053 let weight = parseInt($(siblings[0]).find(targetClass).val(), 10) || 0; 1168 let weight =
1054 $(siblings).find(targetClass).each(function () { 1169 parseInt(
1055 this.value = weight; 1170 $(siblings[0])
1056 weight++; 1171 .find(targetClass)
1057 }); 1172 .val(),
1173 10,
1174 ) || 0;
1175 $(siblings)
1176 .find(targetClass)
1177 .each(function() {
1178 this.value = weight;
1179 weight++;
1180 });
1058 } 1181 }
1059 break; 1182 break;
1060 } 1183 }
1061 } 1184 }
1062 } 1185 }
1074 * @param {HTMLElement} targetRow 1197 * @param {HTMLElement} targetRow
1075 * The element for the target row. 1198 * The element for the target row.
1076 * @param {string} group 1199 * @param {string} group
1077 * The group selector. 1200 * The group selector.
1078 */ 1201 */
1079 Drupal.tableDrag.prototype.copyDragClasses = function (sourceRow, targetRow, group) { 1202 Drupal.tableDrag.prototype.copyDragClasses = function(
1203 sourceRow,
1204 targetRow,
1205 group,
1206 ) {
1080 const sourceElement = $(sourceRow).find(`.${group}`); 1207 const sourceElement = $(sourceRow).find(`.${group}`);
1081 const targetElement = $(targetRow).find(`.${group}`); 1208 const targetElement = $(targetRow).find(`.${group}`);
1082 if (sourceElement.length && targetElement.length) { 1209 if (sourceElement.length && targetElement.length) {
1083 targetElement[0].className = sourceElement[0].className; 1210 targetElement[0].className = sourceElement[0].className;
1084 } 1211 }
1091 * The Y position of the cursor. 1218 * The Y position of the cursor.
1092 * 1219 *
1093 * @return {number} 1220 * @return {number}
1094 * The suggested scroll. 1221 * The suggested scroll.
1095 */ 1222 */
1096 Drupal.tableDrag.prototype.checkScroll = function (cursorY) { 1223 Drupal.tableDrag.prototype.checkScroll = function(cursorY) {
1097 const de = document.documentElement; 1224 const de = document.documentElement;
1098 const b = document.body; 1225 const b = document.body;
1099 1226
1100 const windowHeight = window.innerHeight || (de.clientHeight && de.clientWidth !== 0 ? de.clientHeight : b.offsetHeight); 1227 const windowHeight =
1228 window.innerHeight ||
1229 (de.clientHeight && de.clientWidth !== 0
1230 ? de.clientHeight
1231 : b.offsetHeight);
1101 this.windowHeight = windowHeight; 1232 this.windowHeight = windowHeight;
1102 let scrollY; 1233 let scrollY;
1103 if (document.all) { 1234 if (document.all) {
1104 scrollY = !de.scrollTop ? b.scrollTop : de.scrollTop; 1235 scrollY = !de.scrollTop ? b.scrollTop : de.scrollTop;
1105 } 1236 } else {
1106 else {
1107 scrollY = window.pageYOffset ? window.pageYOffset : window.scrollY; 1237 scrollY = window.pageYOffset ? window.pageYOffset : window.scrollY;
1108 } 1238 }
1109 this.scrollY = scrollY; 1239 this.scrollY = scrollY;
1110 const trigger = this.scrollSettings.trigger; 1240 const trigger = this.scrollSettings.trigger;
1111 let delta = 0; 1241 let delta = 0;
1112 1242
1113 // Return a scroll speed relative to the edge of the screen. 1243 // Return a scroll speed relative to the edge of the screen.
1114 if (cursorY - scrollY > windowHeight - trigger) { 1244 if (cursorY - scrollY > windowHeight - trigger) {
1115 delta = trigger / ((windowHeight + scrollY) - cursorY); 1245 delta = trigger / (windowHeight + scrollY - cursorY);
1116 delta = (delta > 0 && delta < trigger) ? delta : trigger; 1246 delta = delta > 0 && delta < trigger ? delta : trigger;
1117 return delta * this.scrollSettings.amount; 1247 return delta * this.scrollSettings.amount;
1118 } 1248 }
1119 else if (cursorY - scrollY < trigger) { 1249 if (cursorY - scrollY < trigger) {
1120 delta = trigger / (cursorY - scrollY); 1250 delta = trigger / (cursorY - scrollY);
1121 delta = (delta > 0 && delta < trigger) ? delta : trigger; 1251 delta = delta > 0 && delta < trigger ? delta : trigger;
1122 return -delta * this.scrollSettings.amount; 1252 return -delta * this.scrollSettings.amount;
1123 } 1253 }
1124 }; 1254 };
1125 1255
1126 /** 1256 /**
1127 * Set the scroll for the table. 1257 * Set the scroll for the table.
1128 * 1258 *
1129 * @param {number} scrollAmount 1259 * @param {number} scrollAmount
1130 * The amount of scroll to apply to the window. 1260 * The amount of scroll to apply to the window.
1131 */ 1261 */
1132 Drupal.tableDrag.prototype.setScroll = function (scrollAmount) { 1262 Drupal.tableDrag.prototype.setScroll = function(scrollAmount) {
1133 const self = this; 1263 const self = this;
1134 1264
1135 this.scrollInterval = setInterval(() => { 1265 this.scrollInterval = setInterval(() => {
1136 // Update the scroll values stored in the object. 1266 // Update the scroll values stored in the object.
1137 self.checkScroll(self.currentPointerCoords.y); 1267 self.checkScroll(self.currentPointerCoords.y);
1138 const aboveTable = self.scrollY > self.table.topY; 1268 const aboveTable = self.scrollY > self.table.topY;
1139 const belowTable = self.scrollY + self.windowHeight < self.table.bottomY; 1269 const belowTable = self.scrollY + self.windowHeight < self.table.bottomY;
1140 if ((scrollAmount > 0 && belowTable) 1270 if (
1141 || (scrollAmount < 0 && aboveTable)) { 1271 (scrollAmount > 0 && belowTable) ||
1272 (scrollAmount < 0 && aboveTable)
1273 ) {
1142 window.scrollBy(0, scrollAmount); 1274 window.scrollBy(0, scrollAmount);
1143 } 1275 }
1144 }, this.scrollSettings.interval); 1276 }, this.scrollSettings.interval);
1145 }; 1277 };
1146 1278
1147 /** 1279 /**
1148 * Command to restripe table properly. 1280 * Command to restripe table properly.
1149 */ 1281 */
1150 Drupal.tableDrag.prototype.restripeTable = function () { 1282 Drupal.tableDrag.prototype.restripeTable = function() {
1151 // :even and :odd are reversed because jQuery counts from 0 and 1283 // :even and :odd are reversed because jQuery counts from 0 and
1152 // we count from 1, so we're out of sync. 1284 // we count from 1, so we're out of sync.
1153 // Match immediate children of the parent element to allow nesting. 1285 // Match immediate children of the parent element to allow nesting.
1154 $(this.table) 1286 $(this.table)
1155 .find('> tbody > tr.draggable, > tr.draggable') 1287 .find('> tbody > tr.draggable, > tr.draggable')
1167 * Stub function. Allows a custom handler when a row begins dragging. 1299 * Stub function. Allows a custom handler when a row begins dragging.
1168 * 1300 *
1169 * @return {null} 1301 * @return {null}
1170 * Returns null when the stub function is used. 1302 * Returns null when the stub function is used.
1171 */ 1303 */
1172 Drupal.tableDrag.prototype.onDrag = function () { 1304 Drupal.tableDrag.prototype.onDrag = function() {
1173 return null; 1305 return null;
1174 }; 1306 };
1175 1307
1176 /** 1308 /**
1177 * Stub function. Allows a custom handler when a row is dropped. 1309 * Stub function. Allows a custom handler when a row is dropped.
1178 * 1310 *
1179 * @return {null} 1311 * @return {null}
1180 * Returns null when the stub function is used. 1312 * Returns null when the stub function is used.
1181 */ 1313 */
1182 Drupal.tableDrag.prototype.onDrop = function () { 1314 Drupal.tableDrag.prototype.onDrop = function() {
1183 return null; 1315 return null;
1184 }; 1316 };
1185 1317
1186 /** 1318 /**
1187 * Constructor to make a new object to manipulate a table row. 1319 * Constructor to make a new object to manipulate a table row.
1197 * The maximum amount of indentations this row may contain. 1329 * The maximum amount of indentations this row may contain.
1198 * @param {bool} addClasses 1330 * @param {bool} addClasses
1199 * Whether we want to add classes to this row to indicate child 1331 * Whether we want to add classes to this row to indicate child
1200 * relationships. 1332 * relationships.
1201 */ 1333 */
1202 Drupal.tableDrag.prototype.row = function (tableRow, method, indentEnabled, maxDepth, addClasses) { 1334 Drupal.tableDrag.prototype.row = function(
1335 tableRow,
1336 method,
1337 indentEnabled,
1338 maxDepth,
1339 addClasses,
1340 ) {
1203 const $tableRow = $(tableRow); 1341 const $tableRow = $(tableRow);
1204 1342
1205 this.element = tableRow; 1343 this.element = tableRow;
1206 this.method = method; 1344 this.method = method;
1207 this.group = [tableRow]; 1345 this.group = [tableRow];
1216 this.indents = $tableRow.find('.js-indentation').length; 1354 this.indents = $tableRow.find('.js-indentation').length;
1217 this.children = this.findChildren(addClasses); 1355 this.children = this.findChildren(addClasses);
1218 this.group = $.merge(this.group, this.children); 1356 this.group = $.merge(this.group, this.children);
1219 // Find the depth of this entire group. 1357 // Find the depth of this entire group.
1220 for (let n = 0; n < this.group.length; n++) { 1358 for (let n = 0; n < this.group.length; n++) {
1221 this.groupDepth = Math.max($(this.group[n]).find('.js-indentation').length, this.groupDepth); 1359 this.groupDepth = Math.max(
1360 $(this.group[n]).find('.js-indentation').length,
1361 this.groupDepth,
1362 );
1222 } 1363 }
1223 } 1364 }
1224 }; 1365 };
1225 1366
1226 /** 1367 /**
1231 * relationships. 1372 * relationships.
1232 * 1373 *
1233 * @return {Array} 1374 * @return {Array}
1234 * An array of children of the row. 1375 * An array of children of the row.
1235 */ 1376 */
1236 Drupal.tableDrag.prototype.row.prototype.findChildren = function (addClasses) { 1377 Drupal.tableDrag.prototype.row.prototype.findChildren = function(addClasses) {
1237 const parentIndentation = this.indents; 1378 const parentIndentation = this.indents;
1238 let currentRow = $(this.element, this.table).next('tr.draggable'); 1379 let currentRow = $(this.element, this.table).next('tr.draggable');
1239 const rows = []; 1380 const rows = [];
1240 let child = 0; 1381 let child = 0;
1241 1382
1242 function rowIndentation(indentNum, el) { 1383 function rowIndentation(indentNum, el) {
1243 const self = $(el); 1384 const self = $(el);
1244 if (child === 1 && (indentNum === parentIndentation)) { 1385 if (child === 1 && indentNum === parentIndentation) {
1245 self.addClass('tree-child-first'); 1386 self.addClass('tree-child-first');
1246 } 1387 }
1247 if (indentNum === parentIndentation) { 1388 if (indentNum === parentIndentation) {
1248 self.addClass('tree-child'); 1389 self.addClass('tree-child');
1249 } 1390 } else if (indentNum > parentIndentation) {
1250 else if (indentNum > parentIndentation) {
1251 self.addClass('tree-child-horizontal'); 1391 self.addClass('tree-child-horizontal');
1252 } 1392 }
1253 } 1393 }
1254 1394
1255 while (currentRow.length) { 1395 while (currentRow.length) {
1258 child++; 1398 child++;
1259 rows.push(currentRow[0]); 1399 rows.push(currentRow[0]);
1260 if (addClasses) { 1400 if (addClasses) {
1261 currentRow.find('.js-indentation').each(rowIndentation); 1401 currentRow.find('.js-indentation').each(rowIndentation);
1262 } 1402 }
1263 } 1403 } else {
1264 else {
1265 break; 1404 break;
1266 } 1405 }
1267 currentRow = currentRow.next('tr.draggable'); 1406 currentRow = currentRow.next('tr.draggable');
1268 } 1407 }
1269 if (addClasses && rows.length) { 1408 if (addClasses && rows.length) {
1270 $(rows[rows.length - 1]).find(`.js-indentation:nth-child(${parentIndentation + 1})`).addClass('tree-child-last'); 1409 $(rows[rows.length - 1])
1410 .find(`.js-indentation:nth-child(${parentIndentation + 1})`)
1411 .addClass('tree-child-last');
1271 } 1412 }
1272 return rows; 1413 return rows;
1273 }; 1414 };
1274 1415
1275 /** 1416 /**
1279 * DOM object for the row being considered for swapping. 1420 * DOM object for the row being considered for swapping.
1280 * 1421 *
1281 * @return {bool} 1422 * @return {bool}
1282 * Whether the swap is a valid swap or not. 1423 * Whether the swap is a valid swap or not.
1283 */ 1424 */
1284 Drupal.tableDrag.prototype.row.prototype.isValidSwap = function (row) { 1425 Drupal.tableDrag.prototype.row.prototype.isValidSwap = function(row) {
1285 const $row = $(row); 1426 const $row = $(row);
1286 if (this.indentEnabled) { 1427 if (this.indentEnabled) {
1287 let prevRow; 1428 let prevRow;
1288 let nextRow; 1429 let nextRow;
1289 if (this.direction === 'down') { 1430 if (this.direction === 'down') {
1290 prevRow = row; 1431 prevRow = row;
1291 nextRow = $row.next('tr').get(0); 1432 nextRow = $row.next('tr').get(0);
1292 } 1433 } else {
1293 else {
1294 prevRow = $row.prev('tr').get(0); 1434 prevRow = $row.prev('tr').get(0);
1295 nextRow = row; 1435 nextRow = row;
1296 } 1436 }
1297 this.interval = this.validIndentInterval(prevRow, nextRow); 1437 this.interval = this.validIndentInterval(prevRow, nextRow);
1298 1438
1316 * @param {string} position 1456 * @param {string} position
1317 * Whether the swap will occur 'before' or 'after' the given row. 1457 * Whether the swap will occur 'before' or 'after' the given row.
1318 * @param {HTMLElement} row 1458 * @param {HTMLElement} row
1319 * DOM element what will be swapped with the row group. 1459 * DOM element what will be swapped with the row group.
1320 */ 1460 */
1321 Drupal.tableDrag.prototype.row.prototype.swap = function (position, row) { 1461 Drupal.tableDrag.prototype.row.prototype.swap = function(position, row) {
1322 // Makes sure only DOM object are passed to Drupal.detachBehaviors(). 1462 // Makes sure only DOM object are passed to Drupal.detachBehaviors().
1323 this.group.forEach((row) => { 1463 this.group.forEach(row => {
1324 Drupal.detachBehaviors(row, drupalSettings, 'move'); 1464 Drupal.detachBehaviors(row, drupalSettings, 'move');
1325 }); 1465 });
1326 $(row)[position](this.group); 1466 $(row)[position](this.group);
1327 // Makes sure only DOM object are passed to Drupal.attachBehaviors()s. 1467 // Makes sure only DOM object are passed to Drupal.attachBehaviors()s.
1328 this.group.forEach((row) => { 1468 this.group.forEach(row => {
1329 Drupal.attachBehaviors(row, drupalSettings); 1469 Drupal.attachBehaviors(row, drupalSettings);
1330 }); 1470 });
1331 this.changed = true; 1471 this.changed = true;
1332 this.onSwap(row); 1472 this.onSwap(row);
1333 }; 1473 };
1344 * 1484 *
1345 * @return {object} 1485 * @return {object}
1346 * An object with the keys `min` and `max` to indicate the valid indent 1486 * An object with the keys `min` and `max` to indicate the valid indent
1347 * interval. 1487 * interval.
1348 */ 1488 */
1349 Drupal.tableDrag.prototype.row.prototype.validIndentInterval = function (prevRow, nextRow) { 1489 Drupal.tableDrag.prototype.row.prototype.validIndentInterval = function(
1490 prevRow,
1491 nextRow,
1492 ) {
1350 const $prevRow = $(prevRow); 1493 const $prevRow = $(prevRow);
1351 let maxIndent; 1494 let maxIndent;
1352 1495
1353 // Minimum indentation: 1496 // Minimum indentation:
1354 // Do not orphan the next row. 1497 // Do not orphan the next row.
1355 const minIndent = nextRow ? $(nextRow).find('.js-indentation').length : 0; 1498 const minIndent = nextRow ? $(nextRow).find('.js-indentation').length : 0;
1356 1499
1357 // Maximum indentation: 1500 // Maximum indentation:
1358 if (!prevRow || $prevRow.is(':not(.draggable)') || $(this.element).is('.tabledrag-root')) { 1501 if (
1502 !prevRow ||
1503 $prevRow.is(':not(.draggable)') ||
1504 $(this.element).is('.tabledrag-root')
1505 ) {
1359 // Do not indent: 1506 // Do not indent:
1360 // - the first row in the table, 1507 // - the first row in the table,
1361 // - rows dragged below a non-draggable row, 1508 // - rows dragged below a non-draggable row,
1362 // - 'root' rows. 1509 // - 'root' rows.
1363 maxIndent = 0; 1510 maxIndent = 0;
1364 } 1511 } else {
1365 else {
1366 // Do not go deeper than as a child of the previous row. 1512 // Do not go deeper than as a child of the previous row.
1367 maxIndent = $prevRow.find('.js-indentation').length + ($prevRow.is('.tabledrag-leaf') ? 0 : 1); 1513 maxIndent =
1514 $prevRow.find('.js-indentation').length +
1515 ($prevRow.is('.tabledrag-leaf') ? 0 : 1);
1368 // Limit by the maximum allowed depth for the table. 1516 // Limit by the maximum allowed depth for the table.
1369 if (this.maxDepth) { 1517 if (this.maxDepth) {
1370 maxIndent = Math.min(maxIndent, this.maxDepth - (this.groupDepth - this.indents)); 1518 maxIndent = Math.min(
1519 maxIndent,
1520 this.maxDepth - (this.groupDepth - this.indents),
1521 );
1371 } 1522 }
1372 } 1523 }
1373 1524
1374 return { min: minIndent, max: maxIndent }; 1525 return { min: minIndent, max: maxIndent };
1375 }; 1526 };
1383 * indentation level for the row. 1534 * indentation level for the row.
1384 * 1535 *
1385 * @return {number} 1536 * @return {number}
1386 * The number of indentations applied. 1537 * The number of indentations applied.
1387 */ 1538 */
1388 Drupal.tableDrag.prototype.row.prototype.indent = function (indentDiff) { 1539 Drupal.tableDrag.prototype.row.prototype.indent = function(indentDiff) {
1389 const $group = $(this.group); 1540 const $group = $(this.group);
1390 // Determine the valid indentations interval if not available yet. 1541 // Determine the valid indentations interval if not available yet.
1391 if (!this.interval) { 1542 if (!this.interval) {
1392 const prevRow = $(this.element).prev('tr').get(0); 1543 const prevRow = $(this.element)
1393 const nextRow = $group.eq(-1).next('tr').get(0); 1544 .prev('tr')
1545 .get(0);
1546 const nextRow = $group
1547 .eq(-1)
1548 .next('tr')
1549 .get(0);
1394 this.interval = this.validIndentInterval(prevRow, nextRow); 1550 this.interval = this.validIndentInterval(prevRow, nextRow);
1395 } 1551 }
1396 1552
1397 // Adjust to the nearest valid indentation. 1553 // Adjust to the nearest valid indentation.
1398 let indent = this.indents + indentDiff; 1554 let indent = this.indents + indentDiff;
1403 for (let n = 1; n <= Math.abs(indentDiff); n++) { 1559 for (let n = 1; n <= Math.abs(indentDiff); n++) {
1404 // Add or remove indentations. 1560 // Add or remove indentations.
1405 if (indentDiff < 0) { 1561 if (indentDiff < 0) {
1406 $group.find('.js-indentation:first-of-type').remove(); 1562 $group.find('.js-indentation:first-of-type').remove();
1407 this.indents--; 1563 this.indents--;
1408 } 1564 } else {
1409 else { 1565 $group
1410 $group.find('td:first-of-type').prepend(Drupal.theme('tableDragIndentation')); 1566 .find('td:first-of-type')
1567 .prepend(Drupal.theme('tableDragIndentation'));
1411 this.indents++; 1568 this.indents++;
1412 } 1569 }
1413 } 1570 }
1414 if (indentDiff) { 1571 if (indentDiff) {
1415 // Update indentation for this row. 1572 // Update indentation for this row.
1431 * The field settings we're using to identify what constitutes a sibling. 1588 * The field settings we're using to identify what constitutes a sibling.
1432 * 1589 *
1433 * @return {Array} 1590 * @return {Array}
1434 * An array of siblings. 1591 * An array of siblings.
1435 */ 1592 */
1436 Drupal.tableDrag.prototype.row.prototype.findSiblings = function (rowSettings) { 1593 Drupal.tableDrag.prototype.row.prototype.findSiblings = function(
1594 rowSettings,
1595 ) {
1437 const siblings = []; 1596 const siblings = [];
1438 const directions = ['prev', 'next']; 1597 const directions = ['prev', 'next'];
1439 const rowIndentation = this.indents; 1598 const rowIndentation = this.indents;
1440 let checkRowIndentation; 1599 let checkRowIndentation;
1441 for (let d = 0; d < directions.length; d++) { 1600 for (let d = 0; d < directions.length; d++) {
1447 // that this row has the same level of indentation. 1606 // that this row has the same level of indentation.
1448 if (this.indentEnabled) { 1607 if (this.indentEnabled) {
1449 checkRowIndentation = checkRow.find('.js-indentation').length; 1608 checkRowIndentation = checkRow.find('.js-indentation').length;
1450 } 1609 }
1451 1610
1452 if (!(this.indentEnabled) || (checkRowIndentation === rowIndentation)) { 1611 if (!this.indentEnabled || checkRowIndentation === rowIndentation) {
1453 siblings.push(checkRow[0]); 1612 siblings.push(checkRow[0]);
1454 } 1613 } else if (checkRowIndentation < rowIndentation) {
1455 else if (checkRowIndentation < rowIndentation) {
1456 // No need to keep looking for siblings when we get to a parent. 1614 // No need to keep looking for siblings when we get to a parent.
1457 break; 1615 break;
1458 } 1616 }
1459 } 1617 } else {
1460 else {
1461 break; 1618 break;
1462 } 1619 }
1463 checkRow = checkRow[directions[d]](); 1620 checkRow = checkRow[directions[d]]();
1464 } 1621 }
1465 // Since siblings are added in reverse order for previous, reverse the 1622 // Since siblings are added in reverse order for previous, reverse the
1473 }; 1630 };
1474 1631
1475 /** 1632 /**
1476 * Remove indentation helper classes from the current row group. 1633 * Remove indentation helper classes from the current row group.
1477 */ 1634 */
1478 Drupal.tableDrag.prototype.row.prototype.removeIndentClasses = function () { 1635 Drupal.tableDrag.prototype.row.prototype.removeIndentClasses = function() {
1479 Object.keys(this.children || {}).forEach((n) => { 1636 Object.keys(this.children || {}).forEach(n => {
1480 $(this.children[n]).find('.js-indentation') 1637 $(this.children[n])
1638 .find('.js-indentation')
1481 .removeClass('tree-child') 1639 .removeClass('tree-child')
1482 .removeClass('tree-child-first') 1640 .removeClass('tree-child-first')
1483 .removeClass('tree-child-last') 1641 .removeClass('tree-child-last')
1484 .removeClass('tree-child-horizontal'); 1642 .removeClass('tree-child-horizontal');
1485 }); 1643 });
1486 }; 1644 };
1487 1645
1488 /** 1646 /**
1489 * Add an asterisk or other marker to the changed row. 1647 * Add an asterisk or other marker to the changed row.
1490 */ 1648 */
1491 Drupal.tableDrag.prototype.row.prototype.markChanged = function () { 1649 Drupal.tableDrag.prototype.row.prototype.markChanged = function() {
1492 const marker = Drupal.theme('tableDragChangedMarker'); 1650 const marker = Drupal.theme('tableDragChangedMarker');
1493 const cell = $(this.element).find('td:first-of-type'); 1651 const cell = $(this.element).find('td:first-of-type');
1494 if (cell.find('abbr.tabledrag-changed').length === 0) { 1652 if (cell.find('abbr.tabledrag-changed').length === 0) {
1495 cell.append(marker); 1653 cell.append(marker);
1496 } 1654 }
1500 * Stub function. Allows a custom handler when a row is indented. 1658 * Stub function. Allows a custom handler when a row is indented.
1501 * 1659 *
1502 * @return {null} 1660 * @return {null}
1503 * Returns null when the stub function is used. 1661 * Returns null when the stub function is used.
1504 */ 1662 */
1505 Drupal.tableDrag.prototype.row.prototype.onIndent = function () { 1663 Drupal.tableDrag.prototype.row.prototype.onIndent = function() {
1506 return null; 1664 return null;
1507 }; 1665 };
1508 1666
1509 /** 1667 /**
1510 * Stub function. Allows a custom handler when a row is swapped. 1668 * Stub function. Allows a custom handler when a row is swapped.
1513 * The element for the swapped row. 1671 * The element for the swapped row.
1514 * 1672 *
1515 * @return {null} 1673 * @return {null}
1516 * Returns null when the stub function is used. 1674 * Returns null when the stub function is used.
1517 */ 1675 */
1518 Drupal.tableDrag.prototype.row.prototype.onSwap = function (swappedRow) { 1676 Drupal.tableDrag.prototype.row.prototype.onSwap = function(swappedRow) {
1519 return null; 1677 return null;
1520 }; 1678 };
1521 1679
1522 $.extend(Drupal.theme, /** @lends Drupal.theme */{ 1680 $.extend(
1523 1681 Drupal.theme,
1524 /** 1682 /** @lends Drupal.theme */ {
1525 * @return {string} 1683 /**
1526 * Markup for the marker. 1684 * @return {string}
1527 */ 1685 * Markup for the marker.
1528 tableDragChangedMarker() { 1686 */
1529 return `<abbr class="warning tabledrag-changed" title="${Drupal.t('Changed')}">*</abbr>`; 1687 tableDragChangedMarker() {
1688 return `<abbr class="warning tabledrag-changed" title="${Drupal.t(
1689 'Changed',
1690 )}">*</abbr>`;
1691 },
1692
1693 /**
1694 * @return {string}
1695 * Markup for the indentation.
1696 */
1697 tableDragIndentation() {
1698 return '<div class="js-indentation indentation">&nbsp;</div>';
1699 },
1700
1701 /**
1702 * @return {string}
1703 * Markup for the warning.
1704 */
1705 tableDragChangedWarning() {
1706 return `<div class="tabledrag-changed-warning messages messages--warning" role="alert">${Drupal.theme(
1707 'tableDragChangedMarker',
1708 )} ${Drupal.t('You have unsaved changes.')}</div>`;
1709 },
1530 }, 1710 },
1531 1711 );
1532 /** 1712 })(jQuery, Drupal, drupalSettings);
1533 * @return {string}
1534 * Markup for the indentation.
1535 */
1536 tableDragIndentation() {
1537 return '<div class="js-indentation indentation">&nbsp;</div>';
1538 },
1539
1540 /**
1541 * @return {string}
1542 * Markup for the warning.
1543 */
1544 tableDragChangedWarning() {
1545 return `<div class="tabledrag-changed-warning messages messages--warning" role="alert">${Drupal.theme('tableDragChangedMarker')} ${Drupal.t('You have unsaved changes.')}</div>`;
1546 },
1547 });
1548 }(jQuery, Drupal, drupalSettings));