@jh-grid/jhgrid-js 0.1.0 → 0.1.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/README.md +21 -5
- package/dist/jhgrid.esm.js +146 -76
- package/dist/jhgrid.js +146 -76
- package/dist/jhgrid.min.js +37 -37
- package/package.json +1 -1
package/dist/jhgrid.js
CHANGED
|
@@ -44,6 +44,14 @@ var JHGrid = (() => {
|
|
|
44
44
|
#chunkSize;
|
|
45
45
|
#maxChunks;
|
|
46
46
|
#cache = /* @__PURE__ */ new Map();
|
|
47
|
+
// 1-entry cache of the chunk getRow() touched last. A bulk row-major walk (e.g. clearing an
|
|
48
|
+
// entire selection) calls getRow() for every column of the same row back-to-back -- same
|
|
49
|
+
// chunkIdx every time -- and #chunkSize more rows after that before it changes, so this turns
|
|
50
|
+
// the overwhelming majority of getRow() calls into a single index comparison instead of a Map
|
|
51
|
+
// lookup plus the LRU delete+re-insert below. Must be invalidated everywhere #cache forgets a
|
|
52
|
+
// chunk (#evict, clear) so it can never serve an entry #cache itself no longer considers current.
|
|
53
|
+
#lastChunkIdx = -1;
|
|
54
|
+
#lastChunk = null;
|
|
47
55
|
#fetching = /* @__PURE__ */ new Set();
|
|
48
56
|
#failed = /* @__PURE__ */ new Set();
|
|
49
57
|
#failedTimers = /* @__PURE__ */ new Set();
|
|
@@ -77,10 +85,13 @@ var JHGrid = (() => {
|
|
|
77
85
|
// re-request after onChunkLoaded).
|
|
78
86
|
getRow(rowIndex) {
|
|
79
87
|
const chunkIdx = Math.floor(rowIndex / this.#chunkSize);
|
|
88
|
+
if (chunkIdx === this.#lastChunkIdx) return this.#lastChunk[rowIndex % this.#chunkSize] ?? null;
|
|
80
89
|
if (this.#cache.has(chunkIdx)) {
|
|
81
90
|
const chunk = this.#cache.get(chunkIdx);
|
|
82
91
|
this.#cache.delete(chunkIdx);
|
|
83
92
|
this.#cache.set(chunkIdx, chunk);
|
|
93
|
+
this.#lastChunkIdx = chunkIdx;
|
|
94
|
+
this.#lastChunk = chunk;
|
|
84
95
|
return chunk[rowIndex % this.#chunkSize] ?? null;
|
|
85
96
|
}
|
|
86
97
|
this.#request(chunkIdx);
|
|
@@ -241,6 +252,10 @@ var JHGrid = (() => {
|
|
|
241
252
|
while (this.#cache.size > this.#maxChunks) {
|
|
242
253
|
const oldest = this.#cache.keys().next().value;
|
|
243
254
|
this.#cache.delete(oldest);
|
|
255
|
+
if (oldest === this.#lastChunkIdx) {
|
|
256
|
+
this.#lastChunkIdx = -1;
|
|
257
|
+
this.#lastChunk = null;
|
|
258
|
+
}
|
|
244
259
|
}
|
|
245
260
|
}
|
|
246
261
|
// Returning `false` from `callback` stops the walk. Callers that are looking for an answer
|
|
@@ -267,6 +282,8 @@ var JHGrid = (() => {
|
|
|
267
282
|
this.#failed.clear();
|
|
268
283
|
this.#failedTimers.forEach(clearTimeout);
|
|
269
284
|
this.#failedTimers.clear();
|
|
285
|
+
this.#lastChunkIdx = -1;
|
|
286
|
+
this.#lastChunk = null;
|
|
270
287
|
}
|
|
271
288
|
};
|
|
272
289
|
|
|
@@ -4354,6 +4371,12 @@ var JHGrid = (() => {
|
|
|
4354
4371
|
multiSortEnabled,
|
|
4355
4372
|
i18n,
|
|
4356
4373
|
theme,
|
|
4374
|
+
// wrapperHeight + openUpward: when the caller found more room above the header than below (a
|
|
4375
|
+
// grid scrolled to sit low on the page — see _openFilterPanel), the panel anchors its *bottom*
|
|
4376
|
+
// to the header's top edge and grows upward instead of down, same as a native <select> flipping
|
|
4377
|
+
// when it would otherwise overflow the viewport.
|
|
4378
|
+
wrapperHeight,
|
|
4379
|
+
openUpward,
|
|
4357
4380
|
// Set filter (checkbox list of exact values) — distinctValues is null when the column has too
|
|
4358
4381
|
// many/no loaded values yet, in which case the panel falls back to the plain text search box
|
|
4359
4382
|
// below instead of rendering a checklist. selectedValues is the currently-applied array filter
|
|
@@ -4378,7 +4401,6 @@ var JHGrid = (() => {
|
|
|
4378
4401
|
}) {
|
|
4379
4402
|
const PANEL_W = 220;
|
|
4380
4403
|
const panelX = Math.max(0, Math.min(colLeft, width - PANEL_W));
|
|
4381
|
-
const panelY = headerH;
|
|
4382
4404
|
const s = (...parts) => parts.join(";");
|
|
4383
4405
|
const btn = (text, action, style) => {
|
|
4384
4406
|
const b = document.createElement("button");
|
|
@@ -4397,7 +4419,10 @@ var JHGrid = (() => {
|
|
|
4397
4419
|
el.style.cssText = s(
|
|
4398
4420
|
`position:absolute`,
|
|
4399
4421
|
`left:${panelX}px`,
|
|
4400
|
-
|
|
4422
|
+
// Anchoring the bottom edge (instead of top) lets the panel grow upward from the header
|
|
4423
|
+
// without knowing its own height up front — the alternative, computing `top: headerH -
|
|
4424
|
+
// panelHeight`, needs the rendered height before it's laid out.
|
|
4425
|
+
openUpward ? `bottom:${Math.max(0, wrapperHeight - headerH)}px` : `top:${headerH}px`,
|
|
4401
4426
|
`width:${PANEL_W}px`,
|
|
4402
4427
|
`background:${themed(theme, "overlayBg")}`,
|
|
4403
4428
|
`border:1px solid ${themed(theme, "overlayBorder")}`,
|
|
@@ -5963,6 +5988,8 @@ ${title ? `<h2>${esc(title)}</h2>` : ""}
|
|
|
5963
5988
|
// JHGrid.js
|
|
5964
5989
|
var ARROWS = { ArrowDown: [1, 0], ArrowUp: [-1, 0], ArrowRight: [0, 1], ArrowLeft: [0, -1] };
|
|
5965
5990
|
var RESIZE_HIT_W = 5;
|
|
5991
|
+
var RESIZE_HIT_W_TOUCH = 8;
|
|
5992
|
+
var CANVAS_TOUCH_CSS = "touch-action:none;-webkit-touch-callout:none;-webkit-tap-highlight-color:transparent;";
|
|
5966
5993
|
var MIN_COL_W = 30;
|
|
5967
5994
|
var MIN_ROW_H = 16;
|
|
5968
5995
|
var LONG_PRESS_MS = 500;
|
|
@@ -6384,7 +6411,7 @@ ${title ? `<h2>${esc(title)}</h2>` : ""}
|
|
|
6384
6411
|
this._canvas = document.createElement("canvas");
|
|
6385
6412
|
this._canvas.width = Math.round(width * dpr);
|
|
6386
6413
|
this._canvas.height = Math.round(height * dpr);
|
|
6387
|
-
this._canvas.style.cssText = `display:block;width:${width}px;height:${height}px;outline:none
|
|
6414
|
+
this._canvas.style.cssText = `display:block;width:${width}px;height:${height}px;outline:none;${CANVAS_TOUCH_CSS}`;
|
|
6388
6415
|
this._canvas.setAttribute("aria-hidden", "true");
|
|
6389
6416
|
this._canvas.tabIndex = -1;
|
|
6390
6417
|
this._canvas.getContext("2d").scale(dpr, dpr);
|
|
@@ -6614,7 +6641,7 @@ ${title ? `<h2>${esc(title)}</h2>` : ""}
|
|
|
6614
6641
|
this._opts.height = gridHeight;
|
|
6615
6642
|
this._wrapper.style.width = width + "px";
|
|
6616
6643
|
this._wrapper.style.height = gridHeight + "px";
|
|
6617
|
-
this._canvas.style.cssText = `display:block;width:${width}px;height:${gridHeight}px;outline:none
|
|
6644
|
+
this._canvas.style.cssText = `display:block;width:${width}px;height:${gridHeight}px;outline:none;${CANVAS_TOUCH_CSS}`;
|
|
6618
6645
|
const dpr = window.devicePixelRatio || 1;
|
|
6619
6646
|
this._canvas.width = Math.round(width * dpr);
|
|
6620
6647
|
this._canvas.height = Math.round(gridHeight * dpr);
|
|
@@ -7039,29 +7066,85 @@ ${title ? `<h2>${esc(title)}</h2>` : ""}
|
|
|
7039
7066
|
// of, or null. Checks both the hovered row's bottom edge and (falling back, like the column
|
|
7040
7067
|
// check does with col > 0) the previous row's bottom edge when y lands right at a row's top
|
|
7041
7068
|
// edge — both branches identify the same boundary line, resolving to "the row above it".
|
|
7042
|
-
_hitRowBoundary(y, geo = this._geo()) {
|
|
7069
|
+
_hitRowBoundary(y, geo = this._geo(), hitW = RESIZE_HIT_W) {
|
|
7043
7070
|
const { height: H } = this._opts;
|
|
7044
7071
|
if (y < geo.headerH || y >= H - geo.hSB) return null;
|
|
7045
7072
|
const relY = y - geo.headerH + this._scrollTop;
|
|
7046
7073
|
const row = this._rowLayout.rowAt(relY, this._totalRows - 1);
|
|
7047
7074
|
if (row < 0) return null;
|
|
7048
7075
|
const bottomY = this._rowLayout.yOf(row + 1) - this._scrollTop + geo.headerH;
|
|
7049
|
-
if (Math.abs(y - bottomY) <=
|
|
7076
|
+
if (Math.abs(y - bottomY) <= hitW) return row;
|
|
7050
7077
|
if (row > 0) {
|
|
7051
7078
|
const topY = this._rowLayout.yOf(row) - this._scrollTop + geo.headerH;
|
|
7052
|
-
if (Math.abs(y - topY) <=
|
|
7079
|
+
if (Math.abs(y - topY) <= hitW) return row - 1;
|
|
7053
7080
|
}
|
|
7054
7081
|
return null;
|
|
7055
7082
|
}
|
|
7056
|
-
|
|
7083
|
+
// Vertical/horizontal scrollbar hit test, shared by mousedown and touchstart: grabbing the
|
|
7084
|
+
// thumb arms this._drag (consumed by _updateScrollbarDrag on the matching move handler),
|
|
7085
|
+
// tapping the bare track jump-scrolls straight to that position, same as a native scrollbar.
|
|
7086
|
+
// Returns whether (x, y) was inside either scrollbar's hit area at all, so the caller knows to
|
|
7087
|
+
// stop dispatching (preventDefault + return) instead of falling through to header/cell/pan
|
|
7088
|
+
// handling — without this, a touch on the drawn scrollbar was indistinguishable from a touch
|
|
7089
|
+
// anywhere else on the canvas and just started a generic content-drag pan.
|
|
7090
|
+
_hitScrollbar(x, y, geo) {
|
|
7091
|
+
const { v, h } = geo;
|
|
7092
|
+
if (x >= v.x) {
|
|
7093
|
+
if (y >= v.thumbY && y <= v.thumbY + v.thumbH) {
|
|
7094
|
+
this._drag = { axis: "v", startMouse: y, startScroll: this._scrollTop };
|
|
7095
|
+
} else if (y >= v.y && y <= v.y + v.h) {
|
|
7096
|
+
const ratio = Math.max(0, Math.min(1, (y - v.y - v.thumbH / 2) / (v.h - v.thumbH)));
|
|
7097
|
+
this._scrollTop = geo.minScrollY + ratio * (geo.maxScrollY - geo.minScrollY);
|
|
7098
|
+
this._clamp(geo);
|
|
7099
|
+
this._draw();
|
|
7100
|
+
}
|
|
7101
|
+
return true;
|
|
7102
|
+
}
|
|
7103
|
+
if (y >= h.y) {
|
|
7104
|
+
if (x >= h.thumbX && x <= h.thumbX + h.thumbW) {
|
|
7105
|
+
this._drag = { axis: "h", startMouse: x, startScroll: this._scrollLeft };
|
|
7106
|
+
} else if (x >= h.x && x <= h.x + h.w) {
|
|
7107
|
+
const ratio = Math.max(0, Math.min(1, (x - h.x - h.thumbW / 2) / (h.w - h.thumbW)));
|
|
7108
|
+
this._scrollLeft = ratio * geo.maxScrollX;
|
|
7109
|
+
this._clamp(geo);
|
|
7110
|
+
this._draw();
|
|
7111
|
+
}
|
|
7112
|
+
return true;
|
|
7113
|
+
}
|
|
7114
|
+
return false;
|
|
7115
|
+
}
|
|
7116
|
+
// Applies an in-progress scrollbar thumb drag (this._drag, armed by _hitScrollbar) given the
|
|
7117
|
+
// pointer/touch's current raw canvas coordinates. Shared by mousemove and touchmove so the two
|
|
7118
|
+
// input paths can't drift apart.
|
|
7119
|
+
_updateScrollbarDrag(x, y) {
|
|
7120
|
+
const geo = this._geo();
|
|
7121
|
+
const { v, h } = geo;
|
|
7122
|
+
if (this._drag.axis === "v") {
|
|
7123
|
+
const ratio = (y - this._drag.startMouse) / (v.h - v.thumbH);
|
|
7124
|
+
this._scrollTop = this._drag.startScroll + ratio * (geo.maxScrollY - geo.minScrollY);
|
|
7125
|
+
} else {
|
|
7126
|
+
const ratio = (x - this._drag.startMouse) / (h.w - h.thumbW);
|
|
7127
|
+
this._scrollLeft = this._drag.startScroll + ratio * geo.maxScrollX;
|
|
7128
|
+
}
|
|
7129
|
+
this._clamp(geo);
|
|
7130
|
+
this._scrolling = true;
|
|
7131
|
+
this._dm.setHold(true);
|
|
7132
|
+
clearTimeout(this._scrollEndTimer);
|
|
7133
|
+
this._scrollEndTimer = setTimeout(() => {
|
|
7134
|
+
this._scrolling = false;
|
|
7135
|
+
this._dm.setHold(false);
|
|
7136
|
+
this._schedDraw();
|
|
7137
|
+
}, 150);
|
|
7138
|
+
this._schedDraw();
|
|
7139
|
+
}
|
|
7140
|
+
_hitFillHandle(x, y, geo = this._geo(), hitW = RESIZE_HIT_W) {
|
|
7057
7141
|
if (!this._sel) return false;
|
|
7058
7142
|
const { headerH, colPositions } = geo;
|
|
7059
7143
|
const selR2 = this._sel.type === "single" ? this._sel.row : this._sel.r2;
|
|
7060
7144
|
const selC2 = this._sel.type === "single" ? this._sel.col : this._sel.c2;
|
|
7061
7145
|
const handleX = this._colLeft(selC2, geo) + (colPositions[selC2 + 1] - colPositions[selC2]);
|
|
7062
7146
|
const handleY = this._rowLayout.yOf(selR2 + 1) - this._scrollTop + headerH;
|
|
7063
|
-
|
|
7064
|
-
return Math.abs(x - handleX) <= HIT && Math.abs(y - handleY) <= HIT;
|
|
7147
|
+
return Math.abs(x - handleX) <= hitW && Math.abs(y - handleY) <= hitW;
|
|
7065
7148
|
}
|
|
7066
7149
|
_colLeft(col, geo) {
|
|
7067
7150
|
return colScreenX(col, geo, this._scrollLeft);
|
|
@@ -7619,10 +7702,16 @@ ${title ? `<h2>${esc(title)}</h2>` : ""}
|
|
|
7619
7702
|
this._wrapper.style.overflow = "visible";
|
|
7620
7703
|
const wrapperTop = this._wrapper.getBoundingClientRect().top;
|
|
7621
7704
|
const viewportH = window.innerHeight || document.documentElement.clientHeight;
|
|
7622
|
-
const
|
|
7705
|
+
const spaceBelow = viewportH - wrapperTop - geo.headerH - 8;
|
|
7706
|
+
const spaceAbove = wrapperTop - 8;
|
|
7707
|
+
const PANEL_MIN_USABLE = 260;
|
|
7708
|
+
const openUpward = spaceBelow < PANEL_MIN_USABLE && spaceAbove > spaceBelow;
|
|
7709
|
+
const maxPanelHeight = openUpward ? spaceAbove : spaceBelow;
|
|
7623
7710
|
const el = buildFilterPanelEl({
|
|
7624
7711
|
colLeft: this._colLeft(col, geo),
|
|
7625
7712
|
headerH: geo.headerH,
|
|
7713
|
+
wrapperHeight: this._opts.height,
|
|
7714
|
+
openUpward,
|
|
7626
7715
|
width: this._opts.width,
|
|
7627
7716
|
maxPanelHeight,
|
|
7628
7717
|
label,
|
|
@@ -8754,19 +8843,19 @@ ${title ? `<h2>${esc(title)}</h2>` : ""}
|
|
|
8754
8843
|
}
|
|
8755
8844
|
_clearSelection() {
|
|
8756
8845
|
if (!this._sel) return;
|
|
8757
|
-
const
|
|
8758
|
-
|
|
8759
|
-
|
|
8760
|
-
|
|
8761
|
-
|
|
8762
|
-
|
|
8763
|
-
|
|
8846
|
+
const single = this._sel.type === "single";
|
|
8847
|
+
const r1 = single ? this._sel.row : this._sel.r1;
|
|
8848
|
+
const r2 = single ? this._sel.row : this._sel.r2;
|
|
8849
|
+
const c1 = single ? this._sel.col : this._sel.c1;
|
|
8850
|
+
const c2 = single ? this._sel.col : this._sel.c2;
|
|
8851
|
+
const editableFields = [];
|
|
8852
|
+
for (let c = c1; c <= c2; c++) {
|
|
8853
|
+
if (this._isEditable(c)) editableFields.push(this._columns[c]);
|
|
8854
|
+
}
|
|
8764
8855
|
this._editTxnBegin();
|
|
8765
|
-
|
|
8766
|
-
|
|
8767
|
-
|
|
8768
|
-
this._setEdit(r, field, "");
|
|
8769
|
-
});
|
|
8856
|
+
for (let r = r1; r <= r2; r++) {
|
|
8857
|
+
for (const field of editableFields) this._setEdit(r, field, "");
|
|
8858
|
+
}
|
|
8770
8859
|
this._editTxnCommit();
|
|
8771
8860
|
this._draw();
|
|
8772
8861
|
}
|
|
@@ -8951,11 +9040,15 @@ ${title ? `<h2>${esc(title)}</h2>` : ""}
|
|
|
8951
9040
|
const v = data[field];
|
|
8952
9041
|
return v != null ? String(v) : "";
|
|
8953
9042
|
}
|
|
8954
|
-
// Re-runs validation for one cell and updates the validator's invalid-cell set.
|
|
9043
|
+
// Re-runs validation for one cell and updates the validator's invalid-cell set. Takes a
|
|
9044
|
+
// "row_field" key -- for callers that only have that (iterating an _edits-shaped Map). Callers
|
|
9045
|
+
// that already have row/field apart (_setEdit, validateAll) should call _revalidateRowField()
|
|
9046
|
+
// directly instead of paying to stringify them together here just to split them back apart.
|
|
8955
9047
|
_revalidateKey(key) {
|
|
8956
9048
|
const u = key.indexOf("_");
|
|
8957
|
-
|
|
8958
|
-
|
|
9049
|
+
this._revalidateRowField(Number(key.slice(0, u)), key.slice(u + 1));
|
|
9050
|
+
}
|
|
9051
|
+
_revalidateRowField(row, field) {
|
|
8959
9052
|
this._validator.revalidate(row, field, this._resolveCellStringValue(row, field));
|
|
8960
9053
|
}
|
|
8961
9054
|
// Rebuilds invalid-cell state from scratch based on the current _edits map —
|
|
@@ -8990,11 +9083,11 @@ ${title ? `<h2>${esc(title)}</h2>` : ""}
|
|
|
8990
9083
|
const validatedFields = this._columns.filter((f) => this._colDefMap.get(f)?.validation);
|
|
8991
9084
|
if (validatedFields.length > 0) {
|
|
8992
9085
|
this._dm.forEachLoaded((_, rowIndex) => {
|
|
8993
|
-
validatedFields.forEach((field) => this.
|
|
9086
|
+
validatedFields.forEach((field) => this._revalidateRowField(rowIndex, field));
|
|
8994
9087
|
});
|
|
8995
9088
|
this._localRows.forEach((_, i) => {
|
|
8996
9089
|
const r = this._rowPlan.visualOfLocal(i);
|
|
8997
|
-
validatedFields.forEach((field) => this.
|
|
9090
|
+
validatedFields.forEach((field) => this._revalidateRowField(r, field));
|
|
8998
9091
|
});
|
|
8999
9092
|
}
|
|
9000
9093
|
this._draw();
|
|
@@ -9021,7 +9114,7 @@ ${title ? `<h2>${esc(title)}</h2>` : ""}
|
|
|
9021
9114
|
this._edits.set(key, val);
|
|
9022
9115
|
this._editedRows.add(row);
|
|
9023
9116
|
this._opts.onCellChange?.({ row, field, newValue: val, oldValue });
|
|
9024
|
-
this.
|
|
9117
|
+
this._revalidateRowField(row, field);
|
|
9025
9118
|
this._growRowForMultilineValue(row, val);
|
|
9026
9119
|
}
|
|
9027
9120
|
// Excel grows a row's height the moment a cell picks up a line break -- typed (Alt+Enter) or
|
|
@@ -9676,7 +9769,6 @@ ${title ? `<h2>${esc(title)}</h2>` : ""}
|
|
|
9676
9769
|
ev.mousedown = (e) => {
|
|
9677
9770
|
const { x, y } = this._xy(e);
|
|
9678
9771
|
const geo = this._geo();
|
|
9679
|
-
const { v, h } = geo;
|
|
9680
9772
|
const suppressReopenCell = this._suppressReopenCell;
|
|
9681
9773
|
this._suppressReopenCell = null;
|
|
9682
9774
|
if (this._editing) this._commitEdit();
|
|
@@ -9692,27 +9784,7 @@ ${title ? `<h2>${esc(title)}</h2>` : ""}
|
|
|
9692
9784
|
if (withinSel) return;
|
|
9693
9785
|
}
|
|
9694
9786
|
}
|
|
9695
|
-
if (x
|
|
9696
|
-
if (y >= v.thumbY && y <= v.thumbY + v.thumbH) {
|
|
9697
|
-
this._drag = { axis: "v", startMouse: y, startScroll: this._scrollTop };
|
|
9698
|
-
} else if (y >= v.y && y <= v.y + v.h) {
|
|
9699
|
-
const ratio = Math.max(0, Math.min(1, (y - v.y - v.thumbH / 2) / (v.h - v.thumbH)));
|
|
9700
|
-
this._scrollTop = geo.minScrollY + ratio * (geo.maxScrollY - geo.minScrollY);
|
|
9701
|
-
this._clamp(geo);
|
|
9702
|
-
this._draw();
|
|
9703
|
-
}
|
|
9704
|
-
e.preventDefault();
|
|
9705
|
-
return;
|
|
9706
|
-
}
|
|
9707
|
-
if (y >= h.y) {
|
|
9708
|
-
if (x >= h.thumbX && x <= h.thumbX + h.thumbW) {
|
|
9709
|
-
this._drag = { axis: "h", startMouse: x, startScroll: this._scrollLeft };
|
|
9710
|
-
} else if (x >= h.x && x <= h.x + h.w) {
|
|
9711
|
-
const ratio = Math.max(0, Math.min(1, (x - h.x - h.thumbW / 2) / (h.w - h.thumbW)));
|
|
9712
|
-
this._scrollLeft = ratio * geo.maxScrollX;
|
|
9713
|
-
this._clamp(geo);
|
|
9714
|
-
this._draw();
|
|
9715
|
-
}
|
|
9787
|
+
if (this._hitScrollbar(x, y, geo)) {
|
|
9716
9788
|
e.preventDefault();
|
|
9717
9789
|
return;
|
|
9718
9790
|
}
|
|
@@ -9924,25 +9996,7 @@ ${title ? `<h2>${esc(title)}</h2>` : ""}
|
|
|
9924
9996
|
}
|
|
9925
9997
|
}
|
|
9926
9998
|
if (this._drag) {
|
|
9927
|
-
|
|
9928
|
-
const { v, h } = geo;
|
|
9929
|
-
if (this._drag.axis === "v") {
|
|
9930
|
-
const ratio = (y - this._drag.startMouse) / (v.h - v.thumbH);
|
|
9931
|
-
this._scrollTop = this._drag.startScroll + ratio * (geo.maxScrollY - geo.minScrollY);
|
|
9932
|
-
} else {
|
|
9933
|
-
const ratio = (x - this._drag.startMouse) / (h.w - h.thumbW);
|
|
9934
|
-
this._scrollLeft = this._drag.startScroll + ratio * geo.maxScrollX;
|
|
9935
|
-
}
|
|
9936
|
-
this._clamp(geo);
|
|
9937
|
-
this._scrolling = true;
|
|
9938
|
-
this._dm.setHold(true);
|
|
9939
|
-
clearTimeout(this._scrollEndTimer);
|
|
9940
|
-
this._scrollEndTimer = setTimeout(() => {
|
|
9941
|
-
this._scrolling = false;
|
|
9942
|
-
this._dm.setHold(false);
|
|
9943
|
-
this._schedDraw();
|
|
9944
|
-
}, 150);
|
|
9945
|
-
this._schedDraw();
|
|
9999
|
+
this._updateScrollbarDrag(x, y);
|
|
9946
10000
|
return;
|
|
9947
10001
|
}
|
|
9948
10002
|
if (this._selDragging) {
|
|
@@ -10329,19 +10383,23 @@ ${title ? `<h2>${esc(title)}</h2>` : ""}
|
|
|
10329
10383
|
this._rowTap = null;
|
|
10330
10384
|
const geo = this._geo();
|
|
10331
10385
|
const headerH = geo.headerH;
|
|
10386
|
+
if (this._hitScrollbar(x, y, geo)) {
|
|
10387
|
+
e.preventDefault();
|
|
10388
|
+
return;
|
|
10389
|
+
}
|
|
10332
10390
|
if (y >= 0 && y < headerH) {
|
|
10333
10391
|
const col = this._hitHeader(x, geo);
|
|
10334
10392
|
if (col !== null) {
|
|
10335
10393
|
const colW = geo.colPositions[col + 1] - geo.colPositions[col];
|
|
10336
10394
|
const colRight = this._colLeft(col, geo) + colW;
|
|
10337
10395
|
const filterIconX = colRight - FILTER_ICON_W;
|
|
10338
|
-
if (Math.abs(x - colRight) <=
|
|
10396
|
+
if (Math.abs(x - colRight) <= RESIZE_HIT_W_TOUCH) {
|
|
10339
10397
|
this._colResize = { col, startX: x, startWidth: colW, undoBefore: this._snapshotStructural() };
|
|
10340
10398
|
e.preventDefault();
|
|
10341
10399
|
return;
|
|
10342
10400
|
}
|
|
10343
10401
|
const colLeft = this._colLeft(col, geo);
|
|
10344
|
-
if (col > 0 && Math.abs(x - colLeft) <=
|
|
10402
|
+
if (col > 0 && Math.abs(x - colLeft) <= RESIZE_HIT_W_TOUCH) {
|
|
10345
10403
|
const prevColW = geo.colPositions[col] - geo.colPositions[col - 1];
|
|
10346
10404
|
this._colResize = { col: col - 1, startX: x, startWidth: prevColW, undoBefore: this._snapshotStructural() };
|
|
10347
10405
|
e.preventDefault();
|
|
@@ -10353,7 +10411,7 @@ ${title ? `<h2>${esc(title)}</h2>` : ""}
|
|
|
10353
10411
|
const _hcbCx = this._colLeft(col, geo) + _hcbPad + 6;
|
|
10354
10412
|
const _hcbCell = computeHeaderCells(this._opts.headerRows, this._columns, this._opts.columnLetterHeader).find((c) => c.isLeaf && c.col === col);
|
|
10355
10413
|
const _hcbCy = _hcbCell ? _hcbCell.row * this._opts.headerHeight + _hcbCell.rowspan * this._opts.headerHeight / 2 : headerH - this._opts.headerHeight / 2;
|
|
10356
|
-
if (Math.abs(x - _hcbCx) <=
|
|
10414
|
+
if (Math.abs(x - _hcbCx) <= RESIZE_HIT_W_TOUCH && Math.abs(y - _hcbCy) <= RESIZE_HIT_W_TOUCH) {
|
|
10357
10415
|
const _hcbChecked = !(this._headerCheckboxState.get(_hcbField) ?? false);
|
|
10358
10416
|
this._headerCheckboxState.set(_hcbField, _hcbChecked);
|
|
10359
10417
|
this._draw();
|
|
@@ -10383,7 +10441,7 @@ ${title ? `<h2>${esc(title)}</h2>` : ""}
|
|
|
10383
10441
|
return;
|
|
10384
10442
|
}
|
|
10385
10443
|
}
|
|
10386
|
-
const boundaryRow = geo.rowNumW > 0 && x < geo.rowNumW && y >= geo.headerH ? this._hitRowBoundary(y, geo) : null;
|
|
10444
|
+
const boundaryRow = geo.rowNumW > 0 && x < geo.rowNumW && y >= geo.headerH ? this._hitRowBoundary(y, geo, RESIZE_HIT_W_TOUCH) : null;
|
|
10387
10445
|
if (boundaryRow !== null) {
|
|
10388
10446
|
this._rowResize = { row: boundaryRow, startY: y, startHeight: this._rowLayout.heightOf(boundaryRow), undoBefore: this._snapshotStructural() };
|
|
10389
10447
|
e.preventDefault();
|
|
@@ -10405,7 +10463,7 @@ ${title ? `<h2>${esc(title)}</h2>` : ""}
|
|
|
10405
10463
|
}
|
|
10406
10464
|
return;
|
|
10407
10465
|
}
|
|
10408
|
-
if (this._sel && this._hitFillHandle(x, y, geo)) {
|
|
10466
|
+
if (this._sel && this._hitFillHandle(x, y, geo, RESIZE_HIT_W_TOUCH)) {
|
|
10409
10467
|
this._fillDrag = { sel: this._sel };
|
|
10410
10468
|
this._fillPreview = null;
|
|
10411
10469
|
e.preventDefault();
|
|
@@ -10443,6 +10501,14 @@ ${title ? `<h2>${esc(title)}</h2>` : ""}
|
|
|
10443
10501
|
e.preventDefault();
|
|
10444
10502
|
return;
|
|
10445
10503
|
}
|
|
10504
|
+
if (this._drag) {
|
|
10505
|
+
if (!e.touches.length) return;
|
|
10506
|
+
const t = e.touches[0];
|
|
10507
|
+
const rect2 = this._canvas.getBoundingClientRect();
|
|
10508
|
+
this._updateScrollbarDrag(t.clientX - rect2.left, t.clientY - rect2.top);
|
|
10509
|
+
e.preventDefault();
|
|
10510
|
+
return;
|
|
10511
|
+
}
|
|
10446
10512
|
if (!this._touch) return;
|
|
10447
10513
|
const rect = this._canvas.getBoundingClientRect();
|
|
10448
10514
|
if (e.touches.length >= 2 && this._touch.twoFinger) {
|
|
@@ -10479,6 +10545,10 @@ ${title ? `<h2>${esc(title)}</h2>` : ""}
|
|
|
10479
10545
|
ev.touchend = (e) => {
|
|
10480
10546
|
this._cancelLongPress();
|
|
10481
10547
|
if (this._finalizeStructuralGesture()) return;
|
|
10548
|
+
if (this._drag) {
|
|
10549
|
+
this._drag = null;
|
|
10550
|
+
return;
|
|
10551
|
+
}
|
|
10482
10552
|
if (this._rowTap) {
|
|
10483
10553
|
const { row, ctrlKey, shiftKey } = this._rowTap;
|
|
10484
10554
|
this._rowTap = null;
|
|
@@ -11908,7 +11978,7 @@ ${title ? `<h2>${esc(title)}</h2>` : ""}
|
|
|
11908
11978
|
JHGrid.use(RowSelectionPlugin);
|
|
11909
11979
|
|
|
11910
11980
|
// index.js
|
|
11911
|
-
var VERSION = "0.1.
|
|
11981
|
+
var VERSION = "0.1.2";
|
|
11912
11982
|
var SUPPORTED_BROWSERS = {
|
|
11913
11983
|
chrome: 99,
|
|
11914
11984
|
edge: 99,
|