Mercurial > hg > isophonics-drupal-site
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"> </div></a>').attr('title', Drupal.t('Drag to re-order')); | 482 const handle = $( |
483 '<a href="#" class="tabledrag-handle"><div class="handle"> </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"> </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"> </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)); |