mdkcontroller 1.2.0 → 1.2.1

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.
@@ -2,7 +2,7 @@
2
2
  font-family: Arial, Helvetica, sans-serif;
3
3
  border-collapse: collapse;
4
4
  width: 100%;
5
- min-width: 800px;
5
+ table-layout: fixed;
6
6
  }
7
7
 
8
8
  .dk-table td {
@@ -32,6 +32,7 @@
32
32
  margin-right: 3px;
33
33
  border-radius: 6px;
34
34
  cursor: pointer;
35
+ place-self: center;
35
36
  }
36
37
 
37
38
  .dk-table .gridToolCell ul li:hover {
@@ -44,6 +45,11 @@
44
45
  padding: 5px;
45
46
  font-size: 19px;
46
47
  font-weight: bold;
48
+ height: 38px;
49
+ }
50
+
51
+ .dk-table .gridBodyCell {
52
+ vertical-align: text-top;
47
53
  }
48
54
 
49
55
  .dk-table .RowNavigator td {
@@ -119,4 +125,8 @@
119
125
  .dk-actionsBar button:active,
120
126
  .dk-actionsBar button:hover {
121
127
  border-color: #0fbd7db6;
128
+ }
129
+
130
+ .active {
131
+ background: #0075ffc4;
122
132
  }
@@ -7,9 +7,10 @@ class DKGrid {
7
7
  this.idRaw = boxId + "_autogrid_dataraw";
8
8
  this.idEditor = boxId + "_autogrid_editor";
9
9
  this.config = { ...DKGrid.defaultConfig, ...config };
10
- this.#cache = { updated: [], deleted: [], origin: [] };
10
+ this.#cache = { updated: {}, deleted: {}, origin: {} };
11
11
  this.rowOnFocus = null;
12
12
  this.#event = {};
13
+ this.page = { current: 1, total: 1, size: 10 };
13
14
  if (!config) {
14
15
  console.log("Config default cho table " + boxid, DKGrid.configDefault);
15
16
  return;
@@ -56,13 +57,16 @@ class DKGrid {
56
57
  box.innerHTML = tableTemplate;
57
58
  this.tableRaw = document.getElementById(this.idRaw);
58
59
  this.tableEditor = document.getElementById(this.idEditor);
60
+ this.statusBox = document.getElementById(this.id + "_status");
59
61
  this.#attachEvents();
60
62
  }
61
63
 
62
64
  #generateTableHTML() {
63
65
  const th_html = this.config.column.map(f => `<td class="GridHeader GridRow">${f.title}</td>`).join("");
66
+ let totalWidth = 0;
64
67
  const colWidths = this.config.column.map(f => {
65
68
  let width = f.width || (f.dataType === "string" ? 200 : f.dataType === "date" ? 140 : f.dataType === "number" ? 100 : 80);
69
+ totalWidth += width;
66
70
  return `<col style="width: ${width}px;">`;
67
71
  }).join("");
68
72
  let trEditor_html = this.config.column.map(f => {
@@ -82,8 +86,9 @@ class DKGrid {
82
86
  }
83
87
  }).join("\r\n");
84
88
  return `
85
- <table id='${this.id}' class='dk-table'>
86
- <tr>
89
+ <div style='height: 100%;width: 100%; overflow: hidden;'>
90
+ <table id='${this.id}' class='dk-table' style='height: 100%;'>
91
+ <tr style='height: 1px;'>
87
92
  <td class='gridToolCell'>
88
93
  <div>
89
94
  <ul id='${this.id}_gridToolCell' style='display: flex; list-style-type: none; margin: 5px;'>
@@ -91,36 +96,51 @@ class DKGrid {
91
96
  <li data-cmd='del'><i class="fa fa-times" aria-hidden="true"></i></li>
92
97
  <li data-cmd='cancel'><i class="fa fa-recycle" aria-hidden="true"></i></li>
93
98
  <li data-cmd='save'><i class="fa fa-cloud-upload" aria-hidden="true"></i></li>
99
+ <li data-cmd='refresh'><input id='${this.id}_inputSearch' type='search' style='width:150px;'></li>
94
100
  </ul>
95
101
  </div>
96
102
  </td>
97
103
  </tr>
98
- <tr>
104
+ <tr style='height: 1px;'>
99
105
  <td class='gridHeaderCell'>
100
- <table data-primary-key='${this.config.primaryKey}' cellpadding="0" cellspacing="0" border="0" style="table-layout: fixed; height: 100%; width: 0px; position: relative; left: 0px;">
101
- <colgroup>${colWidths}</colgroup>
102
- <thead><tr>${th_html}</tr></thead>
103
- </table>
106
+ <div id='${this.id}_headerTitle' style='overflow-x: hidden;'>
107
+ <table cellpadding="0" cellspacing="0" border="0" style="table-layout: fixed; width: ${totalWidth}px; margin-right: 17px;">
108
+ <colgroup>${colWidths}</colgroup>
109
+ <thead><tr>${th_html}</tr></thead>
110
+ </table>
111
+ </div>
104
112
  </td>
105
113
  </tr>
106
114
  <tr>
107
115
  <td class='gridBodyCell'>
108
- <div style='position: relative;overflow: auto hidden;vertical-align: top;'>
109
- <table id='${this.idRaw}' class='edit' cellpadding="0" cellspacing="0" border="0" style="table-layout: fixed;">
116
+ <div id='${this.id}_bodyContent' style='position: relative; height: 100%; overflow: scroll;'>
117
+ <table id='${this.idRaw}' class='edit' cellpadding="0" cellspacing="0" border="0" style="table-layout: fixed;width: ${totalWidth}px;">
110
118
  <colgroup>${colWidths}</colgroup>
111
119
  <tbody></tbody>
112
120
  </table>
113
- <table id='${this.idEditor}' class='edit RowNavigator' cellpadding="0" cellspacing="0" border="0" style="table-layout: fixed;width: 0px;position: absolute;left: 0px;top: 40px; display: none;">
121
+ <table id='${this.idEditor}' class='edit RowNavigator' cellpadding="0" cellspacing="0" border="0" style="table-layout: fixed;width: ${totalWidth}px;position: absolute;left: 0px;top: 40px; display: none;">
114
122
  <colgroup>${colWidths}</colgroup>
115
123
  <tbody><tr>${trEditor_html}</tr></tbody>
116
124
  </table>
117
125
  </div>
118
126
  </td>
119
127
  </tr>
120
- <tr>
121
- <td class='gridStatusCell'></td>
128
+ <tr style='height: 1px;'>
129
+ <td class='gridToolCell'>
130
+ <div style='display: flex; align-items: center;'>
131
+ <ul id='${this.id}_gridPagingCell' style='display: flex; list-style-type: none; margin: 5px; padding: 2px 32px;'>
132
+ <li data-cmd='1'>1</li>
133
+ <li data-cmd='2'>2</li>
134
+ <li data-cmd='3'>3</li>
135
+ <li data-cmd='4'>4</li>
136
+ <li data-cmd='5'>5</li>
137
+ </ul>
138
+ <span id='${this.id}_status' style='font-size:18px;'>xx/50</span>
139
+ </div>
140
+ </td>
122
141
  </tr>
123
- </table>`;
142
+ </table>
143
+ </div>`;
124
144
  }
125
145
 
126
146
  #attachEvents() {
@@ -149,6 +169,28 @@ class DKGrid {
149
169
  case "cancel": this.cancelChanges(); break;
150
170
  }
151
171
  });
172
+ this.pagingCell = document.getElementById(this.id + "_gridPagingCell");
173
+ this.pagingCell.addEventListener('click', (event) => {
174
+ const cmdElement = event.target.closest('li[data-cmd]');
175
+ if (!cmdElement) return;
176
+
177
+ const cmd = cmdElement.dataset.cmd;
178
+ const page = parseInt(cmd);
179
+ if (page) {
180
+ this.page.current = Math.min(page, this.page.total);
181
+ this.loadDataByPage();
182
+ }
183
+ });
184
+ document.getElementById(dkgrid.id + "_bodyContent").addEventListener("scroll", function () {
185
+ const header = document.getElementById(dkgrid.id + "_headerTitle");
186
+ header.scrollLeft = document.getElementById(dkgrid.id + "_bodyContent").scrollLeft;
187
+ });
188
+ document.getElementById(dkgrid.id + "_inputSearch").addEventListener("keydown", function (event) {
189
+ if (event.key === "Enter") {
190
+ event.preventDefault();
191
+ dkgrid.loadDataByPage();
192
+ }
193
+ });
152
194
  }
153
195
  #keyDownOnTable(keyCode) {
154
196
  // ESC
@@ -197,7 +239,7 @@ class DKGrid {
197
239
 
198
240
  const cache = this.#cache;
199
241
 
200
- let objectCurrent = cache.updated.find(f => f[primaryKey]?.toString() == currentKeyValue) || cache.origin.find(f => f[primaryKey]?.toString() == currentKeyValue);
242
+ let objectCurrent = cache.updated[currentKeyValue] || cache.origin[currentKeyValue];
201
243
  {
202
244
  let throwX = false;
203
245
  this.fireEvent('openEditor', (rs) => {
@@ -236,7 +278,7 @@ class DKGrid {
236
278
  const currentKeyValue = trTag.dataset.primaryValue;
237
279
  const cache = this.#cache;
238
280
 
239
- let objectCurrent = cache.updated.find(f => f[primaryKey]?.toString() == currentKeyValue) || cache.origin.find(f => f[primaryKey]?.toString() == currentKeyValue);
281
+ let objectCurrent = cache.updated[currentKeyValue] || {...cache.origin[currentKeyValue]};
240
282
  let objectEditing = {};
241
283
  let hasChange = false;
242
284
  tbEditor.querySelector('tbody').querySelectorAll('td').forEachExt(
@@ -267,11 +309,8 @@ class DKGrid {
267
309
  Object.keys(objectEditing).forEach(key => {
268
310
  objectCurrent[key] = objectEditing[key];
269
311
  });
270
- cache.updated = cache.updated.filter(obj => obj[primaryKey] !== objectCurrent[primaryKey]);
271
- cache.updated.push(objectCurrent);
272
- {
273
- this.#createRow(trTag, objectCurrent);
274
- }
312
+ cache.updated[currentKeyValue] = objectCurrent;
313
+ this.#createRow(trTag, objectCurrent);
275
314
  }
276
315
  }
277
316
  }
@@ -301,39 +340,90 @@ class DKGrid {
301
340
  trTag.appendChild(td);
302
341
  });
303
342
  }
304
- cancelChanges() {
305
- if (confirm("Bạn có chắc chắn muốn hủy bỏ tất cả thay đổi không?") != true) {
306
- return;
307
- }
308
- const cache = this.#cache;
309
- cache.updated = [];
310
- cache.deleted = [];
311
- this.loadData();
312
- }
313
- loadData(data = undefined) {
314
- let table = this.tableRaw;
315
- const tableConfig = this.config;
343
+ loadData(data) {
316
344
  const cache = this.#cache;
317
345
  if (data) {
318
- cache.origin = data;
319
- cache.updated = [];
320
- cache.deleted = [];
346
+ cache.origin = {};
347
+ data.forEach(item => {
348
+ cache.origin[item[this.config.primaryKey]] = item;
349
+ });
350
+ cache.updated = {};
351
+ cache.deleted = {};
352
+ this.page.total = Math.ceil(data.length / this.page.size);
321
353
  }
322
- const dataPrint = {};
323
- cache.origin.forEach(item => {
324
- dataPrint[item[tableConfig.primaryKey]] = item;
354
+ this.loadDataByPage();
355
+ }
356
+ loadDataByPage() {
357
+ const cache = this.#cache;
358
+
359
+ const dataCollection = {};
360
+ Object.keys(cache.origin).forEach(key => {
361
+ dataCollection[key] = cache.origin[key];
325
362
  });
326
- cache.updated.forEach(item => {
327
- dataPrint[item[tableConfig.primaryKey]] = item;
363
+ Object.keys(cache.updated).forEach(key => {
364
+ dataCollection[key] = cache.updated[key];
328
365
  });
329
- cache.deleted.forEach(item => {
330
- delete dataPrint[item[tableConfig.primaryKey]];
366
+ Object.keys(cache.deleted).forEach(key => {
367
+ delete dataCollection[key];
368
+ });
369
+
370
+ const dataCollection_array = [];
371
+ const textSearch = document.getElementById(this.id + "_inputSearch").value;
372
+ Object.values(dataCollection).forEach(item => {
373
+ if (!textSearch) {
374
+ dataCollection_array.push(item);
375
+ } else {
376
+ this.config.column.forEach(f => {
377
+ let textValue = item[f.fieldName];
378
+ if (f.dataType == "select") {
379
+ textValue = f.items.find(i => i.value == item[f.fieldName])?.text ?? textValue;
380
+ }
381
+ if (textValue?.toString().toLowerCase().includes(textSearch.toLowerCase())) {
382
+ dataCollection_array.push(item);
383
+ return;
384
+ }
385
+ });
386
+ }
331
387
  });
388
+
389
+ const page = this.page;
390
+ page.total = Math.ceil(dataCollection_array.length / page.size);
391
+ page.current = Math.min(page.current, page.total);
392
+
393
+ const start = (page.current - 1) * page.size;
394
+ const end = start + page.size;
395
+
396
+ this.pagingCell.innerHTML = "";
397
+ {
398
+ const min = Math.max(2, page.current - 2);
399
+ const max = Math.min(page.total - 1, page.current + 2);
400
+ this.pagingCell.appendChild(hideCreatePageLi(1, "font-weight: bold; margin-right: 15px;"));
401
+ for (let index = min; index <= max; index++) {
402
+ this.pagingCell.appendChild(hideCreatePageLi(index));
403
+ }
404
+ this.pagingCell.appendChild(hideCreatePageLi(page.total, "font-weight: bold; margin-left: 15px;"));
405
+ function hideCreatePageLi(num, style = '') {
406
+ const li = document.createElement('li');
407
+ li.dataset.cmd = num;
408
+ li.textContent = num;
409
+ li.style = style;
410
+ if (num == page.current) {
411
+ li.classList.add('active');
412
+ }
413
+ return li;
414
+ }
415
+ }
416
+ const dataPrint = dataCollection_array.slice(start, end);
417
+ this.statusBox.textContent = `${dataPrint.length}/${dataCollection_array.length}`;
418
+ this.printPage(dataPrint);
419
+ }
420
+ printPage(dataPrint = []) {
421
+ const table = this.tableRaw;
422
+ const tableConfig = this.config;
332
423
  const tbody = table.querySelector('tbody');
333
424
  tbody.innerHTML = '';
334
- Object.keys(dataPrint).forEach(
335
- key => {
336
- const item = dataPrint[key];
425
+ dataPrint.forEach(
426
+ item => {
337
427
  const tr = document.createElement('tr');
338
428
  tr.dataset.primaryValue = item[tableConfig.primaryKey];
339
429
  tr.dataset.editting = '0';
@@ -374,7 +464,7 @@ class DKGrid {
374
464
  }
375
465
  newTR.dataset.primaryValue = newOb[primaryKey];
376
466
  const cache = this.#cache;
377
- cache.updated.push(newOb);
467
+ cache.updated[newOb[primaryKey]] = (newOb);
378
468
  this.#createRow(newTR, newOb);
379
469
  }
380
470
 
@@ -387,14 +477,14 @@ class DKGrid {
387
477
  const primaryKey = tableConfig.primaryKey;
388
478
  const lastRow = this.rowOnFocus;
389
479
  const currentKeyValue = lastRow.dataset.primaryValue;
390
- const objectOriginal = cache.origin.find(f => f[primaryKey] == currentKeyValue);
480
+ const objectOriginal = cache.origin[currentKeyValue];
391
481
  if (objectOriginal) {
392
- cache.deleted.push(objectOriginal);
482
+ cache.deleted[currentKeyValue] = (objectOriginal);
393
483
  }
394
484
 
395
- let objectCache = cache.updated.find(f => f[primaryKey] == currentKeyValue);
485
+ let objectCache = cache.updated[currentKeyValue];
396
486
  if (objectCache) {
397
- cache.updated = cache.updated.filter(obj => obj[primaryKey] !== objectCache[primaryKey]);
487
+ delete cache.updated[currentKeyValue];
398
488
  }
399
489
 
400
490
  table.dataset.cache = JSON.stringify(cache);
@@ -412,9 +502,11 @@ class DKGrid {
412
502
  return;
413
503
  }
414
504
  const cache = this.#cache;
415
- cache.updated = [];
416
- cache.deleted = [];
417
- this.loadData();
505
+ const dataOrigin = [];
506
+ Object.keys(cache.origin).forEach(key => {
507
+ dataOrigin.push(cache.origin[key]);
508
+ });
509
+ this.loadData(dataOrigin);
418
510
  }
419
511
  static inputCheckboxReadOnly(event) {
420
512
  event.preventDefault();
package/Cores/file/dk.js CHANGED
@@ -122,6 +122,33 @@ const DK = {
122
122
  const imgTag = dk_overlay.getElementsByTagName('img')[0];
123
123
  imgTag.style.height = dialog.parentNode.parentNode.clientHeight + 'px';
124
124
  },
125
+ DKDataCache: {},
126
+ buildFormEvent: () => {
127
+ document.querySelectorAll("input, select").forEach(field => {
128
+ const formP = field.closest('form');
129
+ if (formP && formP.id && field.parentElement.tagName != 'TD' && field.name) {
130
+ DK.DKDataCache[formP.id] = DK.DKDataCache[formP.id] ?? {};
131
+ field.addEventListener("blur", (event) => {
132
+ const fieldName = field.name;
133
+ if (DK.DKDataCache[formP.id][fieldName] != field.value) {
134
+ const oldOB = { ...DK.DKDataCache[formP.id] };
135
+ DK.DKDataCache[formP.id][fieldName] = field.value;
136
+
137
+ const fnname = `${formP.id}_${field.name}_updated`;
138
+ const formEvent = window[`${formP.id}_updated`];
139
+ const fieldEvent = window[fnname];
140
+ if (fieldEvent) {
141
+ fieldEvent(field.value, oldOB[fieldName], { ...oldOB });
142
+ }
143
+ if (formEvent) {
144
+ formEvent(DK.DKDataCache[formP.id], { ...oldOB });
145
+ }
146
+ }
147
+
148
+ });
149
+ }
150
+ });
151
+ },
125
152
  ImportCss: (src) => {
126
153
  var link = document.createElement("link");
127
154
  link.href = src;
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "socket.io": "^4.7.2"
10
10
  },
11
11
  "name": "mdkcontroller",
12
- "version": "1.2.0",
12
+ "version": "1.2.1",
13
13
  "keywords": [],
14
14
  "author": "KHANHNBD <khanh272421@gmail.com>",
15
15
  "license": "ISC",