@schukai/monster 4.128.0 → 4.128.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.
- package/package.json +1 -1
- package/source/components/datatable/datatable.mjs +239 -46
- package/source/components/datatable/style/datatable.pcss +5 -0
- package/source/components/datatable/stylesheet/datatable.mjs +1 -1
- package/source/components/style/floating-ui.pcss +8 -0
- package/source/components/stylesheet/floating-ui.mjs +1 -1
- package/source/dom/customelement.mjs +25 -25
- package/source/dom/updater.mjs +25 -21
- package/test/cases/components/datatable/drag-scroll.mjs +258 -0
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"author":"Volker Schukai","dependencies":{"@floating-ui/dom":"^1.7.6","@popperjs/core":"^2.11.8"},"description":"Monster is a simple library for creating fast, robust and lightweight websites.","homepage":"https://monsterjs.org/","keywords":["framework","web","dom","css","sass","mobile-first","app","front-end","templates","schukai","core","shopcloud","alvine","monster","buildmap","stack","observer","observable","uuid","node","nodelist","css-in-js","logger","log","theme"],"license":"AGPL 3.0","main":"source/monster.mjs","module":"source/monster.mjs","name":"@schukai/monster","repository":{"type":"git","url":"https://gitlab.schukai.com/oss/libraries/javascript/monster.git"},"type":"module","version":"4.128.
|
|
1
|
+
{"author":"Volker Schukai","dependencies":{"@floating-ui/dom":"^1.7.6","@popperjs/core":"^2.11.8"},"description":"Monster is a simple library for creating fast, robust and lightweight websites.","homepage":"https://monsterjs.org/","keywords":["framework","web","dom","css","sass","mobile-first","app","front-end","templates","schukai","core","shopcloud","alvine","monster","buildmap","stack","observer","observable","uuid","node","nodelist","css-in-js","logger","log","theme"],"license":"AGPL 3.0","main":"source/monster.mjs","module":"source/monster.mjs","name":"@schukai/monster","repository":{"type":"git","url":"https://gitlab.schukai.com/oss/libraries/javascript/monster.git"},"type":"module","version":"4.128.2"}
|
|
@@ -117,6 +117,12 @@ const columnBarElementSymbol = Symbol("columnBarElement");
|
|
|
117
117
|
*/
|
|
118
118
|
const copyAllElementSymbol = Symbol("copyAllElement");
|
|
119
119
|
|
|
120
|
+
/**
|
|
121
|
+
* @private
|
|
122
|
+
* @type {symbol}
|
|
123
|
+
*/
|
|
124
|
+
const tableScrollElementSymbol = Symbol("tableScrollElement");
|
|
125
|
+
|
|
120
126
|
/**
|
|
121
127
|
* @private
|
|
122
128
|
* @type {symbol}
|
|
@@ -794,6 +800,7 @@ function getCellValueForCopy(cell) {
|
|
|
794
800
|
*/
|
|
795
801
|
function initEventHandler() {
|
|
796
802
|
const self = this;
|
|
803
|
+
const tableScrollElement = this[tableScrollElementSymbol];
|
|
797
804
|
|
|
798
805
|
// --- Column resizing state ---
|
|
799
806
|
let isResizing = false;
|
|
@@ -801,6 +808,166 @@ function initEventHandler() {
|
|
|
801
808
|
let startX = 0;
|
|
802
809
|
let startWidth = 0;
|
|
803
810
|
|
|
811
|
+
// --- Table drag scrolling state ---
|
|
812
|
+
let isTableDragging = false;
|
|
813
|
+
let tableDragMoved = false;
|
|
814
|
+
let tableDragPointerId = null;
|
|
815
|
+
let tableDragStartX = 0;
|
|
816
|
+
let tableDragStartY = 0;
|
|
817
|
+
let tableDragStartScrollLeft = 0;
|
|
818
|
+
let suppressClickUntil = 0;
|
|
819
|
+
|
|
820
|
+
const isInteractiveDragTarget = (event) => {
|
|
821
|
+
if (
|
|
822
|
+
findTargetElementFromEvent(event, "data-monster-role", "resize-handle")
|
|
823
|
+
) {
|
|
824
|
+
return true;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
const path = event.composedPath?.();
|
|
828
|
+
if (!isArray(path)) {
|
|
829
|
+
return false;
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
for (const node of path) {
|
|
833
|
+
if (!(node instanceof HTMLElement)) {
|
|
834
|
+
continue;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
if (node === tableScrollElement) {
|
|
838
|
+
return false;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
if (
|
|
842
|
+
node.matches(
|
|
843
|
+
[
|
|
844
|
+
"button",
|
|
845
|
+
"a",
|
|
846
|
+
"input",
|
|
847
|
+
"select",
|
|
848
|
+
"textarea",
|
|
849
|
+
"label",
|
|
850
|
+
"summary",
|
|
851
|
+
"[contenteditable]",
|
|
852
|
+
"[contenteditable='true']",
|
|
853
|
+
"[draggable='true']",
|
|
854
|
+
"[role='button']",
|
|
855
|
+
"[role='link']",
|
|
856
|
+
"[role='textbox']",
|
|
857
|
+
"[role='checkbox']",
|
|
858
|
+
"[role='switch']",
|
|
859
|
+
"[role='menuitem']",
|
|
860
|
+
].join(","),
|
|
861
|
+
)
|
|
862
|
+
) {
|
|
863
|
+
return true;
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
return false;
|
|
868
|
+
};
|
|
869
|
+
|
|
870
|
+
const stopTableDragging = () => {
|
|
871
|
+
if (tableScrollElement instanceof HTMLElement) {
|
|
872
|
+
tableScrollElement.classList.remove("is-dragging");
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
getWindow().removeEventListener("pointermove", onTablePointerMove);
|
|
876
|
+
getWindow().removeEventListener("pointerup", onTablePointerUp);
|
|
877
|
+
getWindow().removeEventListener("pointercancel", onTablePointerUp);
|
|
878
|
+
|
|
879
|
+
if (tableDragPointerId !== null) {
|
|
880
|
+
tableScrollElement?.releasePointerCapture?.(tableDragPointerId);
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
isTableDragging = false;
|
|
884
|
+
tableDragMoved = false;
|
|
885
|
+
tableDragPointerId = null;
|
|
886
|
+
};
|
|
887
|
+
|
|
888
|
+
const onTablePointerDown = (event) => {
|
|
889
|
+
if (!(tableScrollElement instanceof HTMLElement)) {
|
|
890
|
+
return;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
if (
|
|
894
|
+
(event.pointerType === "mouse" && event.button !== 0) ||
|
|
895
|
+
event.isPrimary === false
|
|
896
|
+
) {
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
if (tableScrollElement.scrollWidth <= tableScrollElement.clientWidth) {
|
|
901
|
+
return;
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
if (isInteractiveDragTarget(event)) {
|
|
905
|
+
return;
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
isTableDragging = true;
|
|
909
|
+
tableDragMoved = false;
|
|
910
|
+
tableDragPointerId = event.pointerId;
|
|
911
|
+
tableDragStartX = event.clientX;
|
|
912
|
+
tableDragStartY = event.clientY;
|
|
913
|
+
tableDragStartScrollLeft = tableScrollElement.scrollLeft;
|
|
914
|
+
|
|
915
|
+
tableScrollElement.setPointerCapture?.(event.pointerId);
|
|
916
|
+
getWindow().addEventListener("pointermove", onTablePointerMove);
|
|
917
|
+
getWindow().addEventListener("pointerup", onTablePointerUp);
|
|
918
|
+
getWindow().addEventListener("pointercancel", onTablePointerUp);
|
|
919
|
+
};
|
|
920
|
+
|
|
921
|
+
const onTablePointerMove = (event) => {
|
|
922
|
+
if (
|
|
923
|
+
!isTableDragging ||
|
|
924
|
+
tableDragPointerId === null ||
|
|
925
|
+
event.pointerId !== tableDragPointerId ||
|
|
926
|
+
!(tableScrollElement instanceof HTMLElement)
|
|
927
|
+
) {
|
|
928
|
+
return;
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
const deltaX = event.clientX - tableDragStartX;
|
|
932
|
+
const deltaY = event.clientY - tableDragStartY;
|
|
933
|
+
|
|
934
|
+
if (!tableDragMoved) {
|
|
935
|
+
if (Math.abs(deltaX) < 8 || Math.abs(deltaX) <= Math.abs(deltaY)) {
|
|
936
|
+
return;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
tableDragMoved = true;
|
|
940
|
+
tableScrollElement.classList.add("is-dragging");
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
event.preventDefault();
|
|
944
|
+
tableScrollElement.scrollLeft = tableDragStartScrollLeft - deltaX;
|
|
945
|
+
};
|
|
946
|
+
|
|
947
|
+
const onTablePointerUp = (event) => {
|
|
948
|
+
if (tableDragPointerId === null || event.pointerId !== tableDragPointerId) {
|
|
949
|
+
return;
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
if (tableDragMoved) {
|
|
953
|
+
suppressClickUntil = Date.now() + 250;
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
stopTableDragging();
|
|
957
|
+
};
|
|
958
|
+
|
|
959
|
+
const onTableClickCapture = (event) => {
|
|
960
|
+
if (suppressClickUntil < Date.now()) {
|
|
961
|
+
return;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
event.preventDefault();
|
|
965
|
+
event.stopPropagation();
|
|
966
|
+
};
|
|
967
|
+
|
|
968
|
+
tableScrollElement?.addEventListener("pointerdown", onTablePointerDown);
|
|
969
|
+
tableScrollElement?.addEventListener("click", onTableClickCapture, true);
|
|
970
|
+
|
|
804
971
|
// --- Pointer-based resize handlers (robust for mouse/touch/stylus) ---
|
|
805
972
|
const onPointerDown = (event) => {
|
|
806
973
|
// Important: Call helper with (attrName, value) – not with CSS selector
|
|
@@ -879,6 +1046,58 @@ function initEventHandler() {
|
|
|
879
1046
|
const delimiterChar = this.getOption("copy.delimiter");
|
|
880
1047
|
const rowBreak = this.getOption("copy.rowBreak");
|
|
881
1048
|
|
|
1049
|
+
const writeTextToClipboard = (text) => {
|
|
1050
|
+
if (getWindow().navigator.clipboard && text) {
|
|
1051
|
+
getWindow()
|
|
1052
|
+
.navigator.clipboard.writeText(text)
|
|
1053
|
+
.then(
|
|
1054
|
+
() => {},
|
|
1055
|
+
() => {},
|
|
1056
|
+
);
|
|
1057
|
+
}
|
|
1058
|
+
};
|
|
1059
|
+
|
|
1060
|
+
const getCopyTextForRow = (headCell) => {
|
|
1061
|
+
const index = headCell.getAttribute("data-monster-insert-reference");
|
|
1062
|
+
if (!index) {
|
|
1063
|
+
return "";
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
const cols = self.getGridElements(
|
|
1067
|
+
`[data-monster-insert-reference="${index}"]`,
|
|
1068
|
+
);
|
|
1069
|
+
const colTexts = [];
|
|
1070
|
+
|
|
1071
|
+
for (let i = 0; i < cols.length; i++) {
|
|
1072
|
+
const col = cols[i];
|
|
1073
|
+
|
|
1074
|
+
if (
|
|
1075
|
+
col.querySelector("monster-button-bar") ||
|
|
1076
|
+
col.querySelector("monster-button")
|
|
1077
|
+
) {
|
|
1078
|
+
continue;
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
const cellValue = getCellValueForCopy(col);
|
|
1082
|
+
if (cellValue) {
|
|
1083
|
+
colTexts.push(quoteOpenChar + cellValue + quoteCloseChar);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
return colTexts.join(delimiterChar);
|
|
1088
|
+
};
|
|
1089
|
+
|
|
1090
|
+
const getCopyTextForCell = (headCell) => {
|
|
1091
|
+
if (
|
|
1092
|
+
headCell.querySelector("monster-button-bar") ||
|
|
1093
|
+
headCell.querySelector("monster-button")
|
|
1094
|
+
) {
|
|
1095
|
+
return "";
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
return getCellValueForCopy(headCell);
|
|
1099
|
+
};
|
|
1100
|
+
|
|
882
1101
|
// --- Column-Bar -> Header visibility & persistence ---
|
|
883
1102
|
if (self[columnBarElementSymbol]) {
|
|
884
1103
|
self[columnBarElementSymbol].attachObserver(
|
|
@@ -917,60 +1136,30 @@ function initEventHandler() {
|
|
|
917
1136
|
}
|
|
918
1137
|
});
|
|
919
1138
|
|
|
920
|
-
// ---
|
|
921
|
-
const
|
|
1139
|
+
// --- Copy interactions ---
|
|
1140
|
+
const eventHandlerShiftClickCopyRowToClipboard = (event) => {
|
|
922
1141
|
const headCell = findTargetElementFromEvent(event, "data-monster-head");
|
|
923
|
-
if (!headCell)
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
if (event.shiftKey) {
|
|
928
|
-
const index = headCell.getAttribute("data-monster-insert-reference");
|
|
929
|
-
if (index) {
|
|
930
|
-
const cols = self.getGridElements(
|
|
931
|
-
`[data-monster-insert-reference="${index}"]`,
|
|
932
|
-
);
|
|
933
|
-
|
|
934
|
-
const colTexts = [];
|
|
935
|
-
for (let i = 0; i < cols.length; i++) {
|
|
936
|
-
const col = cols[i];
|
|
937
|
-
|
|
938
|
-
if (
|
|
939
|
-
col.querySelector("monster-button-bar") ||
|
|
940
|
-
col.querySelector("monster-button")
|
|
941
|
-
) {
|
|
942
|
-
continue;
|
|
943
|
-
}
|
|
1142
|
+
if (!headCell || !event.shiftKey) {
|
|
1143
|
+
return;
|
|
1144
|
+
}
|
|
944
1145
|
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
colTexts.push(quoteOpenChar + cellValue + quoteCloseChar);
|
|
948
|
-
}
|
|
949
|
-
}
|
|
1146
|
+
writeTextToClipboard(getCopyTextForRow(headCell));
|
|
1147
|
+
};
|
|
950
1148
|
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
headCell.querySelector("monster-button-bar") ||
|
|
956
|
-
headCell.querySelector("monster-button")
|
|
957
|
-
) {
|
|
958
|
-
return;
|
|
959
|
-
}
|
|
960
|
-
text = getCellValueForCopy(headCell);
|
|
1149
|
+
const eventHandlerDoubleClickCopyToClipboard = (event) => {
|
|
1150
|
+
const headCell = findTargetElementFromEvent(event, "data-monster-head");
|
|
1151
|
+
if (!headCell || event.shiftKey) {
|
|
1152
|
+
return;
|
|
961
1153
|
}
|
|
962
1154
|
|
|
963
|
-
|
|
964
|
-
getWindow()
|
|
965
|
-
.navigator.clipboard.writeText(text)
|
|
966
|
-
.then(
|
|
967
|
-
() => {},
|
|
968
|
-
() => {},
|
|
969
|
-
);
|
|
970
|
-
}
|
|
1155
|
+
writeTextToClipboard(getCopyTextForCell(headCell));
|
|
971
1156
|
};
|
|
972
1157
|
|
|
973
1158
|
if (self.getOption("features.doubleClickCopyToClipboard")) {
|
|
1159
|
+
self[gridElementSymbol].addEventListener(
|
|
1160
|
+
"click",
|
|
1161
|
+
eventHandlerShiftClickCopyRowToClipboard,
|
|
1162
|
+
);
|
|
974
1163
|
self[gridElementSymbol].addEventListener(
|
|
975
1164
|
"dblclick",
|
|
976
1165
|
eventHandlerDoubleClickCopyToClipboard,
|
|
@@ -1537,6 +1726,10 @@ function initControlReferences() {
|
|
|
1537
1726
|
"[data-monster-role=copy-all]",
|
|
1538
1727
|
);
|
|
1539
1728
|
|
|
1729
|
+
this[tableScrollElementSymbol] = this.shadowRoot.querySelector(
|
|
1730
|
+
"[data-monster-role=table-scroll]",
|
|
1731
|
+
);
|
|
1732
|
+
|
|
1540
1733
|
return this;
|
|
1541
1734
|
}
|
|
1542
1735
|
|