yummy-guide-generic-administrate 0.8.1 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e0c5692ebb60bfcc4d51157cdca7e52f974523f546c0d75ab5e3b350815a5316
4
- data.tar.gz: 9f398e159619da8c35955fcaaa0a2d2c7a1df5249154486c95326a5fe99e6b1d
3
+ metadata.gz: 55b8c25b868ffa217ed45c64c2c0b53aa46bdb9d60094c022d9979cdd7a4e013
4
+ data.tar.gz: 4889ad38b64d46b34ce69f7e5cb4819c53d71a9c13636096dc94a5721e94fa87
5
5
  SHA512:
6
- metadata.gz: 92ea6916e4083ad8dc0301f48df920d11f63a7f028846fbbdd6d9886b7b29eb30f0e812e2fa413b8db23de600050460867ec9a93d0d799124032619cc552b3fb
7
- data.tar.gz: 688558efd455e8a364b0a7a070e2f088fdd4adb6684a4b143e37438cd8a5d8192f49918d834afba7478851b075c1984570e5d6666bdd04850f229167102a03fe
6
+ metadata.gz: e85e0d5ef1a103b6f72b9544dabc6ec02118bd4c845c2dabffaa47e4b4d66de21cf227277e196ee70c4285aa76721766d9c8a465665c233e7e22a68ba32d9b2a
7
+ data.tar.gz: 508817a41590cac77f1b1f3ecfbb676784ee6e5655dd1336f2e0216c5700100c9c66f6a36c56830c4f8ee611a0ae117cf2a6ee220b82eb5b77913af54d50e708
@@ -16,6 +16,7 @@
16
16
  var dragState = null;
17
17
  var dragPreviewFrame = null;
18
18
  var widthApplyFrame = null;
19
+ var pendingWidthApply = null;
19
20
  var generatedRuleCount = 0;
20
21
  var initializedHandles = new WeakSet();
21
22
  var tableStates = new WeakMap();
@@ -568,6 +569,30 @@
568
569
  return event.pointerType !== 'mouse' || event.button === 0;
569
570
  }
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();
582
+ }
583
+
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;
594
+ }
595
+
571
596
  function scheduleDragWidth(width) {
572
597
  dragState.currentWidth = width;
573
598
  dragState.moved = dragState.moved || Math.abs(width - dragState.startWidth) > 2;
@@ -601,6 +626,18 @@
601
626
  scheduleStickyRefresh(callback);
602
627
  }
603
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
+
604
641
  function refreshStickyLeftColumns(sourceTable) {
605
642
  var api = window.YummyGuideAdministrateStickyLeftColumns;
606
643
 
@@ -609,19 +646,61 @@
609
646
  }
610
647
  }
611
648
 
612
- function stopApplyingWidth(preview) {
613
- removePreview(preview);
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() {
614
673
  applyingWidth = false;
615
674
  document.body.classList.remove(APPLYING_BODY_CLASS);
616
675
  }
617
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
+
618
697
  function applyPendingWidth(pendingWidth) {
619
698
  try {
620
699
  var widths = safeReadWidths(pendingWidth.storageKey);
621
700
  applyColumnWidth(pendingWidth.columnId, pendingWidth.width, pendingWidth.storageKey);
622
701
  widths[pendingWidth.columnId] = preciseNumber(pendingWidth.width);
623
702
  safeWriteWidths(pendingWidth.storageKey, widths);
624
- refreshStickyLeftColumns(pendingWidth.sourceTable);
703
+ refreshStickyLeftColumnsForWidth(pendingWidth);
625
704
  refreshStickyHeaderColumn(pendingWidth, function() {
626
705
  stopApplyingWidth(pendingWidth.preview);
627
706
  });
@@ -632,8 +711,8 @@
632
711
  }
633
712
 
634
713
  function schedulePendingWidthApply(pendingWidth) {
635
- applyingWidth = true;
636
- document.body.classList.add(APPLYING_BODY_CLASS);
714
+ pendingWidthApply = pendingWidth;
715
+ startApplyingWidth();
637
716
 
638
717
  widthApplyFrame = window.requestAnimationFrame(function() {
639
718
  widthApplyFrame = window.requestAnimationFrame(function() {
@@ -705,6 +784,8 @@
705
784
  }
706
785
 
707
786
  flushDragPreview();
787
+ var pointerCancelled = event && event.type === 'pointercancel';
788
+ var shouldApplyWidth = dragState.moved && !pointerCancelled;
708
789
 
709
790
  var pendingWidth = {
710
791
  columnId: dragState.columnId,
@@ -714,12 +795,9 @@
714
795
  preview: dragState.preview
715
796
  };
716
797
 
717
- releaseDragPointerCapture();
718
- dragState = null;
719
- document.body.classList.remove(DRAGGING_BODY_CLASS);
720
- document.removeEventListener('pointermove', handleDragMove);
721
- document.removeEventListener('pointerup', finishDrag);
722
- document.removeEventListener('pointercancel', finishDrag);
798
+ stopDragging(!shouldApplyWidth);
799
+ if (!shouldApplyWidth) return;
800
+
723
801
  schedulePendingWidthApply(pendingWidth);
724
802
  }
725
803
 
@@ -733,6 +811,8 @@
733
811
 
734
812
  event.preventDefault();
735
813
  event.stopPropagation();
814
+ cancelPendingWidthApply();
815
+ stopDragging(true);
736
816
 
737
817
  var sourceTable = sourceTableForHandle(handle);
738
818
  var key = storageKeyForTable(sourceTable || handle.closest(TABLE_SELECTOR));
@@ -740,7 +820,17 @@
740
820
  delete widths[columnId];
741
821
  safeWriteWidths(key, widths);
742
822
  clearColumnWidth(columnId, key);
743
- scheduleStickyRefresh();
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
+ }
744
834
  }
745
835
 
746
836
  function stopHandleClick(event) {
@@ -25,6 +25,37 @@
25
25
  return preciseNumber(value) + "px";
26
26
  }
27
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
+
28
59
  function resetStickyColumns(table) {
29
60
  table.querySelectorAll(".sticky-left").forEach(function(cell) {
30
61
  cell.classList.remove("sticky-left", "sticky-left--last");
@@ -47,15 +78,18 @@
47
78
  return window.matchMedia && window.matchMedia(MOBILE_MEDIA_QUERY).matches;
48
79
  }
49
80
 
50
- function stickyOffsets(table, count) {
81
+ function stickyOffsets(table, count, options) {
51
82
  var headerRow = table.querySelector("thead tr");
52
83
  if (!headerRow) return [];
53
84
 
54
- var widths = directCells(headerRow).slice(0, count).map(function(cell) {
85
+ var headerCells = directCells(headerRow);
86
+ var override = widthOverride(headerCells, options);
87
+ var widths = headerCells.slice(0, count).map(function(cell) {
55
88
  return measuredWidth(cell);
56
89
  });
90
+ var hasMeasuredWidth = widths.some(Boolean);
57
91
 
58
- if (!widths.some(Boolean)) {
92
+ if (!hasMeasuredWidth) {
59
93
  Array.from(table.querySelectorAll("tbody tr, tfoot tr")).some(function(row) {
60
94
  var cells = directCells(row);
61
95
  if (cells.length < count || cells.some(function(cell) { return cell.colSpan > 1; })) return false;
@@ -67,6 +101,8 @@
67
101
  });
68
102
  }
69
103
 
104
+ applyWidthOverride(widths, override);
105
+
70
106
  var offsets = [];
71
107
  var currentLeft = 0;
72
108
 
@@ -78,13 +114,13 @@
78
114
  return offsets;
79
115
  }
80
116
 
81
- function applyStickyColumns(table) {
117
+ function applyStickyColumns(table, options) {
82
118
  resetStickyColumns(table);
83
119
 
84
120
  var count = fixedColumnsCount(table);
85
121
  if (count === 0) return;
86
122
 
87
- var offsets = stickyOffsets(table, count);
123
+ var offsets = stickyOffsets(table, count, options);
88
124
  if (offsets.length === 0) return;
89
125
 
90
126
  table.querySelectorAll("thead tr, tbody tr, tfoot tr").forEach(function(row) {
@@ -127,6 +163,21 @@
127
163
  return true;
128
164
  }
129
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
+
130
181
  function observeStickyColumns(table) {
131
182
  if (!window.ResizeObserver || resizeObservers.has(table)) return;
132
183
 
@@ -181,6 +232,7 @@
181
232
  window.addEventListener("resize", initializeFromDocument);
182
233
 
183
234
  window.YummyGuideAdministrateStickyLeftColumns = {
235
+ refreshColumnWidth: refreshColumnWidth,
184
236
  refreshTable: refreshTable
185
237
  };
186
238
 
@@ -678,6 +678,22 @@
678
678
  return true;
679
679
  }
680
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
+
681
697
  function buildFixedTableHeader(slot, scroll, sourceTable) {
682
698
  if (!slot || !scroll || !sourceTable) return;
683
699
 
@@ -870,7 +886,8 @@
870
886
  window.addEventListener('resize', initializeFromDocument);
871
887
 
872
888
  window.YummyGuideAdministrateStickyTableHeaders = {
873
- refreshColumnWidth: refreshColumnWidth
889
+ refreshColumnWidth: refreshColumnWidth,
890
+ refreshTable: refreshTable
874
891
  };
875
892
 
876
893
  if (window.MutationObserver) {
@@ -2,6 +2,6 @@
2
2
 
3
3
  module YummyGuide
4
4
  module Administrate
5
- VERSION = "0.8.1"
5
+ VERSION = "0.8.2"
6
6
  end
7
7
  end
@@ -59,6 +59,22 @@ RSpec.describe "column resizer assets" do
59
59
  expect(javascript_source).not_to include("applyColumnWidth(dragState.columnId, dragState.currentWidth")
60
60
  end
61
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
+
62
78
  # ドラッグ中の調整後幅を半透明カラムで表示するCSSがあることを確認する
63
79
  it "defines a translucent column preview" do
64
80
  expect(stylesheet_source).to include(".admin-column-resizer__preview")
@@ -83,6 +99,7 @@ RSpec.describe "column resizer assets" do
83
99
  # 幅の適用中だけ待機カーソルを表示することを静的に確認する
84
100
  it "shows a wait cursor while applying the final width" do
85
101
  expect(javascript_source).to include("APPLYING_BODY_CLASS = 'admin-column-resizer--applying'")
102
+ expect(javascript_source).to include("function startApplyingWidth()")
86
103
  expect(javascript_source).to include("document.body.classList.add(APPLYING_BODY_CLASS)")
87
104
  expect(javascript_source).to include("document.body.classList.remove(APPLYING_BODY_CLASS)")
88
105
  expect(stylesheet_source).to include(".admin-column-resizer--applying")
@@ -105,6 +122,7 @@ RSpec.describe "column resizer assets" do
105
122
  expect(javascript_source).to include("api.refreshColumnWidth({")
106
123
  expect(sticky_table_headers_source).to include("window.YummyGuideAdministrateStickyTableHeaders = {")
107
124
  expect(sticky_table_headers_source).to include("refreshColumnWidth: refreshColumnWidth")
125
+ expect(sticky_table_headers_source).to include("refreshTable: refreshTable")
108
126
  expect(sticky_table_headers_source).to include("function refreshColumnWidth(options)")
109
127
  expect(sticky_table_headers_source).to include("applySourceColumnMinWidth(sourceTable, columnIndex, columnCount, width)")
110
128
  expect(sticky_table_headers_source).to include("applyFixedHeaderCellWidth(fixedTable, columnIndex, width)")
@@ -114,11 +132,52 @@ RSpec.describe "column resizer assets" do
114
132
  # 幅適用後の固定左列追従もResizeObserverの重複再計算に頼らないことを静的に確認する
115
133
  it "refreshes sticky left columns directly after applying a width" do
116
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")
117
139
  expect(javascript_source).to include("api.refreshTable(sourceTable)")
118
140
  expect(javascript_source).to include("refreshStickyLeftColumns(pendingWidth.sourceTable)")
119
141
  expect(sticky_left_columns_source).to include("window.YummyGuideAdministrateStickyLeftColumns = {")
142
+ expect(sticky_left_columns_source).to include("refreshColumnWidth: refreshColumnWidth")
120
143
  expect(sticky_left_columns_source).to include("refreshTable: refreshTable")
121
144
  expect(sticky_left_columns_source).to include("function refreshTable(table)")
145
+ expect(sticky_left_columns_source).to include("function refreshColumnWidth(options)")
122
146
  expect(sticky_left_columns_source).to include("suppressResizeApply(table)")
123
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
124
183
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yummy-guide-generic-administrate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.1
4
+ version: 0.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - akatsuki-kk