yummy-guide-generic-administrate 0.8.0 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/javascripts/yummy_guide_administrate/column_resizer.js +352 -50
- data/app/assets/javascripts/yummy_guide_administrate/sticky_left_columns.js +92 -5
- data/app/assets/javascripts/yummy_guide_administrate/sticky_table_headers.js +169 -0
- data/app/assets/stylesheets/yummy_guide_administrate/_column_resizer.scss +33 -4
- data/lib/yummy_guide/administrate/version.rb +1 -1
- data/spec/yummy_guide/administrate/column_resizer_asset_spec.rb +183 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 55b8c25b868ffa217ed45c64c2c0b53aa46bdb9d60094c022d9979cdd7a4e013
|
|
4
|
+
data.tar.gz: 4889ad38b64d46b34ce69f7e5cb4819c53d71a9c13636096dc94a5721e94fa87
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e85e0d5ef1a103b6f72b9544dabc6ec02118bd4c845c2dabffaa47e4b4d66de21cf227277e196ee70c4285aa76721766d9c8a465665c233e7e22a68ba32d9b2a
|
|
7
|
+
data.tar.gz: 508817a41590cac77f1b1f3ecfbb676784ee6e5655dd1336f2e0216c5700100c9c66f6a36c56830c4f8ee611a0ae117cf2a6ee220b82eb5b77913af54d50e708
|
|
@@ -4,21 +4,25 @@
|
|
|
4
4
|
var HEADER_CLASS = 'admin-column-resizer__header';
|
|
5
5
|
var TABLE_CLASS = 'admin-column-resizer__table';
|
|
6
6
|
var DRAGGING_BODY_CLASS = 'admin-column-resizer--dragging';
|
|
7
|
+
var APPLYING_BODY_CLASS = 'admin-column-resizer--applying';
|
|
8
|
+
var PREVIEW_CLASS = 'admin-column-resizer__preview';
|
|
7
9
|
var FIXED_HEADER_TABLE_CLASS = 'table-fixed-header__table';
|
|
10
|
+
var ADJUSTED_COLUMNS_ATTRIBUTE = 'data-admin-column-resizer-adjusted-columns';
|
|
8
11
|
var STORAGE_PREFIX = 'yummyGuideAdminColumnWidths:v1:';
|
|
9
12
|
var STYLE_ELEMENT_ID = 'admin-column-resizer-rules';
|
|
10
13
|
var WIDTH_VAR_PREFIX = '--admin-column-resizer-col-';
|
|
11
14
|
var MIN_WIDTH = 48;
|
|
12
|
-
var STICKY_REFRESH_INTERVAL = 120;
|
|
13
15
|
|
|
14
16
|
var dragState = null;
|
|
15
|
-
var
|
|
17
|
+
var dragPreviewFrame = null;
|
|
18
|
+
var widthApplyFrame = null;
|
|
19
|
+
var pendingWidthApply = null;
|
|
16
20
|
var generatedRuleCount = 0;
|
|
17
21
|
var initializedHandles = new WeakSet();
|
|
18
22
|
var tableStates = new WeakMap();
|
|
19
23
|
var stickyRefreshFrame = null;
|
|
20
|
-
var
|
|
21
|
-
var
|
|
24
|
+
var stickyRefreshCallbacks = [];
|
|
25
|
+
var applyingWidth = false;
|
|
22
26
|
|
|
23
27
|
function storageScopeForTable(table) {
|
|
24
28
|
var sourceTable = matchingSourceTable(table);
|
|
@@ -74,6 +78,10 @@
|
|
|
74
78
|
return preciseNumber(rectWidth || element.offsetWidth || 0);
|
|
75
79
|
}
|
|
76
80
|
|
|
81
|
+
function viewportHeight() {
|
|
82
|
+
return window.innerHeight || document.documentElement.clientHeight || 0;
|
|
83
|
+
}
|
|
84
|
+
|
|
77
85
|
function normalizedIdentifier(value) {
|
|
78
86
|
return (value || '').toString().trim().toLowerCase()
|
|
79
87
|
.replace(/[^a-z0-9]+/g, '_')
|
|
@@ -169,13 +177,22 @@
|
|
|
169
177
|
function columnRule(index) {
|
|
170
178
|
var nthChild = index + 1;
|
|
171
179
|
var variableName = columnWidthVariable(index);
|
|
172
|
-
var
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
180
|
+
var adjustedTableSelector = '.' + TABLE_CLASS + '[' + ADJUSTED_COLUMNS_ATTRIBUTE + '~="' + nthChild + '"]';
|
|
181
|
+
var selectors = [
|
|
182
|
+
adjustedTableSelector + ' > thead > tr > :nth-child(' + nthChild + ')',
|
|
183
|
+
adjustedTableSelector + ' > tbody > tr > :nth-child(' + nthChild + ')',
|
|
184
|
+
adjustedTableSelector + ' > tfoot > tr > :nth-child(' + nthChild + ')'
|
|
185
|
+
];
|
|
186
|
+
var selector = selectors.join(', ');
|
|
187
|
+
|
|
188
|
+
var contentSelector = selectors.concat(selectors.map(function(cellSelector) {
|
|
189
|
+
return cellSelector + ' *';
|
|
190
|
+
})).join(', ');
|
|
177
191
|
|
|
178
|
-
return
|
|
192
|
+
return [
|
|
193
|
+
selector + ' { box-sizing: border-box !important; width: var(' + variableName + ') !important; min-width: var(' + variableName + ') !important; max-width: var(' + variableName + ') !important; }',
|
|
194
|
+
contentSelector + ' { white-space: normal !important; overflow-wrap: anywhere !important; word-break: break-word !important; }'
|
|
195
|
+
].join('\n');
|
|
179
196
|
}
|
|
180
197
|
|
|
181
198
|
function ensureStyleElement() {
|
|
@@ -315,6 +332,33 @@
|
|
|
315
332
|
colgroup.children[index].style.width = widthValue;
|
|
316
333
|
}
|
|
317
334
|
|
|
335
|
+
function adjustedColumnIndexes(table) {
|
|
336
|
+
return (table.getAttribute(ADJUSTED_COLUMNS_ATTRIBUTE) || '')
|
|
337
|
+
.split(/\s+/)
|
|
338
|
+
.filter(Boolean);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function setAdjustedColumn(table, index, adjusted) {
|
|
342
|
+
var indexToken = (index + 1).toString();
|
|
343
|
+
var indexes = adjustedColumnIndexes(table).filter(function(candidate, candidateIndex, candidates) {
|
|
344
|
+
return candidate !== indexToken && candidates.indexOf(candidate) === candidateIndex;
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
if (adjusted) {
|
|
348
|
+
indexes.push(indexToken);
|
|
349
|
+
indexes.sort(function(left, right) {
|
|
350
|
+
return parseInt(left, 10) - parseInt(right, 10);
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (indexes.length === 0) {
|
|
355
|
+
table.removeAttribute(ADJUSTED_COLUMNS_ATTRIBUTE);
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
table.setAttribute(ADJUSTED_COLUMNS_ATTRIBUTE, indexes.join(' '));
|
|
360
|
+
}
|
|
361
|
+
|
|
318
362
|
function clearColgroupWidth(table, columnCount, index) {
|
|
319
363
|
var colgroup = ensureManagedColgroup(table, columnCount);
|
|
320
364
|
if (!colgroup || !colgroup.children[index]) return;
|
|
@@ -329,6 +373,7 @@
|
|
|
329
373
|
|
|
330
374
|
var widthValue = cssPixelValue(width);
|
|
331
375
|
table.style.setProperty(columnWidthVariable(index), widthValue);
|
|
376
|
+
setAdjustedColumn(table, index, true);
|
|
332
377
|
applyColgroupWidth(table, state.columnCount, index, widthValue);
|
|
333
378
|
}
|
|
334
379
|
|
|
@@ -338,6 +383,7 @@
|
|
|
338
383
|
if (!state || index === undefined) return;
|
|
339
384
|
|
|
340
385
|
table.style.removeProperty(columnWidthVariable(index));
|
|
386
|
+
setAdjustedColumn(table, index, false);
|
|
341
387
|
clearColgroupWidth(table, state.columnCount, index);
|
|
342
388
|
}
|
|
343
389
|
|
|
@@ -381,26 +427,23 @@
|
|
|
381
427
|
|
|
382
428
|
function dispatchStickyRefresh() {
|
|
383
429
|
stickyRefreshFrame = null;
|
|
384
|
-
lastStickyRefreshAt = Date.now();
|
|
385
430
|
window.dispatchEvent(new Event('resize'));
|
|
386
|
-
}
|
|
387
431
|
|
|
388
|
-
|
|
389
|
-
|
|
432
|
+
var callbacks = stickyRefreshCallbacks;
|
|
433
|
+
stickyRefreshCallbacks = [];
|
|
434
|
+
callbacks.forEach(function(callback) {
|
|
435
|
+
callback();
|
|
436
|
+
});
|
|
437
|
+
}
|
|
390
438
|
|
|
391
|
-
|
|
392
|
-
|
|
439
|
+
function scheduleStickyRefresh(callback) {
|
|
440
|
+
if (callback) {
|
|
441
|
+
stickyRefreshCallbacks.push(callback);
|
|
442
|
+
}
|
|
393
443
|
|
|
394
|
-
|
|
395
|
-
stickyRefreshTimer = null;
|
|
396
|
-
stickyRefreshFrame = window.requestAnimationFrame(dispatchStickyRefresh);
|
|
397
|
-
}, delay);
|
|
398
|
-
}
|
|
444
|
+
if (stickyRefreshFrame) return;
|
|
399
445
|
|
|
400
|
-
|
|
401
|
-
return header.classList.contains('sticky') ||
|
|
402
|
-
header.classList.contains('sticky-left') ||
|
|
403
|
-
header.classList.contains('actions-column');
|
|
446
|
+
stickyRefreshFrame = window.requestAnimationFrame(dispatchStickyRefresh);
|
|
404
447
|
}
|
|
405
448
|
|
|
406
449
|
function sourceTableForHandle(handle) {
|
|
@@ -419,34 +462,269 @@
|
|
|
419
462
|
}) || matchingSourceTable(table) || null;
|
|
420
463
|
}
|
|
421
464
|
|
|
422
|
-
function
|
|
465
|
+
function previewBoundsForTable(table, header) {
|
|
466
|
+
var headerRect = header.getBoundingClientRect();
|
|
467
|
+
var tableRect = table.getBoundingClientRect();
|
|
468
|
+
var scrollContainer = table.closest('.sticky-table-scroll, .scroll-table, .home-table__wrapper');
|
|
469
|
+
var scrollRect = scrollContainer ? scrollContainer.getBoundingClientRect() : tableRect;
|
|
470
|
+
var headerTable = header.closest(TABLE_SELECTOR);
|
|
471
|
+
var fromFixedHeader = headerTable && headerTable.classList.contains(FIXED_HEADER_TABLE_CLASS);
|
|
472
|
+
var viewportBottom = viewportHeight();
|
|
473
|
+
var top = fromFixedHeader ? headerRect.top : Math.max(tableRect.top, scrollRect.top);
|
|
474
|
+
var bottom = Math.min(viewportBottom, Math.max(tableRect.bottom, scrollRect.bottom, headerRect.bottom));
|
|
475
|
+
|
|
476
|
+
top = Math.max(0, Math.min(top, viewportBottom));
|
|
477
|
+
if (bottom <= top) {
|
|
478
|
+
bottom = Math.min(viewportBottom, top + Math.max(headerRect.height, 32));
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
return {
|
|
482
|
+
left: headerRect.left,
|
|
483
|
+
top: top,
|
|
484
|
+
height: Math.max(32, bottom - top)
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
function updateDragPreview(preview, width) {
|
|
489
|
+
if (!preview) return;
|
|
490
|
+
|
|
491
|
+
preview.element.style.width = cssPixelValue(width);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
function createDragPreview(table, header, width) {
|
|
495
|
+
var bounds = previewBoundsForTable(table, header);
|
|
496
|
+
var element = document.createElement('div');
|
|
497
|
+
|
|
498
|
+
element.className = PREVIEW_CLASS;
|
|
499
|
+
element.setAttribute('aria-hidden', 'true');
|
|
500
|
+
element.style.left = cssPixelValue(bounds.left);
|
|
501
|
+
element.style.top = cssPixelValue(bounds.top);
|
|
502
|
+
element.style.height = cssPixelValue(bounds.height);
|
|
503
|
+
|
|
504
|
+
document.body.appendChild(element);
|
|
505
|
+
|
|
506
|
+
var preview = {
|
|
507
|
+
element: element
|
|
508
|
+
};
|
|
509
|
+
updateDragPreview(preview, width);
|
|
510
|
+
|
|
511
|
+
return preview;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
function removePreview(preview) {
|
|
515
|
+
if (!preview) return;
|
|
516
|
+
|
|
517
|
+
preview.element.remove();
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
function removeDragPreview() {
|
|
521
|
+
if (!dragState || !dragState.preview) return;
|
|
522
|
+
|
|
523
|
+
removePreview(dragState.preview);
|
|
524
|
+
dragState.preview = null;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
function flushDragPreview() {
|
|
423
528
|
if (!dragState) return;
|
|
424
529
|
|
|
425
|
-
if (
|
|
426
|
-
window.cancelAnimationFrame(
|
|
427
|
-
|
|
530
|
+
if (dragPreviewFrame) {
|
|
531
|
+
window.cancelAnimationFrame(dragPreviewFrame);
|
|
532
|
+
dragPreviewFrame = null;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
updateDragPreview(dragState.preview, dragState.currentWidth || dragState.startWidth);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
function releaseDragPointerCapture() {
|
|
539
|
+
if (!dragState || !dragState.handle || dragState.pointerId === null || typeof dragState.pointerId === 'undefined') return;
|
|
540
|
+
if (!dragState.handle.releasePointerCapture) return;
|
|
541
|
+
|
|
542
|
+
try {
|
|
543
|
+
dragState.handle.releasePointerCapture(dragState.pointerId);
|
|
544
|
+
} catch (_error) {
|
|
545
|
+
// The pointer may already be released by the browser after cancellation.
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
function captureDragPointer(handle, event) {
|
|
550
|
+
if (!handle.setPointerCapture || event.pointerId === null || typeof event.pointerId === 'undefined') return;
|
|
551
|
+
|
|
552
|
+
try {
|
|
553
|
+
handle.setPointerCapture(event.pointerId);
|
|
554
|
+
} catch (_error) {
|
|
555
|
+
// Pointer capture is an enhancement for touch/pen dragging; document listeners remain as fallback.
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
function eventMatchesDragPointer(event) {
|
|
560
|
+
return !event ||
|
|
561
|
+
dragState.pointerId === null ||
|
|
562
|
+
typeof dragState.pointerId === 'undefined' ||
|
|
563
|
+
event.pointerId === dragState.pointerId;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
function pointerCanStartDrag(event) {
|
|
567
|
+
if (event.isPrimary === false) return false;
|
|
568
|
+
|
|
569
|
+
return event.pointerType !== 'mouse' || event.button === 0;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
function stopDragging(removePreview) {
|
|
573
|
+
if (!dragState) return null;
|
|
574
|
+
|
|
575
|
+
if (dragPreviewFrame) {
|
|
576
|
+
window.cancelAnimationFrame(dragPreviewFrame);
|
|
577
|
+
dragPreviewFrame = null;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
if (removePreview) {
|
|
581
|
+
removeDragPreview();
|
|
428
582
|
}
|
|
429
583
|
|
|
430
|
-
|
|
584
|
+
releaseDragPointerCapture();
|
|
585
|
+
|
|
586
|
+
var completedDrag = dragState;
|
|
587
|
+
dragState = null;
|
|
588
|
+
document.body.classList.remove(DRAGGING_BODY_CLASS);
|
|
589
|
+
document.removeEventListener('pointermove', handleDragMove);
|
|
590
|
+
document.removeEventListener('pointerup', finishDrag);
|
|
591
|
+
document.removeEventListener('pointercancel', finishDrag);
|
|
592
|
+
|
|
593
|
+
return completedDrag;
|
|
431
594
|
}
|
|
432
595
|
|
|
433
596
|
function scheduleDragWidth(width) {
|
|
434
597
|
dragState.currentWidth = width;
|
|
435
598
|
dragState.moved = dragState.moved || Math.abs(width - dragState.startWidth) > 2;
|
|
436
599
|
|
|
437
|
-
if (
|
|
600
|
+
if (dragPreviewFrame) return;
|
|
438
601
|
|
|
439
|
-
|
|
440
|
-
|
|
602
|
+
dragPreviewFrame = window.requestAnimationFrame(function() {
|
|
603
|
+
dragPreviewFrame = null;
|
|
441
604
|
if (!dragState) return;
|
|
442
605
|
|
|
443
|
-
|
|
444
|
-
|
|
606
|
+
updateDragPreview(dragState.preview, dragState.currentWidth);
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
function refreshStickyHeaderColumn(pendingWidth, callback) {
|
|
611
|
+
var api = window.YummyGuideAdministrateStickyTableHeaders;
|
|
612
|
+
|
|
613
|
+
if (api && typeof api.refreshColumnWidth === 'function') {
|
|
614
|
+
var refreshed = api.refreshColumnWidth({
|
|
615
|
+
sourceTable: pendingWidth.sourceTable,
|
|
616
|
+
columnId: pendingWidth.columnId,
|
|
617
|
+
width: pendingWidth.width
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
if (refreshed) {
|
|
621
|
+
window.requestAnimationFrame(callback);
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
scheduleStickyRefresh(callback);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
function refreshStickyHeaderTable(sourceTable, callback) {
|
|
630
|
+
var api = window.YummyGuideAdministrateStickyTableHeaders;
|
|
631
|
+
|
|
632
|
+
if (api && typeof api.refreshTable === 'function') {
|
|
633
|
+
var refreshed = api.refreshTable(sourceTable, callback);
|
|
634
|
+
|
|
635
|
+
if (refreshed) return;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
scheduleStickyRefresh(callback);
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
function refreshStickyLeftColumns(sourceTable) {
|
|
642
|
+
var api = window.YummyGuideAdministrateStickyLeftColumns;
|
|
643
|
+
|
|
644
|
+
if (api && typeof api.refreshTable === 'function') {
|
|
645
|
+
api.refreshTable(sourceTable);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
function refreshStickyLeftColumnsForWidth(pendingWidth) {
|
|
650
|
+
var api = window.YummyGuideAdministrateStickyLeftColumns;
|
|
651
|
+
|
|
652
|
+
if (!api) return;
|
|
653
|
+
|
|
654
|
+
if (typeof api.refreshColumnWidth === 'function') {
|
|
655
|
+
var refreshed = api.refreshColumnWidth({
|
|
656
|
+
sourceTable: pendingWidth.sourceTable,
|
|
657
|
+
columnId: pendingWidth.columnId,
|
|
658
|
+
width: pendingWidth.width
|
|
659
|
+
});
|
|
660
|
+
|
|
661
|
+
if (refreshed) return;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
refreshStickyLeftColumns(pendingWidth.sourceTable);
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
function startApplyingWidth() {
|
|
668
|
+
applyingWidth = true;
|
|
669
|
+
document.body.classList.add(APPLYING_BODY_CLASS);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
function stopApplyingState() {
|
|
673
|
+
applyingWidth = false;
|
|
674
|
+
document.body.classList.remove(APPLYING_BODY_CLASS);
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
function stopApplyingWidth(preview) {
|
|
678
|
+
removePreview(preview);
|
|
679
|
+
pendingWidthApply = null;
|
|
680
|
+
stopApplyingState();
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
function cancelPendingWidthApply() {
|
|
684
|
+
if (widthApplyFrame) {
|
|
685
|
+
window.cancelAnimationFrame(widthApplyFrame);
|
|
686
|
+
widthApplyFrame = null;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
if (pendingWidthApply) {
|
|
690
|
+
removePreview(pendingWidthApply.preview);
|
|
691
|
+
pendingWidthApply = null;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
stopApplyingState();
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
function applyPendingWidth(pendingWidth) {
|
|
698
|
+
try {
|
|
699
|
+
var widths = safeReadWidths(pendingWidth.storageKey);
|
|
700
|
+
applyColumnWidth(pendingWidth.columnId, pendingWidth.width, pendingWidth.storageKey);
|
|
701
|
+
widths[pendingWidth.columnId] = preciseNumber(pendingWidth.width);
|
|
702
|
+
safeWriteWidths(pendingWidth.storageKey, widths);
|
|
703
|
+
refreshStickyLeftColumnsForWidth(pendingWidth);
|
|
704
|
+
refreshStickyHeaderColumn(pendingWidth, function() {
|
|
705
|
+
stopApplyingWidth(pendingWidth.preview);
|
|
706
|
+
});
|
|
707
|
+
} catch (error) {
|
|
708
|
+
stopApplyingWidth(pendingWidth.preview);
|
|
709
|
+
throw error;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
function schedulePendingWidthApply(pendingWidth) {
|
|
714
|
+
pendingWidthApply = pendingWidth;
|
|
715
|
+
startApplyingWidth();
|
|
716
|
+
|
|
717
|
+
widthApplyFrame = window.requestAnimationFrame(function() {
|
|
718
|
+
widthApplyFrame = window.requestAnimationFrame(function() {
|
|
719
|
+
widthApplyFrame = null;
|
|
720
|
+
applyPendingWidth(pendingWidth);
|
|
721
|
+
});
|
|
445
722
|
});
|
|
446
723
|
}
|
|
447
724
|
|
|
448
725
|
function startDrag(event) {
|
|
449
|
-
if (event
|
|
726
|
+
if (!pointerCanStartDrag(event)) return;
|
|
727
|
+
if (applyingWidth || widthApplyFrame) return;
|
|
450
728
|
|
|
451
729
|
var handle = event.currentTarget;
|
|
452
730
|
var header = handle.closest('th');
|
|
@@ -459,8 +737,11 @@
|
|
|
459
737
|
if (!sourceTable) return;
|
|
460
738
|
|
|
461
739
|
var sourceHeader = columnHeader(sourceTable, columnId) || header;
|
|
462
|
-
var
|
|
740
|
+
var sourceHeaderWidth = measuredWidth(sourceHeader);
|
|
741
|
+
var handleHeaderWidth = measuredWidth(header);
|
|
742
|
+
var startWidth = sourceHeaderWidth || handleHeaderWidth;
|
|
463
743
|
if (!startWidth) return;
|
|
744
|
+
var previewHeader = sourceHeaderWidth ? sourceHeader : header;
|
|
464
745
|
|
|
465
746
|
event.preventDefault();
|
|
466
747
|
event.stopPropagation();
|
|
@@ -471,10 +752,14 @@
|
|
|
471
752
|
startX: event.clientX,
|
|
472
753
|
startWidth: startWidth,
|
|
473
754
|
currentWidth: startWidth,
|
|
755
|
+
pointerId: event.pointerId,
|
|
756
|
+
handle: handle,
|
|
757
|
+
sourceTable: sourceTable,
|
|
474
758
|
moved: false,
|
|
475
|
-
|
|
759
|
+
preview: createDragPreview(sourceTable, previewHeader, startWidth)
|
|
476
760
|
};
|
|
477
761
|
|
|
762
|
+
captureDragPointer(handle, event);
|
|
478
763
|
document.body.classList.add(DRAGGING_BODY_CLASS);
|
|
479
764
|
document.addEventListener('pointermove', handleDragMove);
|
|
480
765
|
document.addEventListener('pointerup', finishDrag);
|
|
@@ -483,6 +768,7 @@
|
|
|
483
768
|
|
|
484
769
|
function handleDragMove(event) {
|
|
485
770
|
if (!dragState) return;
|
|
771
|
+
if (!eventMatchesDragPointer(event)) return;
|
|
486
772
|
|
|
487
773
|
event.preventDefault();
|
|
488
774
|
|
|
@@ -491,24 +777,28 @@
|
|
|
491
777
|
|
|
492
778
|
function finishDrag(event) {
|
|
493
779
|
if (!dragState) return;
|
|
780
|
+
if (!eventMatchesDragPointer(event)) return;
|
|
494
781
|
|
|
495
782
|
if (event) {
|
|
496
783
|
event.preventDefault();
|
|
497
784
|
}
|
|
498
785
|
|
|
499
|
-
|
|
786
|
+
flushDragPreview();
|
|
787
|
+
var pointerCancelled = event && event.type === 'pointercancel';
|
|
788
|
+
var shouldApplyWidth = dragState.moved && !pointerCancelled;
|
|
500
789
|
|
|
501
|
-
var
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
790
|
+
var pendingWidth = {
|
|
791
|
+
columnId: dragState.columnId,
|
|
792
|
+
storageKey: dragState.storageKey,
|
|
793
|
+
sourceTable: dragState.sourceTable,
|
|
794
|
+
width: Math.max(MIN_WIDTH, dragState.currentWidth || dragState.startWidth),
|
|
795
|
+
preview: dragState.preview
|
|
796
|
+
};
|
|
505
797
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
document.removeEventListener('pointercancel', finishDrag);
|
|
511
|
-
scheduleStickyRefresh(true);
|
|
798
|
+
stopDragging(!shouldApplyWidth);
|
|
799
|
+
if (!shouldApplyWidth) return;
|
|
800
|
+
|
|
801
|
+
schedulePendingWidthApply(pendingWidth);
|
|
512
802
|
}
|
|
513
803
|
|
|
514
804
|
function resetColumn(event) {
|
|
@@ -521,6 +811,8 @@
|
|
|
521
811
|
|
|
522
812
|
event.preventDefault();
|
|
523
813
|
event.stopPropagation();
|
|
814
|
+
cancelPendingWidthApply();
|
|
815
|
+
stopDragging(true);
|
|
524
816
|
|
|
525
817
|
var sourceTable = sourceTableForHandle(handle);
|
|
526
818
|
var key = storageKeyForTable(sourceTable || handle.closest(TABLE_SELECTOR));
|
|
@@ -528,7 +820,17 @@
|
|
|
528
820
|
delete widths[columnId];
|
|
529
821
|
safeWriteWidths(key, widths);
|
|
530
822
|
clearColumnWidth(columnId, key);
|
|
531
|
-
|
|
823
|
+
startApplyingWidth();
|
|
824
|
+
if (sourceTable) {
|
|
825
|
+
refreshStickyHeaderTable(sourceTable, function() {
|
|
826
|
+
refreshStickyLeftColumns(sourceTable);
|
|
827
|
+
stopApplyingWidth(null);
|
|
828
|
+
});
|
|
829
|
+
} else {
|
|
830
|
+
scheduleStickyRefresh(function() {
|
|
831
|
+
stopApplyingWidth(null);
|
|
832
|
+
});
|
|
833
|
+
}
|
|
532
834
|
}
|
|
533
835
|
|
|
534
836
|
function stopHandleClick(event) {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
var TABLE_SELECTOR = "table[data-fixed-columns-count]";
|
|
3
3
|
var MOBILE_MEDIA_QUERY = "(max-width: 767px)";
|
|
4
4
|
var resizeObservers = new WeakMap();
|
|
5
|
+
var suppressedResizeTables = new WeakMap();
|
|
5
6
|
|
|
6
7
|
function directCells(row) {
|
|
7
8
|
return Array.from(row.children).filter(function(cell) {
|
|
@@ -24,6 +25,37 @@
|
|
|
24
25
|
return preciseNumber(value) + "px";
|
|
25
26
|
}
|
|
26
27
|
|
|
28
|
+
function headerColumnId(header) {
|
|
29
|
+
return header.dataset.adminColumnResizerColumnId || header.dataset.columnId || "";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function columnIndex(headerCells, columnId) {
|
|
33
|
+
if (!columnId) return -1;
|
|
34
|
+
|
|
35
|
+
return headerCells.findIndex(function(header) {
|
|
36
|
+
return headerColumnId(header) === columnId;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function widthOverride(headerCells, options) {
|
|
41
|
+
var settings = options || {};
|
|
42
|
+
var width = parseFloat(settings.width);
|
|
43
|
+
var index = columnIndex(headerCells, settings.columnId);
|
|
44
|
+
|
|
45
|
+
if (index < 0 || Number.isNaN(width)) return null;
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
index: index,
|
|
49
|
+
width: preciseNumber(width)
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function applyWidthOverride(widths, override) {
|
|
54
|
+
if (!override || override.index >= widths.length) return;
|
|
55
|
+
|
|
56
|
+
widths[override.index] = override.width;
|
|
57
|
+
}
|
|
58
|
+
|
|
27
59
|
function resetStickyColumns(table) {
|
|
28
60
|
table.querySelectorAll(".sticky-left").forEach(function(cell) {
|
|
29
61
|
cell.classList.remove("sticky-left", "sticky-left--last");
|
|
@@ -46,15 +78,18 @@
|
|
|
46
78
|
return window.matchMedia && window.matchMedia(MOBILE_MEDIA_QUERY).matches;
|
|
47
79
|
}
|
|
48
80
|
|
|
49
|
-
function stickyOffsets(table, count) {
|
|
81
|
+
function stickyOffsets(table, count, options) {
|
|
50
82
|
var headerRow = table.querySelector("thead tr");
|
|
51
83
|
if (!headerRow) return [];
|
|
52
84
|
|
|
53
|
-
var
|
|
85
|
+
var headerCells = directCells(headerRow);
|
|
86
|
+
var override = widthOverride(headerCells, options);
|
|
87
|
+
var widths = headerCells.slice(0, count).map(function(cell) {
|
|
54
88
|
return measuredWidth(cell);
|
|
55
89
|
});
|
|
90
|
+
var hasMeasuredWidth = widths.some(Boolean);
|
|
56
91
|
|
|
57
|
-
if (!
|
|
92
|
+
if (!hasMeasuredWidth) {
|
|
58
93
|
Array.from(table.querySelectorAll("tbody tr, tfoot tr")).some(function(row) {
|
|
59
94
|
var cells = directCells(row);
|
|
60
95
|
if (cells.length < count || cells.some(function(cell) { return cell.colSpan > 1; })) return false;
|
|
@@ -66,6 +101,8 @@
|
|
|
66
101
|
});
|
|
67
102
|
}
|
|
68
103
|
|
|
104
|
+
applyWidthOverride(widths, override);
|
|
105
|
+
|
|
69
106
|
var offsets = [];
|
|
70
107
|
var currentLeft = 0;
|
|
71
108
|
|
|
@@ -77,13 +114,13 @@
|
|
|
77
114
|
return offsets;
|
|
78
115
|
}
|
|
79
116
|
|
|
80
|
-
function applyStickyColumns(table) {
|
|
117
|
+
function applyStickyColumns(table, options) {
|
|
81
118
|
resetStickyColumns(table);
|
|
82
119
|
|
|
83
120
|
var count = fixedColumnsCount(table);
|
|
84
121
|
if (count === 0) return;
|
|
85
122
|
|
|
86
|
-
var offsets = stickyOffsets(table, count);
|
|
123
|
+
var offsets = stickyOffsets(table, count, options);
|
|
87
124
|
if (offsets.length === 0) return;
|
|
88
125
|
|
|
89
126
|
table.querySelectorAll("thead tr, tbody tr, tfoot tr").forEach(function(row) {
|
|
@@ -100,11 +137,56 @@
|
|
|
100
137
|
});
|
|
101
138
|
}
|
|
102
139
|
|
|
140
|
+
function suppressResizeApply(table) {
|
|
141
|
+
if (!table) return;
|
|
142
|
+
|
|
143
|
+
var token = (suppressedResizeTables.get(table) || 0) + 1;
|
|
144
|
+
suppressedResizeTables.set(table, token);
|
|
145
|
+
|
|
146
|
+
window.setTimeout(function() {
|
|
147
|
+
if (suppressedResizeTables.get(table) === token) {
|
|
148
|
+
suppressedResizeTables.delete(table);
|
|
149
|
+
}
|
|
150
|
+
}, 250);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function resizeApplySuppressed(table) {
|
|
154
|
+
return suppressedResizeTables.has(table);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function refreshTable(table) {
|
|
158
|
+
if (!table) return false;
|
|
159
|
+
|
|
160
|
+
suppressResizeApply(table);
|
|
161
|
+
applyStickyColumns(table);
|
|
162
|
+
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function refreshColumnWidth(options) {
|
|
167
|
+
var settings = options || {};
|
|
168
|
+
var table = settings.sourceTable;
|
|
169
|
+
|
|
170
|
+
if (!table) return false;
|
|
171
|
+
|
|
172
|
+
suppressResizeApply(table);
|
|
173
|
+
applyStickyColumns(table, {
|
|
174
|
+
columnId: settings.columnId,
|
|
175
|
+
width: settings.width
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
|
|
103
181
|
function observeStickyColumns(table) {
|
|
104
182
|
if (!window.ResizeObserver || resizeObservers.has(table)) return;
|
|
105
183
|
|
|
106
184
|
var observer = new ResizeObserver(function() {
|
|
185
|
+
if (resizeApplySuppressed(table)) return;
|
|
186
|
+
|
|
107
187
|
window.requestAnimationFrame(function() {
|
|
188
|
+
if (resizeApplySuppressed(table)) return;
|
|
189
|
+
|
|
108
190
|
applyStickyColumns(table);
|
|
109
191
|
});
|
|
110
192
|
});
|
|
@@ -149,6 +231,11 @@
|
|
|
149
231
|
document.addEventListener("turbo:load", initializeFromDocument);
|
|
150
232
|
window.addEventListener("resize", initializeFromDocument);
|
|
151
233
|
|
|
234
|
+
window.YummyGuideAdministrateStickyLeftColumns = {
|
|
235
|
+
refreshColumnWidth: refreshColumnWidth,
|
|
236
|
+
refreshTable: refreshTable
|
|
237
|
+
};
|
|
238
|
+
|
|
152
239
|
if (window.MutationObserver) {
|
|
153
240
|
var mutationObserver = new MutationObserver(function(mutations) {
|
|
154
241
|
mutations.forEach(function(mutation) {
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
var observedScrolls = new WeakMap();
|
|
7
7
|
var observedFixedScrolls = new WeakMap();
|
|
8
8
|
var scrollSyncStates = new WeakMap();
|
|
9
|
+
var suppressedResizeScrolls = new WeakMap();
|
|
9
10
|
|
|
10
11
|
function directCells(row) {
|
|
11
12
|
return Array.from(row.children).filter(function(cell) {
|
|
@@ -36,6 +37,11 @@
|
|
|
36
37
|
return preciseNumber(Math.max(table.scrollWidth || 0, measuredWidth(table), widthsSum));
|
|
37
38
|
}
|
|
38
39
|
|
|
40
|
+
function parsedPixelValue(value) {
|
|
41
|
+
var parsedValue = parseFloat(value || '0');
|
|
42
|
+
return Number.isNaN(parsedValue) ? 0 : preciseNumber(parsedValue);
|
|
43
|
+
}
|
|
44
|
+
|
|
39
45
|
function fixedColumnsCount(table) {
|
|
40
46
|
var rawCount = table.dataset.fixedColumnsCount || '0';
|
|
41
47
|
|
|
@@ -339,6 +345,19 @@
|
|
|
339
345
|
});
|
|
340
346
|
}
|
|
341
347
|
|
|
348
|
+
function applyColGroupColumnWidth(table, index, widthValue) {
|
|
349
|
+
if (!table) return;
|
|
350
|
+
|
|
351
|
+
var colgroup = table.querySelector('colgroup[data-fixed-header-colgroup]');
|
|
352
|
+
if (!colgroup) return;
|
|
353
|
+
|
|
354
|
+
while (colgroup.children.length <= index) {
|
|
355
|
+
colgroup.appendChild(document.createElement('col'));
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
colgroup.children[index].style.width = widthValue;
|
|
359
|
+
}
|
|
360
|
+
|
|
342
361
|
function applyFixedHeaderCellWidths(fixedTable, widths) {
|
|
343
362
|
var headerRow = fixedTable && fixedTable.querySelector('thead tr');
|
|
344
363
|
if (!headerRow) return;
|
|
@@ -356,6 +375,56 @@
|
|
|
356
375
|
});
|
|
357
376
|
}
|
|
358
377
|
|
|
378
|
+
function applyFixedHeaderCellWidth(fixedTable, index, width) {
|
|
379
|
+
var headerRow = fixedTable && fixedTable.querySelector('thead tr');
|
|
380
|
+
if (!headerRow) return;
|
|
381
|
+
|
|
382
|
+
var cell = directCells(headerRow)[index];
|
|
383
|
+
if (!cell) return;
|
|
384
|
+
|
|
385
|
+
var widthValue = cssPixelValue(width);
|
|
386
|
+
cell.style.width = widthValue;
|
|
387
|
+
cell.style.minWidth = widthValue;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function columnIdentifier(cell) {
|
|
391
|
+
if (!cell) return '';
|
|
392
|
+
|
|
393
|
+
return cell.dataset.adminColumnResizerColumnId || cell.dataset.columnId || '';
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function sourceColumnIndex(sourceTable, columnId) {
|
|
397
|
+
var sourceRow = sourceTable && sourceTable.querySelector('thead tr');
|
|
398
|
+
if (!sourceRow) return -1;
|
|
399
|
+
|
|
400
|
+
return directCells(sourceRow).findIndex(function(cell) {
|
|
401
|
+
return columnIdentifier(cell) === columnId;
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
function columnWidthsFromCurrentHeader(sourceTable, fixedTable, columnCount) {
|
|
406
|
+
var sourceRow = sourceTable && sourceTable.querySelector('thead tr');
|
|
407
|
+
var fixedRow = fixedTable && fixedTable.querySelector('thead tr');
|
|
408
|
+
var sourceCells = sourceRow ? directCells(sourceRow) : [];
|
|
409
|
+
var fixedCells = fixedRow ? directCells(fixedRow) : [];
|
|
410
|
+
var sourceColgroup = sourceTable && sourceTable.querySelector('colgroup[data-fixed-header-colgroup]');
|
|
411
|
+
var fixedColgroup = fixedTable && fixedTable.querySelector('colgroup[data-fixed-header-colgroup]');
|
|
412
|
+
var widths = [];
|
|
413
|
+
|
|
414
|
+
for (var index = 0; index < columnCount; index += 1) {
|
|
415
|
+
var fixedColWidth = fixedColgroup && fixedColgroup.children[index] && parsedPixelValue(fixedColgroup.children[index].style.width);
|
|
416
|
+
var sourceColWidth = sourceColgroup && sourceColgroup.children[index] && parsedPixelValue(sourceColgroup.children[index].style.width);
|
|
417
|
+
|
|
418
|
+
widths[index] = fixedColWidth ||
|
|
419
|
+
sourceColWidth ||
|
|
420
|
+
measuredWidth(fixedCells[index]) ||
|
|
421
|
+
measuredWidth(sourceCells[index]) ||
|
|
422
|
+
0;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
return widths;
|
|
426
|
+
}
|
|
427
|
+
|
|
359
428
|
function mergeMeasuredCellWidths(widths, cells) {
|
|
360
429
|
cells.forEach(function(cell, index) {
|
|
361
430
|
widths[index] = Math.max(widths[index] || 0, measuredWidth(cell));
|
|
@@ -467,6 +536,24 @@
|
|
|
467
536
|
});
|
|
468
537
|
}
|
|
469
538
|
|
|
539
|
+
function applySourceColumnMinWidth(sourceTable, columnIndex, columnCount, width) {
|
|
540
|
+
if (!sourceTable) return;
|
|
541
|
+
|
|
542
|
+
var widthValue = cssPixelValue(width);
|
|
543
|
+
Array.from(sourceTable.querySelectorAll('thead tr, tbody tr, tfoot tr')).forEach(function(row) {
|
|
544
|
+
var cells = directCells(row);
|
|
545
|
+
if (cells.length !== columnCount || cells.some(function(cell) { return cell.colSpan > 1; })) return;
|
|
546
|
+
|
|
547
|
+
var cell = cells[columnIndex];
|
|
548
|
+
if (!cell) return;
|
|
549
|
+
|
|
550
|
+
cell.style.setProperty('--fixed-header-column-min-width', widthValue);
|
|
551
|
+
applyManagedCellWidth(cell, 'width', widthValue);
|
|
552
|
+
applyManagedCellWidth(cell, 'min-width', widthValue);
|
|
553
|
+
cell.setAttribute('data-fixed-header-column-min-width', 'true');
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
|
|
470
557
|
function clearFixedHeaderState(slot, scroll, sourceTable) {
|
|
471
558
|
if (slot) {
|
|
472
559
|
slot.hidden = true;
|
|
@@ -534,6 +621,79 @@
|
|
|
534
621
|
});
|
|
535
622
|
}
|
|
536
623
|
|
|
624
|
+
function suppressResizeBuild(scroll) {
|
|
625
|
+
if (!scroll) return;
|
|
626
|
+
|
|
627
|
+
var token = (suppressedResizeScrolls.get(scroll) || 0) + 1;
|
|
628
|
+
suppressedResizeScrolls.set(scroll, token);
|
|
629
|
+
|
|
630
|
+
window.setTimeout(function() {
|
|
631
|
+
if (suppressedResizeScrolls.get(scroll) === token) {
|
|
632
|
+
suppressedResizeScrolls.delete(scroll);
|
|
633
|
+
}
|
|
634
|
+
}, 250);
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
function resizeBuildSuppressed(scroll) {
|
|
638
|
+
return suppressedResizeScrolls.has(scroll);
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
function refreshColumnWidth(options) {
|
|
642
|
+
var settings = options || {};
|
|
643
|
+
var sourceTable = settings.sourceTable;
|
|
644
|
+
var columnId = settings.columnId;
|
|
645
|
+
var width = parseFloat(settings.width);
|
|
646
|
+
|
|
647
|
+
if (!sourceTable || !columnId || Number.isNaN(width)) return false;
|
|
648
|
+
|
|
649
|
+
var scroll = sourceTable.closest(WRAPPER_SELECTOR);
|
|
650
|
+
if (!scroll) return false;
|
|
651
|
+
|
|
652
|
+
var slot = ensureFixedHeaderSlot(scroll);
|
|
653
|
+
var fixedScroll = slot && slot.querySelector('.table-fixed-header__scroll');
|
|
654
|
+
var fixedTable = fixedScroll && fixedScroll.querySelector('.table-fixed-header__table');
|
|
655
|
+
if (!slot || !fixedScroll || !fixedTable) return false;
|
|
656
|
+
|
|
657
|
+
var sourceRow = sourceTable.querySelector('thead tr');
|
|
658
|
+
var columnCount = sourceRow ? directCells(sourceRow).length : 0;
|
|
659
|
+
var columnIndex = sourceColumnIndex(sourceTable, columnId);
|
|
660
|
+
if (columnIndex < 0 || columnCount === 0) return false;
|
|
661
|
+
|
|
662
|
+
suppressResizeBuild(scroll);
|
|
663
|
+
|
|
664
|
+
var widthValue = cssPixelValue(width);
|
|
665
|
+
var widths = columnWidthsFromCurrentHeader(sourceTable, fixedTable, columnCount);
|
|
666
|
+
widths[columnIndex] = preciseNumber(width);
|
|
667
|
+
|
|
668
|
+
applySourceColumnMinWidth(sourceTable, columnIndex, columnCount, width);
|
|
669
|
+
applyColGroupColumnWidth(sourceTable, columnIndex, widthValue);
|
|
670
|
+
applyColGroupColumnWidth(fixedTable, columnIndex, widthValue);
|
|
671
|
+
applyFixedHeaderCellWidth(fixedTable, columnIndex, width);
|
|
672
|
+
applyFixedHeaderStickyColumns(sourceTable, fixedTable, widths);
|
|
673
|
+
|
|
674
|
+
fixedTable.style.width = cssPixelValue(measuredTableWidth(sourceTable, widths));
|
|
675
|
+
syncStickyPageHeader(scroll, slot);
|
|
676
|
+
syncFixedHeaderScroll(scroll, fixedScroll);
|
|
677
|
+
|
|
678
|
+
return true;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
function refreshTable(sourceTable, callback) {
|
|
682
|
+
if (!sourceTable) return false;
|
|
683
|
+
|
|
684
|
+
var scroll = sourceTable.closest(WRAPPER_SELECTOR);
|
|
685
|
+
if (!scroll) return false;
|
|
686
|
+
|
|
687
|
+
suppressResizeBuild(scroll);
|
|
688
|
+
initializeFixedHeaderForScroll(scroll);
|
|
689
|
+
|
|
690
|
+
if (callback) {
|
|
691
|
+
window.requestAnimationFrame(callback);
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
return true;
|
|
695
|
+
}
|
|
696
|
+
|
|
537
697
|
function buildFixedTableHeader(slot, scroll, sourceTable) {
|
|
538
698
|
if (!slot || !scroll || !sourceTable) return;
|
|
539
699
|
|
|
@@ -612,7 +772,11 @@
|
|
|
612
772
|
var observer = resizeObservers.get(scroll);
|
|
613
773
|
if (!observer) {
|
|
614
774
|
observer = new ResizeObserver(function() {
|
|
775
|
+
if (resizeBuildSuppressed(scroll)) return;
|
|
776
|
+
|
|
615
777
|
window.requestAnimationFrame(function() {
|
|
778
|
+
if (resizeBuildSuppressed(scroll)) return;
|
|
779
|
+
|
|
616
780
|
initializeFixedHeaderForScroll(scroll);
|
|
617
781
|
});
|
|
618
782
|
});
|
|
@@ -721,6 +885,11 @@
|
|
|
721
885
|
document.addEventListener('turbo:load', initializeFromDocument);
|
|
722
886
|
window.addEventListener('resize', initializeFromDocument);
|
|
723
887
|
|
|
888
|
+
window.YummyGuideAdministrateStickyTableHeaders = {
|
|
889
|
+
refreshColumnWidth: refreshColumnWidth,
|
|
890
|
+
refreshTable: refreshTable
|
|
891
|
+
};
|
|
892
|
+
|
|
724
893
|
if (window.MutationObserver) {
|
|
725
894
|
var mutationObserver = new MutationObserver(function(mutations) {
|
|
726
895
|
mutations.forEach(function(mutation) {
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
table.admin-column-resizer__table:not(.table-fixed-header__table) {
|
|
2
|
+
table-layout: auto !important;
|
|
3
|
+
width: max-content !important;
|
|
4
|
+
min-width: 100% !important;
|
|
5
|
+
}
|
|
6
|
+
|
|
1
7
|
.admin-column-resizer__header {
|
|
2
8
|
position: relative;
|
|
3
9
|
}
|
|
@@ -7,7 +13,7 @@
|
|
|
7
13
|
top: 0;
|
|
8
14
|
right: -5px;
|
|
9
15
|
bottom: 0;
|
|
10
|
-
z-index:
|
|
16
|
+
z-index: 1;
|
|
11
17
|
width: 12px;
|
|
12
18
|
cursor: col-resize;
|
|
13
19
|
touch-action: none;
|
|
@@ -42,6 +48,25 @@
|
|
|
42
48
|
user-select: none !important;
|
|
43
49
|
}
|
|
44
50
|
|
|
51
|
+
.admin-column-resizer--applying,
|
|
52
|
+
.admin-column-resizer--applying * {
|
|
53
|
+
cursor: wait !important;
|
|
54
|
+
user-select: none !important;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.admin-column-resizer__preview {
|
|
58
|
+
position: fixed;
|
|
59
|
+
z-index: 10000;
|
|
60
|
+
box-sizing: border-box;
|
|
61
|
+
pointer-events: none;
|
|
62
|
+
background: rgba(37, 99, 235, 0.12);
|
|
63
|
+
border-right: 2px solid rgba(37, 99, 235, 0.85);
|
|
64
|
+
border-left: 1px solid rgba(37, 99, 235, 0.35);
|
|
65
|
+
box-shadow: inset 0 0 0 1px rgba(37, 99, 235, 0.12);
|
|
66
|
+
contain: layout paint style;
|
|
67
|
+
will-change: width;
|
|
68
|
+
}
|
|
69
|
+
|
|
45
70
|
[data-fixed-table-header] .admin-column-resizer__handle {
|
|
46
71
|
pointer-events: auto;
|
|
47
72
|
}
|
|
@@ -52,13 +77,17 @@
|
|
|
52
77
|
|
|
53
78
|
@media (pointer: coarse), screen and (max-width: 767px) {
|
|
54
79
|
.admin-column-resizer__handle {
|
|
55
|
-
right: -
|
|
56
|
-
width:
|
|
80
|
+
right: -14px;
|
|
81
|
+
width: 36px;
|
|
57
82
|
}
|
|
58
83
|
|
|
59
84
|
.admin-column-resizer__handle::after {
|
|
60
|
-
right:
|
|
85
|
+
right: 17px;
|
|
61
86
|
background: rgba(255, 255, 255, 0.75);
|
|
62
87
|
opacity: 1;
|
|
63
88
|
}
|
|
89
|
+
|
|
90
|
+
.admin-column-resizer__preview {
|
|
91
|
+
border-right-width: 3px;
|
|
92
|
+
}
|
|
64
93
|
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe "column resizer assets" do
|
|
4
|
+
let(:javascript_source) do
|
|
5
|
+
File.read(File.expand_path("../../../app/assets/javascripts/yummy_guide_administrate/column_resizer.js", __dir__))
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
let(:stylesheet_source) do
|
|
9
|
+
File.read(File.expand_path("../../../app/assets/stylesheets/yummy_guide_administrate/_column_resizer.scss", __dir__))
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
let(:sticky_table_headers_source) do
|
|
13
|
+
File.read(File.expand_path("../../../app/assets/javascripts/yummy_guide_administrate/sticky_table_headers.js", __dir__))
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
let(:sticky_left_columns_source) do
|
|
17
|
+
File.read(File.expand_path("../../../app/assets/javascripts/yummy_guide_administrate/sticky_left_columns.js", __dir__))
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# 未調整列は内容幅で表示され、調整済み列だけが幅固定されることを静的に確認する
|
|
21
|
+
it "scopes fixed width rules to adjusted columns" do
|
|
22
|
+
expect(javascript_source).to include("data-admin-column-resizer-adjusted-columns")
|
|
23
|
+
expect(javascript_source).to include("setAdjustedColumn(table, index, true)")
|
|
24
|
+
expect(javascript_source).to include("setAdjustedColumn(table, index, false)")
|
|
25
|
+
expect(javascript_source).to include("ADJUSTED_COLUMNS_ATTRIBUTE + '~=\"' + nthChild")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# 幅調整後の内容が常に折り返されるCSSが生成されることを確認する
|
|
29
|
+
it "generates wrapping rules for adjusted columns" do
|
|
30
|
+
expect(javascript_source).to include("white-space: normal !important")
|
|
31
|
+
expect(javascript_source).to include("overflow-wrap: anywhere !important")
|
|
32
|
+
expect(javascript_source).to include("word-break: break-word !important")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# デフォルト状態の列幅が内容の最大幅を基準に決まることを確認する
|
|
36
|
+
it "uses max-content table sizing by default" do
|
|
37
|
+
expect(stylesheet_source).to include("table-layout: auto !important")
|
|
38
|
+
expect(stylesheet_source).to include("width: max-content !important")
|
|
39
|
+
expect(stylesheet_source).to include("min-width: 100% !important")
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# ドラッグ中に固定ヘッダー同期を繰り返さず、調整完了後だけ同期することを静的に確認する
|
|
43
|
+
it "synchronizes fixed headers after drag completion instead of during drag" do
|
|
44
|
+
expect(javascript_source).not_to include("scheduleStickyRefresh(false)")
|
|
45
|
+
expect(javascript_source).not_to include("refreshDuringDrag")
|
|
46
|
+
expect(javascript_source).not_to include("columnNeedsDragRefresh")
|
|
47
|
+
expect(javascript_source).not_to include("STICKY_REFRESH_INTERVAL")
|
|
48
|
+
expect(javascript_source).to include("refreshStickyHeaderColumn(pendingWidth, function()")
|
|
49
|
+
expect(javascript_source).to include("scheduleStickyRefresh(callback)")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# ドラッグ中は実テーブルを再レイアウトせず、プレビューだけを更新することを静的に確認する
|
|
53
|
+
it "updates only the lightweight preview while dragging" do
|
|
54
|
+
expect(javascript_source).to include("createDragPreview(sourceTable, previewHeader, startWidth)")
|
|
55
|
+
expect(javascript_source).to include("updateDragPreview(dragState.preview, dragState.currentWidth)")
|
|
56
|
+
expect(javascript_source).to include("schedulePendingWidthApply(pendingWidth)")
|
|
57
|
+
expect(javascript_source).to include("applyColumnWidth(pendingWidth.columnId, pendingWidth.width, pendingWidth.storageKey)")
|
|
58
|
+
expect(javascript_source).to include("sourceTable: dragState.sourceTable")
|
|
59
|
+
expect(javascript_source).not_to include("applyColumnWidth(dragState.columnId, dragState.currentWidth")
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# ハンドルのクリックやダブルクリックで、ドラッグ完了扱いの幅適用が予約されないことを静的に確認する
|
|
63
|
+
it "does not apply a width when the pointer did not move" do
|
|
64
|
+
expect(javascript_source).to include("var shouldApplyWidth = dragState.moved && !pointerCancelled")
|
|
65
|
+
expect(javascript_source).to include("stopDragging(!shouldApplyWidth)")
|
|
66
|
+
expect(javascript_source).to include("if (!shouldApplyWidth) return")
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# ダブルクリックの幅リセット前に、未実行の幅適用予約とプレビューを破棄することを静的に確認する
|
|
70
|
+
it "cancels pending width application before resetting a column" do
|
|
71
|
+
expect(javascript_source).to include("function cancelPendingWidthApply()")
|
|
72
|
+
expect(javascript_source).to include("window.cancelAnimationFrame(widthApplyFrame)")
|
|
73
|
+
expect(javascript_source).to include("removePreview(pendingWidthApply.preview)")
|
|
74
|
+
expect(javascript_source).to include("pendingWidthApply = null")
|
|
75
|
+
expect(javascript_source).to include("cancelPendingWidthApply()")
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# ドラッグ中の調整後幅を半透明カラムで表示するCSSがあることを確認する
|
|
79
|
+
it "defines a translucent column preview" do
|
|
80
|
+
expect(stylesheet_source).to include(".admin-column-resizer__preview")
|
|
81
|
+
expect(stylesheet_source).to include("pointer-events: none")
|
|
82
|
+
expect(stylesheet_source).to include("will-change: width")
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# 幅調整中のpxラベルが表示されないことを静的に確認する
|
|
86
|
+
it "does not render a pixel width label in the preview" do
|
|
87
|
+
expect(javascript_source).not_to include("PREVIEW_LABEL_CLASS")
|
|
88
|
+
expect(javascript_source).not_to include("admin-column-resizer__preview-label")
|
|
89
|
+
expect(javascript_source).not_to include("Math.round(width) + 'px'")
|
|
90
|
+
expect(stylesheet_source).not_to include(".admin-column-resizer__preview-label")
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# 固定列ヘッダーより幅調整ハンドルを背面にすることを静的に確認する
|
|
94
|
+
it "keeps resize handles behind sticky column headers" do
|
|
95
|
+
expect(stylesheet_source).to include("z-index: 1")
|
|
96
|
+
expect(stylesheet_source).not_to include("z-index: 20")
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# 幅の適用中だけ待機カーソルを表示することを静的に確認する
|
|
100
|
+
it "shows a wait cursor while applying the final width" do
|
|
101
|
+
expect(javascript_source).to include("APPLYING_BODY_CLASS = 'admin-column-resizer--applying'")
|
|
102
|
+
expect(javascript_source).to include("function startApplyingWidth()")
|
|
103
|
+
expect(javascript_source).to include("document.body.classList.add(APPLYING_BODY_CLASS)")
|
|
104
|
+
expect(javascript_source).to include("document.body.classList.remove(APPLYING_BODY_CLASS)")
|
|
105
|
+
expect(stylesheet_source).to include(".admin-column-resizer--applying")
|
|
106
|
+
expect(stylesheet_source).to include("cursor: wait !important")
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# モバイルのtouch/pen操作でハンドル外へ移動しても調整を継続できることを静的に確認する
|
|
110
|
+
it "supports touch and pen pointer dragging on mobile" do
|
|
111
|
+
expect(javascript_source).to include("event.pointerType !== 'mouse' || event.button === 0")
|
|
112
|
+
expect(javascript_source).to include("event.isPrimary === false")
|
|
113
|
+
expect(javascript_source).to include("handle.setPointerCapture(event.pointerId)")
|
|
114
|
+
expect(javascript_source).to include("dragState.handle.releasePointerCapture(dragState.pointerId)")
|
|
115
|
+
expect(stylesheet_source).to include("right: -14px")
|
|
116
|
+
expect(stylesheet_source).to include("width: 36px")
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# 幅適用後の固定ヘッダー追従が全体rebuildではなく対象カラム同期を優先することを静的に確認する
|
|
120
|
+
it "uses targeted fixed header synchronization after applying a width" do
|
|
121
|
+
expect(javascript_source).to include("window.YummyGuideAdministrateStickyTableHeaders")
|
|
122
|
+
expect(javascript_source).to include("api.refreshColumnWidth({")
|
|
123
|
+
expect(sticky_table_headers_source).to include("window.YummyGuideAdministrateStickyTableHeaders = {")
|
|
124
|
+
expect(sticky_table_headers_source).to include("refreshColumnWidth: refreshColumnWidth")
|
|
125
|
+
expect(sticky_table_headers_source).to include("refreshTable: refreshTable")
|
|
126
|
+
expect(sticky_table_headers_source).to include("function refreshColumnWidth(options)")
|
|
127
|
+
expect(sticky_table_headers_source).to include("applySourceColumnMinWidth(sourceTable, columnIndex, columnCount, width)")
|
|
128
|
+
expect(sticky_table_headers_source).to include("applyFixedHeaderCellWidth(fixedTable, columnIndex, width)")
|
|
129
|
+
expect(sticky_table_headers_source).to include("suppressResizeBuild(scroll)")
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# 幅適用後の固定左列追従もResizeObserverの重複再計算に頼らないことを静的に確認する
|
|
133
|
+
it "refreshes sticky left columns directly after applying a width" do
|
|
134
|
+
expect(javascript_source).to include("window.YummyGuideAdministrateStickyLeftColumns")
|
|
135
|
+
expect(javascript_source).to include("api.refreshColumnWidth({")
|
|
136
|
+
expect(javascript_source).to include("sourceTable: pendingWidth.sourceTable")
|
|
137
|
+
expect(javascript_source).to include("columnId: pendingWidth.columnId")
|
|
138
|
+
expect(javascript_source).to include("width: pendingWidth.width")
|
|
139
|
+
expect(javascript_source).to include("api.refreshTable(sourceTable)")
|
|
140
|
+
expect(javascript_source).to include("refreshStickyLeftColumns(pendingWidth.sourceTable)")
|
|
141
|
+
expect(sticky_left_columns_source).to include("window.YummyGuideAdministrateStickyLeftColumns = {")
|
|
142
|
+
expect(sticky_left_columns_source).to include("refreshColumnWidth: refreshColumnWidth")
|
|
143
|
+
expect(sticky_left_columns_source).to include("refreshTable: refreshTable")
|
|
144
|
+
expect(sticky_left_columns_source).to include("function refreshTable(table)")
|
|
145
|
+
expect(sticky_left_columns_source).to include("function refreshColumnWidth(options)")
|
|
146
|
+
expect(sticky_left_columns_source).to include("suppressResizeApply(table)")
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# 固定5列の4列目を調整した直後に5列目のleftが古い幅で残らないことを静的に確認する
|
|
150
|
+
it "uses the resized fixed column width when recalculating sticky-left offsets" do
|
|
151
|
+
expect(sticky_left_columns_source).to include("function widthOverride(headerCells, options)")
|
|
152
|
+
expect(sticky_left_columns_source).to include("columnIndex(headerCells, settings.columnId)")
|
|
153
|
+
expect(sticky_left_columns_source).to include("width: preciseNumber(width)")
|
|
154
|
+
expect(sticky_left_columns_source).to include("var hasMeasuredWidth = widths.some(Boolean)")
|
|
155
|
+
expect(sticky_left_columns_source).to include("applyWidthOverride(widths, override)")
|
|
156
|
+
expect(sticky_left_columns_source).to include("var offsets = stickyOffsets(table, count, options)")
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# 幅リセット時は明示幅がないため、クリア後に通常の固定左列再計算へ戻すことを静的に確認する
|
|
160
|
+
it "recalculates sticky-left offsets after clearing a column width" do
|
|
161
|
+
expect(javascript_source).to include("clearColumnWidth(columnId, key)")
|
|
162
|
+
expect(javascript_source).to include("refreshStickyHeaderTable(sourceTable, function()")
|
|
163
|
+
expect(javascript_source).to include("refreshStickyLeftColumns(sourceTable)")
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# ダブルクリックで幅リセットした時も、固定列同期が完了するまで待機カーソルを表示することを静的に確認する
|
|
167
|
+
it "shows a wait cursor while resetting a column width" do
|
|
168
|
+
expect(javascript_source).to include("clearColumnWidth(columnId, key)")
|
|
169
|
+
expect(javascript_source).to include("startApplyingWidth()")
|
|
170
|
+
expect(javascript_source).to include("stopApplyingWidth(null)")
|
|
171
|
+
expect(javascript_source).to include("scheduleStickyRefresh(function()")
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# 幅リセット時は固定ヘッダーの管理幅を先に作り直してから固定左列を再計算することを静的に確認する
|
|
175
|
+
it "rebuilds fixed headers before refreshing sticky-left columns after clearing a width" do
|
|
176
|
+
expect(javascript_source).to include("function refreshStickyHeaderTable(sourceTable, callback)")
|
|
177
|
+
expect(javascript_source).to include("api.refreshTable(sourceTable, callback)")
|
|
178
|
+
expect(javascript_source).to include("scheduleStickyRefresh(callback)")
|
|
179
|
+
expect(sticky_table_headers_source).to include("function refreshTable(sourceTable, callback)")
|
|
180
|
+
expect(sticky_table_headers_source).to include("initializeFixedHeaderForScroll(scroll)")
|
|
181
|
+
expect(sticky_table_headers_source).to include("window.requestAnimationFrame(callback)")
|
|
182
|
+
end
|
|
183
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: yummy-guide-generic-administrate
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.8.
|
|
4
|
+
version: 0.8.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- akatsuki-kk
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-06-
|
|
11
|
+
date: 2026-06-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: administrate
|
|
@@ -142,6 +142,7 @@ files:
|
|
|
142
142
|
- spec/yummy/guide/generic/administrate_spec.rb
|
|
143
143
|
- spec/yummy_guide/administrate/application_dashboard_spec.rb
|
|
144
144
|
- spec/yummy_guide/administrate/collection_helper_spec.rb
|
|
145
|
+
- spec/yummy_guide/administrate/column_resizer_asset_spec.rb
|
|
145
146
|
- spec/yummy_guide/administrate/datetime_filter_parameters_spec.rb
|
|
146
147
|
- spec/yummy_guide/administrate/datetime_input_helper_spec.rb
|
|
147
148
|
- spec/yummy_guide/administrate/fields/json_pretty_field_spec.rb
|