@jh-grid/jhgrid-js 0.1.1 → 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.
@@ -4,6 +4,14 @@ var DataManager = class {
4
4
  #chunkSize;
5
5
  #maxChunks;
6
6
  #cache = /* @__PURE__ */ new Map();
7
+ // 1-entry cache of the chunk getRow() touched last. A bulk row-major walk (e.g. clearing an
8
+ // entire selection) calls getRow() for every column of the same row back-to-back -- same
9
+ // chunkIdx every time -- and #chunkSize more rows after that before it changes, so this turns
10
+ // the overwhelming majority of getRow() calls into a single index comparison instead of a Map
11
+ // lookup plus the LRU delete+re-insert below. Must be invalidated everywhere #cache forgets a
12
+ // chunk (#evict, clear) so it can never serve an entry #cache itself no longer considers current.
13
+ #lastChunkIdx = -1;
14
+ #lastChunk = null;
7
15
  #fetching = /* @__PURE__ */ new Set();
8
16
  #failed = /* @__PURE__ */ new Set();
9
17
  #failedTimers = /* @__PURE__ */ new Set();
@@ -37,10 +45,13 @@ var DataManager = class {
37
45
  // re-request after onChunkLoaded).
38
46
  getRow(rowIndex) {
39
47
  const chunkIdx = Math.floor(rowIndex / this.#chunkSize);
48
+ if (chunkIdx === this.#lastChunkIdx) return this.#lastChunk[rowIndex % this.#chunkSize] ?? null;
40
49
  if (this.#cache.has(chunkIdx)) {
41
50
  const chunk = this.#cache.get(chunkIdx);
42
51
  this.#cache.delete(chunkIdx);
43
52
  this.#cache.set(chunkIdx, chunk);
53
+ this.#lastChunkIdx = chunkIdx;
54
+ this.#lastChunk = chunk;
44
55
  return chunk[rowIndex % this.#chunkSize] ?? null;
45
56
  }
46
57
  this.#request(chunkIdx);
@@ -201,6 +212,10 @@ var DataManager = class {
201
212
  while (this.#cache.size > this.#maxChunks) {
202
213
  const oldest = this.#cache.keys().next().value;
203
214
  this.#cache.delete(oldest);
215
+ if (oldest === this.#lastChunkIdx) {
216
+ this.#lastChunkIdx = -1;
217
+ this.#lastChunk = null;
218
+ }
204
219
  }
205
220
  }
206
221
  // Returning `false` from `callback` stops the walk. Callers that are looking for an answer
@@ -227,6 +242,8 @@ var DataManager = class {
227
242
  this.#failed.clear();
228
243
  this.#failedTimers.forEach(clearTimeout);
229
244
  this.#failedTimers.clear();
245
+ this.#lastChunkIdx = -1;
246
+ this.#lastChunk = null;
230
247
  }
231
248
  };
232
249
 
@@ -8786,19 +8803,19 @@ var JHGrid = class _JHGrid {
8786
8803
  }
8787
8804
  _clearSelection() {
8788
8805
  if (!this._sel) return;
8789
- const pairs = this._sel.type === "single" ? [[this._sel.row, this._sel.col]] : Array.from(
8790
- { length: this._sel.r2 - this._sel.r1 + 1 },
8791
- (_, ri) => Array.from(
8792
- { length: this._sel.c2 - this._sel.c1 + 1 },
8793
- (_2, ci) => [this._sel.r1 + ri, this._sel.c1 + ci]
8794
- )
8795
- ).flat();
8806
+ const single = this._sel.type === "single";
8807
+ const r1 = single ? this._sel.row : this._sel.r1;
8808
+ const r2 = single ? this._sel.row : this._sel.r2;
8809
+ const c1 = single ? this._sel.col : this._sel.c1;
8810
+ const c2 = single ? this._sel.col : this._sel.c2;
8811
+ const editableFields = [];
8812
+ for (let c = c1; c <= c2; c++) {
8813
+ if (this._isEditable(c)) editableFields.push(this._columns[c]);
8814
+ }
8796
8815
  this._editTxnBegin();
8797
- pairs.forEach(([r, c]) => {
8798
- if (!this._isEditable(c)) return;
8799
- const field = this._columns[c];
8800
- this._setEdit(r, field, "");
8801
- });
8816
+ for (let r = r1; r <= r2; r++) {
8817
+ for (const field of editableFields) this._setEdit(r, field, "");
8818
+ }
8802
8819
  this._editTxnCommit();
8803
8820
  this._draw();
8804
8821
  }
@@ -8983,11 +9000,15 @@ var JHGrid = class _JHGrid {
8983
9000
  const v = data[field];
8984
9001
  return v != null ? String(v) : "";
8985
9002
  }
8986
- // Re-runs validation for one cell and updates the validator's invalid-cell set.
9003
+ // Re-runs validation for one cell and updates the validator's invalid-cell set. Takes a
9004
+ // "row_field" key -- for callers that only have that (iterating an _edits-shaped Map). Callers
9005
+ // that already have row/field apart (_setEdit, validateAll) should call _revalidateRowField()
9006
+ // directly instead of paying to stringify them together here just to split them back apart.
8987
9007
  _revalidateKey(key) {
8988
9008
  const u = key.indexOf("_");
8989
- const row = Number(key.slice(0, u));
8990
- const field = key.slice(u + 1);
9009
+ this._revalidateRowField(Number(key.slice(0, u)), key.slice(u + 1));
9010
+ }
9011
+ _revalidateRowField(row, field) {
8991
9012
  this._validator.revalidate(row, field, this._resolveCellStringValue(row, field));
8992
9013
  }
8993
9014
  // Rebuilds invalid-cell state from scratch based on the current _edits map —
@@ -9022,11 +9043,11 @@ var JHGrid = class _JHGrid {
9022
9043
  const validatedFields = this._columns.filter((f) => this._colDefMap.get(f)?.validation);
9023
9044
  if (validatedFields.length > 0) {
9024
9045
  this._dm.forEachLoaded((_, rowIndex) => {
9025
- validatedFields.forEach((field) => this._revalidateKey(`${rowIndex}_${field}`));
9046
+ validatedFields.forEach((field) => this._revalidateRowField(rowIndex, field));
9026
9047
  });
9027
9048
  this._localRows.forEach((_, i) => {
9028
9049
  const r = this._rowPlan.visualOfLocal(i);
9029
- validatedFields.forEach((field) => this._revalidateKey(`${r}_${field}`));
9050
+ validatedFields.forEach((field) => this._revalidateRowField(r, field));
9030
9051
  });
9031
9052
  }
9032
9053
  this._draw();
@@ -9053,7 +9074,7 @@ var JHGrid = class _JHGrid {
9053
9074
  this._edits.set(key, val);
9054
9075
  this._editedRows.add(row);
9055
9076
  this._opts.onCellChange?.({ row, field, newValue: val, oldValue });
9056
- this._revalidateKey(key);
9077
+ this._revalidateRowField(row, field);
9057
9078
  this._growRowForMultilineValue(row, val);
9058
9079
  }
9059
9080
  // Excel grows a row's height the moment a cell picks up a line break -- typed (Alt+Enter) or
@@ -11917,7 +11938,7 @@ var JHGrid = class _JHGrid {
11917
11938
  JHGrid.use(RowSelectionPlugin);
11918
11939
 
11919
11940
  // index.js
11920
- var VERSION = "0.1.1";
11941
+ var VERSION = "0.1.2";
11921
11942
  var SUPPORTED_BROWSERS = {
11922
11943
  chrome: 99,
11923
11944
  edge: 99,
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
 
@@ -8826,19 +8843,19 @@ ${title ? `<h2>${esc(title)}</h2>` : ""}
8826
8843
  }
8827
8844
  _clearSelection() {
8828
8845
  if (!this._sel) return;
8829
- const pairs = this._sel.type === "single" ? [[this._sel.row, this._sel.col]] : Array.from(
8830
- { length: this._sel.r2 - this._sel.r1 + 1 },
8831
- (_, ri) => Array.from(
8832
- { length: this._sel.c2 - this._sel.c1 + 1 },
8833
- (_2, ci) => [this._sel.r1 + ri, this._sel.c1 + ci]
8834
- )
8835
- ).flat();
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
+ }
8836
8855
  this._editTxnBegin();
8837
- pairs.forEach(([r, c]) => {
8838
- if (!this._isEditable(c)) return;
8839
- const field = this._columns[c];
8840
- this._setEdit(r, field, "");
8841
- });
8856
+ for (let r = r1; r <= r2; r++) {
8857
+ for (const field of editableFields) this._setEdit(r, field, "");
8858
+ }
8842
8859
  this._editTxnCommit();
8843
8860
  this._draw();
8844
8861
  }
@@ -9023,11 +9040,15 @@ ${title ? `<h2>${esc(title)}</h2>` : ""}
9023
9040
  const v = data[field];
9024
9041
  return v != null ? String(v) : "";
9025
9042
  }
9026
- // 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.
9027
9047
  _revalidateKey(key) {
9028
9048
  const u = key.indexOf("_");
9029
- const row = Number(key.slice(0, u));
9030
- const field = key.slice(u + 1);
9049
+ this._revalidateRowField(Number(key.slice(0, u)), key.slice(u + 1));
9050
+ }
9051
+ _revalidateRowField(row, field) {
9031
9052
  this._validator.revalidate(row, field, this._resolveCellStringValue(row, field));
9032
9053
  }
9033
9054
  // Rebuilds invalid-cell state from scratch based on the current _edits map —
@@ -9062,11 +9083,11 @@ ${title ? `<h2>${esc(title)}</h2>` : ""}
9062
9083
  const validatedFields = this._columns.filter((f) => this._colDefMap.get(f)?.validation);
9063
9084
  if (validatedFields.length > 0) {
9064
9085
  this._dm.forEachLoaded((_, rowIndex) => {
9065
- validatedFields.forEach((field) => this._revalidateKey(`${rowIndex}_${field}`));
9086
+ validatedFields.forEach((field) => this._revalidateRowField(rowIndex, field));
9066
9087
  });
9067
9088
  this._localRows.forEach((_, i) => {
9068
9089
  const r = this._rowPlan.visualOfLocal(i);
9069
- validatedFields.forEach((field) => this._revalidateKey(`${r}_${field}`));
9090
+ validatedFields.forEach((field) => this._revalidateRowField(r, field));
9070
9091
  });
9071
9092
  }
9072
9093
  this._draw();
@@ -9093,7 +9114,7 @@ ${title ? `<h2>${esc(title)}</h2>` : ""}
9093
9114
  this._edits.set(key, val);
9094
9115
  this._editedRows.add(row);
9095
9116
  this._opts.onCellChange?.({ row, field, newValue: val, oldValue });
9096
- this._revalidateKey(key);
9117
+ this._revalidateRowField(row, field);
9097
9118
  this._growRowForMultilineValue(row, val);
9098
9119
  }
9099
9120
  // Excel grows a row's height the moment a cell picks up a line break -- typed (Alt+Enter) or
@@ -11957,7 +11978,7 @@ ${title ? `<h2>${esc(title)}</h2>` : ""}
11957
11978
  JHGrid.use(RowSelectionPlugin);
11958
11979
 
11959
11980
  // index.js
11960
- var VERSION = "0.1.1";
11981
+ var VERSION = "0.1.2";
11961
11982
  var SUPPORTED_BROWSERS = {
11962
11983
  chrome: 99,
11963
11984
  edge: 99,