mdkcontroller 1.1.4 → 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.
- package/Cores/file/DKGrid.css +132 -0
- package/Cores/file/DKGrid.js +534 -0
- package/Cores/file/dk.js +36 -7
- package/package.json +5 -5
- package/readme.md +1 -0
- package/Cores/file/dk_table.css +0 -63
- package/Cores/file/dk_table.js +0 -252
- package/Pages/DemoHomeV1/asset/global-grid.css +0 -19
- package/Pages/DemoHomeV1/asset/global-nav.css +0 -63
- package/Pages/DemoHomeV1/asset/global.css +0 -25
- package/Pages/DemoHomeV1/home/index.html +0 -68
- package/dk_modules/autohtml.js +0 -99
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
.dk-table {
|
|
2
|
+
font-family: Arial, Helvetica, sans-serif;
|
|
3
|
+
border-collapse: collapse;
|
|
4
|
+
width: 100%;
|
|
5
|
+
table-layout: fixed;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.dk-table td {
|
|
9
|
+
border: 1px solid #ddd;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.dk-table th {
|
|
13
|
+
padding-top: 12px;
|
|
14
|
+
padding-bottom: 12px;
|
|
15
|
+
text-align: left;
|
|
16
|
+
background-color: #04aa6d;
|
|
17
|
+
color: white;
|
|
18
|
+
font-weight: bold;
|
|
19
|
+
border: 1px solid;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.dk-table .gridToolCell ul {
|
|
23
|
+
display: flex;
|
|
24
|
+
list-style-type: none;
|
|
25
|
+
margin: 5px;
|
|
26
|
+
padding-left: 10px;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.dk-table .gridToolCell ul li {
|
|
30
|
+
padding: 3px 10px;
|
|
31
|
+
border: 1px solid;
|
|
32
|
+
margin-right: 3px;
|
|
33
|
+
border-radius: 6px;
|
|
34
|
+
cursor: pointer;
|
|
35
|
+
place-self: center;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.dk-table .gridToolCell ul li:hover {
|
|
39
|
+
background-color: #3e559ed6;
|
|
40
|
+
color: white;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.dk-table .gridHeaderCell td {
|
|
44
|
+
background: #aeb4c4;
|
|
45
|
+
padding: 5px;
|
|
46
|
+
font-size: 19px;
|
|
47
|
+
font-weight: bold;
|
|
48
|
+
height: 38px;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.dk-table .gridBodyCell {
|
|
52
|
+
vertical-align: text-top;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.dk-table .RowNavigator td {
|
|
56
|
+
background: white;
|
|
57
|
+
border-bottom: 1px solid #ff2828d6;
|
|
58
|
+
border-radius: 7px;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.dk-table .edit {
|
|
62
|
+
font-size: 18px;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.dk-table .edit tr {
|
|
66
|
+
height: 33px;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.dk-table .RowNavigator td>input,
|
|
70
|
+
.dk-table .RowNavigator td>select {
|
|
71
|
+
height: 23px;
|
|
72
|
+
font-size: 18px;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.dk-table .edit tr:nth-child(even) {
|
|
76
|
+
background-color: #dadada;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.dk-table .edit tr:nth-child(odd) {
|
|
80
|
+
background-color: #f1f1f1;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.dk-table .edit input[type="checkbox"] {
|
|
84
|
+
min-height: 22px;
|
|
85
|
+
width: 30px;
|
|
86
|
+
margin: auto;
|
|
87
|
+
display: block;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.dk-table .edit input[type="checkbox"]:disabled {
|
|
91
|
+
cursor: not-allowed;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.dk-table .edit input:not([type="checkbox"]) :focus {
|
|
95
|
+
outline: 1px solid rgba(65, 185, 65, 0.705);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.dk-table .edit input:not(:disabled),
|
|
99
|
+
.dk-table .edit select {
|
|
100
|
+
display: block;
|
|
101
|
+
color: #495057;
|
|
102
|
+
background-color: #fff;
|
|
103
|
+
background-image: none;
|
|
104
|
+
background-clip: padding-box;
|
|
105
|
+
border: 1px solid rgba(0, 0, 0, 0.15);
|
|
106
|
+
border-radius: 0.25rem;
|
|
107
|
+
transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
|
|
108
|
+
width: -webkit-fill-available;
|
|
109
|
+
padding: 0;
|
|
110
|
+
outline: none;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.dk-actionsBar {
|
|
114
|
+
padding: 5px 10px;
|
|
115
|
+
width: max-content;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.dk-actionsBar button {
|
|
119
|
+
border: 2px solid #0e9966b6;
|
|
120
|
+
border-radius: 5px;
|
|
121
|
+
cursor: pointer;
|
|
122
|
+
transition: all 1s;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.dk-actionsBar button:active,
|
|
126
|
+
.dk-actionsBar button:hover {
|
|
127
|
+
border-color: #0fbd7db6;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.active {
|
|
131
|
+
background: #0075ffc4;
|
|
132
|
+
}
|
|
@@ -0,0 +1,534 @@
|
|
|
1
|
+
class DKGrid {
|
|
2
|
+
#cache;
|
|
3
|
+
#event;
|
|
4
|
+
constructor(boxId, config = {}) {
|
|
5
|
+
this.boxId = boxId;
|
|
6
|
+
this.id = boxId + "_autogrid";
|
|
7
|
+
this.idRaw = boxId + "_autogrid_dataraw";
|
|
8
|
+
this.idEditor = boxId + "_autogrid_editor";
|
|
9
|
+
this.config = { ...DKGrid.defaultConfig, ...config };
|
|
10
|
+
this.#cache = { updated: {}, deleted: {}, origin: {} };
|
|
11
|
+
this.rowOnFocus = null;
|
|
12
|
+
this.#event = {};
|
|
13
|
+
this.page = { current: 1, total: 1, size: 10 };
|
|
14
|
+
if (!config) {
|
|
15
|
+
console.log("Config default cho table " + boxid, DKGrid.configDefault);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
this.#init();
|
|
20
|
+
return this;
|
|
21
|
+
}
|
|
22
|
+
addEventListener(eventName, callback) {
|
|
23
|
+
this.#event[eventName] = this.#event[eventName] || [];
|
|
24
|
+
this.#event[eventName].push(callback);
|
|
25
|
+
//rowClick, openEditor, commitData, onCreateNewKey
|
|
26
|
+
}
|
|
27
|
+
fireEvent(eventName, callback, ...args) {
|
|
28
|
+
const callbacks = this.#event[eventName] || [];
|
|
29
|
+
for (let index = 0; index < callbacks.length; index++) {
|
|
30
|
+
const cb = callbacks[index];
|
|
31
|
+
const rs = cb(...args);
|
|
32
|
+
if (callback && callback(rs) == false) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
static defaultConfig = {
|
|
38
|
+
postTo: '',
|
|
39
|
+
allowCommit: true,
|
|
40
|
+
allowEdit: true,
|
|
41
|
+
primaryKey: '',
|
|
42
|
+
column: [{ fieldName: '', title: '', dataType: '' }]
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
#init() {
|
|
46
|
+
const box = document.getElementById(this.boxId);
|
|
47
|
+
if (!box) {
|
|
48
|
+
console.error(`Không tìm thấy phần tử có ID: ${this.boxId}`);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (!this.config.primaryKey) {
|
|
53
|
+
this.config.primaryKey = this.config.column[0]?.fieldName || '';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const tableTemplate = this.#generateTableHTML();
|
|
57
|
+
box.innerHTML = tableTemplate;
|
|
58
|
+
this.tableRaw = document.getElementById(this.idRaw);
|
|
59
|
+
this.tableEditor = document.getElementById(this.idEditor);
|
|
60
|
+
this.statusBox = document.getElementById(this.id + "_status");
|
|
61
|
+
this.#attachEvents();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
#generateTableHTML() {
|
|
65
|
+
const th_html = this.config.column.map(f => `<td class="GridHeader GridRow">${f.title}</td>`).join("");
|
|
66
|
+
let totalWidth = 0;
|
|
67
|
+
const colWidths = this.config.column.map(f => {
|
|
68
|
+
let width = f.width || (f.dataType === "string" ? 200 : f.dataType === "date" ? 140 : f.dataType === "number" ? 100 : 80);
|
|
69
|
+
totalWidth += width;
|
|
70
|
+
return `<col style="width: ${width}px;">`;
|
|
71
|
+
}).join("");
|
|
72
|
+
let trEditor_html = this.config.column.map(f => {
|
|
73
|
+
switch (f.dataType) {
|
|
74
|
+
case "string": return `<td><input type='text'name='${f.fieldName}'/></td>`;
|
|
75
|
+
case "bool": return `<td><input type="checkbox" name='${f.fieldName}'></td>`;
|
|
76
|
+
case "date": return `<td><input type="date" name='${f.fieldName}'></td>`;
|
|
77
|
+
case "number": return `<td><input type="number" name='${f.fieldName}'></td>`;
|
|
78
|
+
case "select":
|
|
79
|
+
let items = "";
|
|
80
|
+
for (let index = 0; index < f.items.length; index++) {
|
|
81
|
+
const item = f.items[index];
|
|
82
|
+
items += `<option value="${item.value}">${item.text}</option>`;
|
|
83
|
+
}
|
|
84
|
+
return `<td><select name='${f.fieldName}'>${items}</select></td>`;
|
|
85
|
+
default: return `<td><input type='text' name='${f.fieldName}'/></td>`;
|
|
86
|
+
}
|
|
87
|
+
}).join("\r\n");
|
|
88
|
+
return `
|
|
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;'>
|
|
92
|
+
<td class='gridToolCell'>
|
|
93
|
+
<div>
|
|
94
|
+
<ul id='${this.id}_gridToolCell' style='display: flex; list-style-type: none; margin: 5px;'>
|
|
95
|
+
<li data-cmd='add'><i class="fa fa-plus" aria-hidden="true"></i></li>
|
|
96
|
+
<li data-cmd='del'><i class="fa fa-times" aria-hidden="true"></i></li>
|
|
97
|
+
<li data-cmd='cancel'><i class="fa fa-recycle" aria-hidden="true"></i></li>
|
|
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>
|
|
100
|
+
</ul>
|
|
101
|
+
</div>
|
|
102
|
+
</td>
|
|
103
|
+
</tr>
|
|
104
|
+
<tr style='height: 1px;'>
|
|
105
|
+
<td class='gridHeaderCell'>
|
|
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>
|
|
112
|
+
</td>
|
|
113
|
+
</tr>
|
|
114
|
+
<tr>
|
|
115
|
+
<td class='gridBodyCell'>
|
|
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;">
|
|
118
|
+
<colgroup>${colWidths}</colgroup>
|
|
119
|
+
<tbody></tbody>
|
|
120
|
+
</table>
|
|
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;">
|
|
122
|
+
<colgroup>${colWidths}</colgroup>
|
|
123
|
+
<tbody><tr>${trEditor_html}</tr></tbody>
|
|
124
|
+
</table>
|
|
125
|
+
</div>
|
|
126
|
+
</td>
|
|
127
|
+
</tr>
|
|
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>
|
|
141
|
+
</tr>
|
|
142
|
+
</table>
|
|
143
|
+
</div>`;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
#attachEvents() {
|
|
147
|
+
const dkgrid = this;
|
|
148
|
+
this.tableEditor.addEventListener('keydown', function (event) {
|
|
149
|
+
const keyCode = event.keyCode || event.which;
|
|
150
|
+
|
|
151
|
+
dkgrid.#keyDownOnTable(keyCode);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
this.tableRaw.addEventListener('click', function (event) {
|
|
155
|
+
const clickedRow = event.target.closest('tr');
|
|
156
|
+
if (clickedRow) {
|
|
157
|
+
dkgrid.#rowClick(event);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
document.getElementById(this.id + "_gridToolCell").addEventListener('click', (event) => {
|
|
161
|
+
const cmdElement = event.target.closest('li[data-cmd]');
|
|
162
|
+
if (!cmdElement) return;
|
|
163
|
+
|
|
164
|
+
const cmd = cmdElement.dataset.cmd;
|
|
165
|
+
switch (cmd) {
|
|
166
|
+
case "add": this.addNewRow(); break;
|
|
167
|
+
case "del": this.deleteRow(); break;
|
|
168
|
+
case "save": this.commitData(); break;
|
|
169
|
+
case "cancel": this.cancelChanges(); break;
|
|
170
|
+
}
|
|
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
|
+
});
|
|
194
|
+
}
|
|
195
|
+
#keyDownOnTable(keyCode) {
|
|
196
|
+
// ESC
|
|
197
|
+
if (keyCode == 27) {
|
|
198
|
+
if (this.rowOnFocus) {
|
|
199
|
+
const lastRow = this.rowOnFocus;
|
|
200
|
+
this.#closeEditor(lastRow, true);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
// ENTER
|
|
204
|
+
if (keyCode == 13) {
|
|
205
|
+
if (this.rowOnFocus) {
|
|
206
|
+
const lastRow = this.rowOnFocus;
|
|
207
|
+
this.#closeEditor(lastRow, false);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
#rowClick(sender) {
|
|
212
|
+
const trTag = sender.target.closest('tr');
|
|
213
|
+
const tableConfig = this.config;
|
|
214
|
+
if (this.rowOnFocus) {
|
|
215
|
+
const lastRow = this.rowOnFocus;
|
|
216
|
+
if (lastRow.dataset.editting == "1") {
|
|
217
|
+
this.#closeEditor(lastRow, false);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
this.rowOnFocus = trTag;
|
|
221
|
+
if (!tableConfig.allowEdit) return;
|
|
222
|
+
|
|
223
|
+
if (this.#openEditor(trTag) == false) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const cellIndex = sender.target.cellIndex;
|
|
228
|
+
const tbEditor = this.tableEditor;
|
|
229
|
+
var cell = tbEditor.querySelector('tbody').querySelectorAll('td')[cellIndex];
|
|
230
|
+
if (cell?.firstChild) {
|
|
231
|
+
cell.firstChild.focus();
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
#openEditor(trTag = new HTMLElement()) {
|
|
235
|
+
const table = trTag.closest('table');
|
|
236
|
+
const tableConfig = this.config;
|
|
237
|
+
const primaryKey = tableConfig.primaryKey;
|
|
238
|
+
const currentKeyValue = trTag.dataset.primaryValue;
|
|
239
|
+
|
|
240
|
+
const cache = this.#cache;
|
|
241
|
+
|
|
242
|
+
let objectCurrent = cache.updated[currentKeyValue] || cache.origin[currentKeyValue];
|
|
243
|
+
{
|
|
244
|
+
let throwX = false;
|
|
245
|
+
this.fireEvent('openEditor', (rs) => {
|
|
246
|
+
throwX = rs === false;
|
|
247
|
+
return !throwX;
|
|
248
|
+
}, objectCurrent, this);
|
|
249
|
+
if (throwX) return false;
|
|
250
|
+
}
|
|
251
|
+
const tbEditor = this.tableEditor;
|
|
252
|
+
tbEditor.querySelector('tbody').querySelectorAll('td').forEachExt(
|
|
253
|
+
child => {
|
|
254
|
+
const input = child.firstChild;
|
|
255
|
+
try {
|
|
256
|
+
if (input.tagName == "INPUT" || input.tagName == "SELECT") {
|
|
257
|
+
input.value = objectCurrent[input.name] || "";
|
|
258
|
+
if (input.type == 'checkbox') {
|
|
259
|
+
input.checked = objectCurrent[input.name] || false;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
} catch (exx) {
|
|
263
|
+
console.log("Error in openEditor: ", exx);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
);
|
|
267
|
+
tbEditor.style.top = trTag.offsetTop + "px";
|
|
268
|
+
tbEditor.style.display = "table";
|
|
269
|
+
trTag.dataset.editting = '1';
|
|
270
|
+
return true;
|
|
271
|
+
}
|
|
272
|
+
#closeEditor(trTag = new HTMLElement(), isClear = false, isdelete = false) {
|
|
273
|
+
const table = trTag.closest('table');
|
|
274
|
+
const tbEditor = this.tableEditor;
|
|
275
|
+
if (!isdelete) {
|
|
276
|
+
const tableConfig = this.config;
|
|
277
|
+
const primaryKey = tableConfig.primaryKey;
|
|
278
|
+
const currentKeyValue = trTag.dataset.primaryValue;
|
|
279
|
+
const cache = this.#cache;
|
|
280
|
+
|
|
281
|
+
let objectCurrent = cache.updated[currentKeyValue] || {...cache.origin[currentKeyValue]};
|
|
282
|
+
let objectEditing = {};
|
|
283
|
+
let hasChange = false;
|
|
284
|
+
tbEditor.querySelector('tbody').querySelectorAll('td').forEachExt(
|
|
285
|
+
child => {
|
|
286
|
+
const input = child.firstChild;
|
|
287
|
+
if (input.tagName == "INPUT" || input.tagName == "SELECT") {
|
|
288
|
+
objectEditing[input.name] = input.value;
|
|
289
|
+
if (input.type == 'checkbox') {
|
|
290
|
+
objectEditing[input.name] = input.checked;
|
|
291
|
+
}
|
|
292
|
+
if (input.type == 'number') {
|
|
293
|
+
objectEditing[input.name] = Number.parseFloat(input.value) || "";
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
if (objectCurrent[input.name] != objectEditing[input.name]) {
|
|
297
|
+
hasChange = true;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
);
|
|
301
|
+
if (hasChange) {
|
|
302
|
+
let isBreak = false;
|
|
303
|
+
if (isClear) {
|
|
304
|
+
if (confirm("Bạn có chắc chắn muốn hủy bỏ tất cả thay đổi không?")) {
|
|
305
|
+
isBreak = true;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
if (!isBreak) {
|
|
309
|
+
Object.keys(objectEditing).forEach(key => {
|
|
310
|
+
objectCurrent[key] = objectEditing[key];
|
|
311
|
+
});
|
|
312
|
+
cache.updated[currentKeyValue] = objectCurrent;
|
|
313
|
+
this.#createRow(trTag, objectCurrent);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
tbEditor.style.top = "-50px";
|
|
318
|
+
tbEditor.style.display = "none";
|
|
319
|
+
trTag.dataset.editting = '0';
|
|
320
|
+
}
|
|
321
|
+
#createRow(trTag, data) {
|
|
322
|
+
const table = trTag.closest('table');
|
|
323
|
+
const tableConfig = this.config;
|
|
324
|
+
const item = data;
|
|
325
|
+
trTag.innerHTML = "";
|
|
326
|
+
tableConfig.column.forEach(f => {
|
|
327
|
+
const td = document.createElement('td');
|
|
328
|
+
switch (f.dataType) {
|
|
329
|
+
case "string": td.textContent = item[f.fieldName]; break;
|
|
330
|
+
case "bool":
|
|
331
|
+
td.textContent = item[f.fieldName] ? "checked" : "";
|
|
332
|
+
td.innerHTML = `<input type='checkbox' ${td.textContent}/>`; break;
|
|
333
|
+
case "date": td.textContent = item[f.fieldName] || ''; break;
|
|
334
|
+
case "number": td.textContent = item[f.fieldName] || ''; break;
|
|
335
|
+
case "select":
|
|
336
|
+
td.textContent = f.items.find(i => i.value == item[f.fieldName])?.text;
|
|
337
|
+
break;
|
|
338
|
+
default: td.textContent = item[f.fieldName]; break;
|
|
339
|
+
}
|
|
340
|
+
trTag.appendChild(td);
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
loadData(data) {
|
|
344
|
+
const cache = this.#cache;
|
|
345
|
+
if (data) {
|
|
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);
|
|
353
|
+
}
|
|
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];
|
|
362
|
+
});
|
|
363
|
+
Object.keys(cache.updated).forEach(key => {
|
|
364
|
+
dataCollection[key] = cache.updated[key];
|
|
365
|
+
});
|
|
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
|
+
}
|
|
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;
|
|
423
|
+
const tbody = table.querySelector('tbody');
|
|
424
|
+
tbody.innerHTML = '';
|
|
425
|
+
dataPrint.forEach(
|
|
426
|
+
item => {
|
|
427
|
+
const tr = document.createElement('tr');
|
|
428
|
+
tr.dataset.primaryValue = item[tableConfig.primaryKey];
|
|
429
|
+
tr.dataset.editting = '0';
|
|
430
|
+
tableConfig.column.forEach(f => {
|
|
431
|
+
const td = document.createElement('td');
|
|
432
|
+
switch (f.dataType) {
|
|
433
|
+
case "string": td.textContent = item[f.fieldName]; break;
|
|
434
|
+
case "bool":
|
|
435
|
+
td.textContent = item[f.fieldName] ? "checked" : "";
|
|
436
|
+
td.innerHTML = `<input type='checkbox' ${td.textContent}/>`; break;
|
|
437
|
+
case "date": td.textContent = item[f.fieldName] || ''; break;
|
|
438
|
+
case "number": td.textContent = item[f.fieldName] || ''; break;
|
|
439
|
+
case "select":
|
|
440
|
+
td.textContent = f.items.find(i => i.value == item[f.fieldName]).text;
|
|
441
|
+
break;
|
|
442
|
+
default: td.textContent = item[f.fieldName]; break;
|
|
443
|
+
}
|
|
444
|
+
tr.appendChild(td);
|
|
445
|
+
});
|
|
446
|
+
tbody.appendChild(tr);
|
|
447
|
+
}
|
|
448
|
+
);
|
|
449
|
+
}
|
|
450
|
+
addNewRow() {
|
|
451
|
+
const tbody = this.tableRaw.querySelector('tbody');
|
|
452
|
+
const newTR = document.createElement('tr');
|
|
453
|
+
tbody.appendChild(newTR);
|
|
454
|
+
const tableConfig = this.config;
|
|
455
|
+
const primaryKey = tableConfig.primaryKey;
|
|
456
|
+
let newOb = {};
|
|
457
|
+
{
|
|
458
|
+
this.fireEvent('onCreateNewKey', (rs) => {
|
|
459
|
+
newOb[primaryKey] = rs;
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
if (!newOb[primaryKey]) {
|
|
463
|
+
newOb[primaryKey] = DKGrid.generateRandomString(32);
|
|
464
|
+
}
|
|
465
|
+
newTR.dataset.primaryValue = newOb[primaryKey];
|
|
466
|
+
const cache = this.#cache;
|
|
467
|
+
cache.updated[newOb[primaryKey]] = (newOb);
|
|
468
|
+
this.#createRow(newTR, newOb);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
deleteRow() {
|
|
472
|
+
if (this.rowOnFocus) {
|
|
473
|
+
if (confirm("Bạn có chắc chắn muốn xóa dữ liệu này?") != true) return;
|
|
474
|
+
this.#closeEditor(this.rowOnFocus, true, true);
|
|
475
|
+
const cache = this.#cache;
|
|
476
|
+
const tableConfig = this.config;
|
|
477
|
+
const primaryKey = tableConfig.primaryKey;
|
|
478
|
+
const lastRow = this.rowOnFocus;
|
|
479
|
+
const currentKeyValue = lastRow.dataset.primaryValue;
|
|
480
|
+
const objectOriginal = cache.origin[currentKeyValue];
|
|
481
|
+
if (objectOriginal) {
|
|
482
|
+
cache.deleted[currentKeyValue] = (objectOriginal);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
let objectCache = cache.updated[currentKeyValue];
|
|
486
|
+
if (objectCache) {
|
|
487
|
+
delete cache.updated[currentKeyValue];
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
table.dataset.cache = JSON.stringify(cache);
|
|
491
|
+
lastRow.remove();
|
|
492
|
+
delete this.rowOnFocus;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
commitData() {
|
|
497
|
+
this.fireEvent('commitData', null, ({ updated: this.#cache.updated, deleted: this.#cache.deleted }));
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
cancelChanges() {
|
|
501
|
+
if (confirm("Bạn có chắc chắn muốn hủy bỏ tất cả thay đổi không?") != true) {
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
const cache = this.#cache;
|
|
505
|
+
const dataOrigin = [];
|
|
506
|
+
Object.keys(cache.origin).forEach(key => {
|
|
507
|
+
dataOrigin.push(cache.origin[key]);
|
|
508
|
+
});
|
|
509
|
+
this.loadData(dataOrigin);
|
|
510
|
+
}
|
|
511
|
+
static inputCheckboxReadOnly(event) {
|
|
512
|
+
event.preventDefault();
|
|
513
|
+
}
|
|
514
|
+
static generateRandomString(length = 8) {
|
|
515
|
+
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
|
516
|
+
let result = '';
|
|
517
|
+
const charactersLength = characters.length;
|
|
518
|
+
for (let i = 0; i < length; i++) {
|
|
519
|
+
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
|
520
|
+
}
|
|
521
|
+
return result.toUpperCase();
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
525
|
+
const scriptElements = document.getElementsByTagName('script');
|
|
526
|
+
for (let x = 0; x < scriptElements.length; x++) {
|
|
527
|
+
const currentScript = scriptElements[x];
|
|
528
|
+
const scriptPath = currentScript.src;
|
|
529
|
+
if (scriptPath.endsWith('/dkgrid.js')) {
|
|
530
|
+
const currentScriptPath = scriptPath.substring(0, scriptPath.lastIndexOf('/dkgrid.js'))
|
|
531
|
+
DK.ImportCss(currentScriptPath + '/DKGrid.css');
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
});
|
package/Cores/file/dk.js
CHANGED
|
@@ -92,7 +92,7 @@ const DK = {
|
|
|
92
92
|
|
|
93
93
|
const divImage = document.createElement('div');
|
|
94
94
|
divImage.style.cssText = `height: 100%;display: flex;flex-direction: column;align-items: center;justify-content: center;`;
|
|
95
|
-
divImage.innerHTML = `<img style='position: fixed;opacity: 0.1;
|
|
95
|
+
divImage.innerHTML = `<img style='position: fixed;opacity: 0.1;' src='${(DK.varHide.currentScriptPath + '/' + imageName)}'/>`;
|
|
96
96
|
const overlay_inner = document.createElement('span');
|
|
97
97
|
overlay_inner.style.cssText = 'font-weight: bold;overflow-wrap: anywhere;max-width: 500px;z-index: 1;overflow: auto;';
|
|
98
98
|
overlay_inner.classList.add('dk-overlay_inner');
|
|
@@ -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;
|
|
@@ -131,12 +158,18 @@ const DK = {
|
|
|
131
158
|
|
|
132
159
|
document.getElementsByTagName("head")[0].appendChild(link);
|
|
133
160
|
},
|
|
134
|
-
ImportJS: (src) => {
|
|
161
|
+
ImportJS: (src, isModule = false) => {
|
|
135
162
|
var scriptJS = document.createElement("script");
|
|
136
163
|
scriptJS.src = src;
|
|
164
|
+
if (isModule) scriptJS.type = "module";
|
|
137
165
|
document.getElementsByTagName("head")[0].appendChild(scriptJS);
|
|
138
166
|
}
|
|
139
167
|
}
|
|
168
|
+
Object.prototype.forEachExt = function (work) {
|
|
169
|
+
for (let i = 0; i < this.length; i++) {
|
|
170
|
+
work(this[i], i, this);
|
|
171
|
+
}
|
|
172
|
+
};
|
|
140
173
|
document.addEventListener('DOMContentLoaded', () => {
|
|
141
174
|
const scriptElements = document.getElementsByTagName('script');
|
|
142
175
|
for (let x = 0; x < scriptElements.length; x++) {
|
|
@@ -145,10 +178,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
145
178
|
if (scriptPath.endsWith('/dk.js')) {
|
|
146
179
|
DK.varHide.currentScriptPath = scriptPath.substring(0, scriptPath.lastIndexOf('/dk.js'))
|
|
147
180
|
DK.ImportCss(DK.varHide.currentScriptPath + '/dk.css');
|
|
148
|
-
setTimeout(() => {
|
|
149
|
-
DK.ImportJS(DK.varHide.currentScriptPath + '/dk_table.js');
|
|
150
|
-
DK.ImportCss(DK.varHide.currentScriptPath + '/dk_table.css');
|
|
151
|
-
}, 100);
|
|
152
181
|
}
|
|
153
182
|
}
|
|
154
|
-
});
|
|
183
|
+
});
|
package/package.json
CHANGED
|
@@ -9,14 +9,15 @@
|
|
|
9
9
|
"socket.io": "^4.7.2"
|
|
10
10
|
},
|
|
11
11
|
"name": "mdkcontroller",
|
|
12
|
-
"version": "1.1
|
|
12
|
+
"version": "1.2.1",
|
|
13
13
|
"keywords": [],
|
|
14
14
|
"author": "KHANHNBD <khanh272421@gmail.com>",
|
|
15
15
|
"license": "ISC",
|
|
16
16
|
"description": "Quick setup authentication and express",
|
|
17
17
|
"type": "module",
|
|
18
18
|
"exports": {
|
|
19
|
-
".": "./index.js"
|
|
19
|
+
".": "./index.js",
|
|
20
|
+
"./autosequence": "./dk_modules/autoSequence.js"
|
|
20
21
|
},
|
|
21
22
|
"types": "./index.js",
|
|
22
23
|
"files": [
|
|
@@ -24,7 +25,6 @@
|
|
|
24
25
|
"main.js",
|
|
25
26
|
"index.js",
|
|
26
27
|
"Cores/",
|
|
27
|
-
"dk_modules/"
|
|
28
|
-
"Pages/"
|
|
28
|
+
"dk_modules/"
|
|
29
29
|
]
|
|
30
|
-
}
|
|
30
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#some thing
|
package/Cores/file/dk_table.css
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
.dk-table-x1 {
|
|
2
|
-
font-family: Arial, Helvetica, sans-serif;
|
|
3
|
-
border-collapse: collapse;
|
|
4
|
-
width: 100%;
|
|
5
|
-
min-width: 800px;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
.dk-table-x1 th {
|
|
9
|
-
padding: 5px;
|
|
10
|
-
font-size: 15px;
|
|
11
|
-
}
|
|
12
|
-
.dk-table-x1 td {
|
|
13
|
-
font-size: 13px;
|
|
14
|
-
border: 1px solid #ddd;
|
|
15
|
-
}
|
|
16
|
-
.dk-table-x1 tr:nth-child(even) {
|
|
17
|
-
background-color: #f2f2f2;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
.dk-table-x1 tr:hover {
|
|
21
|
-
background-color: #ddd;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
.dk-table-x1 th {
|
|
25
|
-
padding-top: 12px;
|
|
26
|
-
padding-bottom: 12px;
|
|
27
|
-
text-align: left;
|
|
28
|
-
background-color: #04aa6d;
|
|
29
|
-
color: white;
|
|
30
|
-
font-weight: bold;
|
|
31
|
-
border: 1px solid;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
.dk-table-x1 input[type="checkbox"] {
|
|
35
|
-
min-height: 22px;
|
|
36
|
-
width: 30px;
|
|
37
|
-
margin: auto;
|
|
38
|
-
display: block;
|
|
39
|
-
}
|
|
40
|
-
.dk-table-x1 input[type="checkbox"]:disabled {
|
|
41
|
-
cursor: not-allowed;
|
|
42
|
-
}
|
|
43
|
-
.dk-table-x1 input:not([type="checkbox"]) {
|
|
44
|
-
width: 100%;
|
|
45
|
-
}
|
|
46
|
-
.dk-table-x1 input:not(:disabled) {
|
|
47
|
-
display: block;
|
|
48
|
-
color: #495057;
|
|
49
|
-
background-color: #fff;
|
|
50
|
-
background-image: none;
|
|
51
|
-
background-clip: padding-box;
|
|
52
|
-
border: 1px solid rgba(0, 0, 0, 0.15);
|
|
53
|
-
border-radius: 0.25rem;
|
|
54
|
-
transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
|
|
55
|
-
}
|
|
56
|
-
.dk-actionsBar {
|
|
57
|
-
padding: 5px 10px;
|
|
58
|
-
width: max-content;
|
|
59
|
-
}
|
|
60
|
-
.dk-actionsBar button {
|
|
61
|
-
border-radius: 6px;
|
|
62
|
-
border: none;
|
|
63
|
-
}
|
package/Cores/file/dk_table.js
DELETED
|
@@ -1,252 +0,0 @@
|
|
|
1
|
-
const DKTable = {
|
|
2
|
-
rowOnFocus: {},
|
|
3
|
-
rowClick: (sender) => {
|
|
4
|
-
const trTag = sender.currentTarget;
|
|
5
|
-
const table = trTag.upParent('table');
|
|
6
|
-
if (trTag.dataset.editting == "true") return;
|
|
7
|
-
const cellIndex = sender.target.cellIndex;
|
|
8
|
-
if (DKTable.rowOnFocus[table.id]) {
|
|
9
|
-
const lastRow = DKTable.rowOnFocus[table.id];
|
|
10
|
-
DKTable.hideUpdateRecord(lastRow, table, false);
|
|
11
|
-
}
|
|
12
|
-
DKTable.rowOnFocus[table.id] = trTag;
|
|
13
|
-
|
|
14
|
-
const storeData = JSON.parse(table.dataset.store);
|
|
15
|
-
const fieldTypes = JSON.parse(table.dataset.fieldType);
|
|
16
|
-
const primaryKey = table.dataset.primaryKey;
|
|
17
|
-
const currentKeyValue = trTag.dataset.primaryValue;
|
|
18
|
-
|
|
19
|
-
const cache = JSON.parse(table.dataset.cache || JSON.stringify({ updated: [], deleted: [] }));
|
|
20
|
-
let objectCurrent = cache.updated.find(f => f[primaryKey] == currentKeyValue);
|
|
21
|
-
if (!objectCurrent) {
|
|
22
|
-
objectCurrent = storeData.find(f => f[primaryKey] == currentKeyValue);
|
|
23
|
-
}
|
|
24
|
-
DKTable.hideLoadRecord(trTag, objectCurrent, fieldTypes, sender.target);
|
|
25
|
-
console.log('Your input is: ', sender.target);
|
|
26
|
-
var cell = trTag.cells[cellIndex];
|
|
27
|
-
if (cell?.children[0]) {
|
|
28
|
-
cell.children[0].focus();
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
hideUpdateRecord: (trTag = new HTMLElement(), table = new HTMLElement(), isClear = false) => {
|
|
32
|
-
if (trTag.dataset.editting == 'false') {
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
const storeData = JSON.parse(table.dataset.store);
|
|
36
|
-
const fieldTypes = JSON.parse(table.dataset.fieldType);
|
|
37
|
-
const primaryKey = table.dataset.primaryKey;
|
|
38
|
-
const currentKeyValue = trTag.dataset.primaryValue;
|
|
39
|
-
const objectCurrent = storeData.find(f => f[primaryKey] == currentKeyValue) || {};
|
|
40
|
-
///
|
|
41
|
-
const cache = JSON.parse(table.dataset.cache || JSON.stringify({ updated: [], deleted: [] }));
|
|
42
|
-
let itemOnCache = cache.updated.find(f => f[primaryKey] == currentKeyValue);
|
|
43
|
-
if (!itemOnCache) {
|
|
44
|
-
if (isClear) {
|
|
45
|
-
itemOnCache = objectCurrent;
|
|
46
|
-
DKTable.rowOnFocus[table.id] = undefined;
|
|
47
|
-
} else {
|
|
48
|
-
cache.updated.push({ ...objectCurrent });
|
|
49
|
-
itemOnCache = cache.updated.find(f => f[primaryKey] == currentKeyValue);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
if (!isClear) {
|
|
53
|
-
fieldTypes.forEach(field => {
|
|
54
|
-
const input = trTag.querySelector(`input[name="${field.fieldName}"]`).closest('input');
|
|
55
|
-
if (input) {
|
|
56
|
-
switch (input.type) {
|
|
57
|
-
case 'checkbox':
|
|
58
|
-
itemOnCache[field.fieldName] = input.checked;
|
|
59
|
-
break;
|
|
60
|
-
default:
|
|
61
|
-
itemOnCache[field.fieldName] = input.value;
|
|
62
|
-
break;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
trTag.dataset.primaryValue = itemOnCache[primaryKey];
|
|
68
|
-
trTag.innerHTML = "";
|
|
69
|
-
fieldTypes.forEach(field => {
|
|
70
|
-
const td = document.createElement('td');
|
|
71
|
-
switch (field.dataType) {
|
|
72
|
-
case "boolean":
|
|
73
|
-
td.innerHTML = `<input type="checkbox" ${(itemOnCache[field.fieldName] ? 'checked' : '')} onclick='DKTable.inputCheckboxReadOnly(event)'>`; break;
|
|
74
|
-
default:
|
|
75
|
-
td.innerText = itemOnCache[field.fieldName]; break;
|
|
76
|
-
}
|
|
77
|
-
trTag.appendChild(td);
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
let areEqual = true;
|
|
81
|
-
let hasChild = false;
|
|
82
|
-
for (const key in itemOnCache) {
|
|
83
|
-
hasChild = true;
|
|
84
|
-
if (objectCurrent[key] !== itemOnCache[key]) {
|
|
85
|
-
areEqual = false;
|
|
86
|
-
break;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
if (areEqual && hasChild) {
|
|
90
|
-
cache.updated = cache.updated.filter(obj => obj[primaryKey] !== itemOnCache[primaryKey]);
|
|
91
|
-
}
|
|
92
|
-
trTag.dataset.editting = "false";
|
|
93
|
-
table.dataset.cache = JSON.stringify(cache);
|
|
94
|
-
},
|
|
95
|
-
hideLoadRecord: (trTag = new HTMLElement(), data = {}, fieldTypes = []) => {
|
|
96
|
-
const inputWs = [];
|
|
97
|
-
for (let index = 0; index < trTag.children.length; index++) {
|
|
98
|
-
const element = trTag.children[index];
|
|
99
|
-
inputWs.push(element.clientWidth);
|
|
100
|
-
}
|
|
101
|
-
trTag.innerHTML = "";
|
|
102
|
-
let firsttd = null;
|
|
103
|
-
let ccinput = 0;
|
|
104
|
-
fieldTypes.forEach(field => {
|
|
105
|
-
const td = document.createElement('td');
|
|
106
|
-
td.style.minWidth = inputWs[ccinput++] + 'px';
|
|
107
|
-
switch (field.dataType) {
|
|
108
|
-
case "boolean":
|
|
109
|
-
td.innerHTML = `<input name="${field.fieldName}" type="checkbox" ${data[field.fieldName] ? 'checked' : ''}>`;
|
|
110
|
-
break;
|
|
111
|
-
case "number":
|
|
112
|
-
td.innerHTML = `<input name="${field.fieldName}" type='number' value='${data[field.fieldName] || 0}'>`;
|
|
113
|
-
break;
|
|
114
|
-
case "date":
|
|
115
|
-
td.innerHTML = `<input name="${field.fieldName}" type='date' value='${data[field.fieldName] || ""}'>`;
|
|
116
|
-
break;
|
|
117
|
-
default:
|
|
118
|
-
td.innerHTML = `<input name="${field.fieldName}" type='text' value='${data[field.fieldName] || ""}'>`;
|
|
119
|
-
break;
|
|
120
|
-
}
|
|
121
|
-
firsttd = firsttd || td;
|
|
122
|
-
trTag.appendChild(td);
|
|
123
|
-
});
|
|
124
|
-
// firsttd.children[0].focus();
|
|
125
|
-
trTag.dataset.editting = "true";
|
|
126
|
-
},
|
|
127
|
-
CommitDataTable: (table = new HTMLElement()) => {
|
|
128
|
-
const storeData = JSON.parse(table.dataset.store);
|
|
129
|
-
if (DKTable.rowOnFocus[table.id]) {
|
|
130
|
-
const lastRow = DKTable.rowOnFocus[table.id];
|
|
131
|
-
DKTable.hideUpdateRecord(lastRow, table, false);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const cache = JSON.parse(table.dataset.cache || JSON.stringify({ updated: [], deleted: [] }));
|
|
135
|
-
const host = document.location.origin;
|
|
136
|
-
DK.showBusy(true, "Đang cập nhật thông tin phân quyền video");
|
|
137
|
-
fetch(host + table.dataset.postTo, {
|
|
138
|
-
method: "POST",
|
|
139
|
-
headers: {
|
|
140
|
-
'Content-Type': 'application/json'
|
|
141
|
-
},
|
|
142
|
-
body: JSON.stringify(cache)
|
|
143
|
-
})
|
|
144
|
-
.then(response => {
|
|
145
|
-
if (response.ok) {
|
|
146
|
-
return response.json();
|
|
147
|
-
} else {
|
|
148
|
-
throw new Error('API request failed');
|
|
149
|
-
}
|
|
150
|
-
})
|
|
151
|
-
.then(res => {
|
|
152
|
-
DK.showBusy(false, "Đang cập nhật thông tin phân quyền video");
|
|
153
|
-
if (res.success) {
|
|
154
|
-
DK.showMessage("Đã cập nhật thành công", 1);
|
|
155
|
-
}
|
|
156
|
-
else {
|
|
157
|
-
DK.showMessage(res.message, 4);
|
|
158
|
-
}
|
|
159
|
-
})
|
|
160
|
-
.catch(error => {
|
|
161
|
-
DK.showBusy(false, "Đang cập nhật thông tin phân quyền video");
|
|
162
|
-
DK.showMessage(error, 4);
|
|
163
|
-
});;
|
|
164
|
-
},
|
|
165
|
-
DeleteRowCurrent: (table = new HTMLElement()) => {
|
|
166
|
-
if (DKTable.rowOnFocus[table.id]) {
|
|
167
|
-
const storeData = JSON.parse(table.dataset.store);
|
|
168
|
-
const primaryKey = table.dataset.primaryKey;
|
|
169
|
-
const lastRow = DKTable.rowOnFocus[table.id];
|
|
170
|
-
const currentKeyValue = lastRow.dataset.primaryValue;
|
|
171
|
-
const objectOriginal = storeData.find(f => f[primaryKey] == currentKeyValue);
|
|
172
|
-
///
|
|
173
|
-
const cache = JSON.parse(table.dataset.cache || JSON.stringify({ updated: [], deleted: [] }));
|
|
174
|
-
let objectCache = cache.updated.find(f => f[primaryKey] == currentKeyValue);
|
|
175
|
-
if (objectOriginal) {
|
|
176
|
-
cache.deleted.push(objectOriginal);
|
|
177
|
-
}
|
|
178
|
-
cache.updated = cache.updated.filter(obj => obj[primaryKey] !== objectCache[primaryKey]);
|
|
179
|
-
table.dataset.cache = JSON.stringify(cache);
|
|
180
|
-
lastRow.remove();
|
|
181
|
-
delete DKTable.rowOnFocus[table.id];
|
|
182
|
-
}
|
|
183
|
-
},
|
|
184
|
-
AddNewRow: (table = new HTMLElement()) => {
|
|
185
|
-
const fieldTypes = JSON.parse(table.dataset.fieldType);
|
|
186
|
-
const primaryKey = table.dataset.primaryKey;
|
|
187
|
-
const cache = JSON.parse(table.dataset.cache || JSON.stringify({ updated: [], deleted: [] }));
|
|
188
|
-
|
|
189
|
-
const tbody = table.downChild('tbody');
|
|
190
|
-
const trTag = document.createElement('tr');
|
|
191
|
-
trTag.onclick = () => { DKTable.rowClick(trTag) };
|
|
192
|
-
const currentTicks = new Date().getTime();
|
|
193
|
-
if (!fieldTypes.find(f => f.fieldName == primaryKey)) {
|
|
194
|
-
trTag.dataset.primaryValue = "AutoGenerate_" + currentTicks.toString();
|
|
195
|
-
cache.updated.push(JSON.parse(`{"${primaryKey}":"${trTag.dataset.primaryValue}"}`));
|
|
196
|
-
table.dataset.cache = JSON.stringify(cache);
|
|
197
|
-
}
|
|
198
|
-
trTag.innerHTML = "";
|
|
199
|
-
fieldTypes.forEach(field => {
|
|
200
|
-
const td = document.createElement('td');
|
|
201
|
-
switch (field.dataType) {
|
|
202
|
-
case "boolean":
|
|
203
|
-
td.innerHTML = `<input type="checkbox" disabled>`;
|
|
204
|
-
break;
|
|
205
|
-
case "number":
|
|
206
|
-
td.innerText = 0;
|
|
207
|
-
break;
|
|
208
|
-
default:
|
|
209
|
-
td.innerText = "";
|
|
210
|
-
break;
|
|
211
|
-
}
|
|
212
|
-
trTag.appendChild(td);
|
|
213
|
-
});
|
|
214
|
-
trTag.dataset.editting = "false";
|
|
215
|
-
tbody.appendChild(trTag);
|
|
216
|
-
},
|
|
217
|
-
keyDownOnTable: (keyCode, sender) => {
|
|
218
|
-
// ESC
|
|
219
|
-
if (keyCode == 27) {
|
|
220
|
-
const table = sender;
|
|
221
|
-
if (DKTable.rowOnFocus[table.id]) {
|
|
222
|
-
const lastRow = DKTable.rowOnFocus[table.id];
|
|
223
|
-
DKTable.hideUpdateRecord(lastRow, table, true);
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
},
|
|
227
|
-
inputCheckboxReadOnly: (event) => {
|
|
228
|
-
event.preventDefault();
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
HTMLElement.prototype.upParent = function (name) {
|
|
232
|
-
if (this.parentNode.tagName.toLowerCase() == name.toLowerCase()) {
|
|
233
|
-
return this.parentNode;
|
|
234
|
-
}
|
|
235
|
-
if (this.parentNode) {
|
|
236
|
-
return this.parentNode.upParent(name);
|
|
237
|
-
}
|
|
238
|
-
return null;
|
|
239
|
-
}
|
|
240
|
-
HTMLElement.prototype.downChild = function (name) {
|
|
241
|
-
for (let index = 0; index < this.children.length; index++) {
|
|
242
|
-
const element = this.children[index];
|
|
243
|
-
if (element.tagName.toLowerCase() == name.toLowerCase()) {
|
|
244
|
-
return element;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
const downTry = element.downChild(name);
|
|
248
|
-
if (downTry)
|
|
249
|
-
return downTry;
|
|
250
|
-
}
|
|
251
|
-
return null;
|
|
252
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
.grid_Line {
|
|
2
|
-
display: flex;
|
|
3
|
-
justify-content: space-between;
|
|
4
|
-
padding: 0 20px;
|
|
5
|
-
align-items: center;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
.grid_Line > * {
|
|
9
|
-
overflow-wrap: anywhere;
|
|
10
|
-
padding: 3px;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
.grid_Line .f1 {
|
|
14
|
-
width: 100%;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
.grid_Line .f2 {
|
|
18
|
-
width: 50%;
|
|
19
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
.dk-usernameNav {
|
|
2
|
-
top: 0;
|
|
3
|
-
position: sticky;
|
|
4
|
-
border-bottom: 1px solid;
|
|
5
|
-
display: flow-root;
|
|
6
|
-
background-color: #ffffff2e;
|
|
7
|
-
backdrop-filter: blur(5px);
|
|
8
|
-
min-height: 25px;
|
|
9
|
-
padding: 5px 0 0 0;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
.dk-usernameNav .uleft {
|
|
13
|
-
display: flex;
|
|
14
|
-
float: left;
|
|
15
|
-
}
|
|
16
|
-
.dk-usernameNav .uleft a{
|
|
17
|
-
margin-right: 10px;
|
|
18
|
-
}
|
|
19
|
-
.dk-usernameNav .uright {
|
|
20
|
-
float: right;
|
|
21
|
-
display: flex;
|
|
22
|
-
flex-direction: row-reverse;
|
|
23
|
-
}
|
|
24
|
-
.dk-usernameNav .uright a{
|
|
25
|
-
margin-left: 10px;
|
|
26
|
-
}
|
|
27
|
-
.dk-usernameNav a:hover {
|
|
28
|
-
cursor: pointer;
|
|
29
|
-
}
|
|
30
|
-
.dk-usernameNav .menu > menu{
|
|
31
|
-
position: absolute;
|
|
32
|
-
display: block;
|
|
33
|
-
height: 0;
|
|
34
|
-
opacity: 0;
|
|
35
|
-
max-width: 300px;
|
|
36
|
-
background-color: black;
|
|
37
|
-
transition: all ease-out 0.2s;
|
|
38
|
-
overflow: hidden;
|
|
39
|
-
border-bottom-right-radius: 10px;
|
|
40
|
-
border-bottom-left-radius: 10px;
|
|
41
|
-
border: 1px solid #97e68e;
|
|
42
|
-
padding: 3px 10px;
|
|
43
|
-
margin: 0;
|
|
44
|
-
}
|
|
45
|
-
.dk-usernameNav .menu:hover {
|
|
46
|
-
menu{
|
|
47
|
-
height: auto;
|
|
48
|
-
opacity: 1;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
ul {
|
|
52
|
-
margin: 0;
|
|
53
|
-
}
|
|
54
|
-
/*MOBILE*/
|
|
55
|
-
|
|
56
|
-
@media only screen and (max-width: 767px) {
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/*DESKTOP*/
|
|
61
|
-
@media only screen and (min-width: 768px) {
|
|
62
|
-
|
|
63
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
@import "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css";
|
|
2
|
-
@import "global-nav.css";
|
|
3
|
-
@import "global-grid.css";
|
|
4
|
-
|
|
5
|
-
.bodyBox {
|
|
6
|
-
border: 0px solid;
|
|
7
|
-
border-radius: 10px;
|
|
8
|
-
margin: 30px;
|
|
9
|
-
padding: 0 10px;
|
|
10
|
-
background-color: rgba(0, 0, 0, 0.9);
|
|
11
|
-
min-height: 500px;
|
|
12
|
-
color: white;
|
|
13
|
-
font-size: 18px;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
.boxBorder {
|
|
17
|
-
border: 1px solid white;
|
|
18
|
-
border-radius: 8px;
|
|
19
|
-
padding: 5px;
|
|
20
|
-
margin: 5px;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
h1, h2, h3, h4, h5 {
|
|
24
|
-
margin: 0;
|
|
25
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<title>DashBoard SoThuChi</title>
|
|
6
|
-
<link rel="stylesheet" href="../asset/global.css">
|
|
7
|
-
<script type="text/javascript">
|
|
8
|
-
const _userInfo = {displayName: 'Duy Khanh '};
|
|
9
|
-
</script>
|
|
10
|
-
</head>
|
|
11
|
-
<body>
|
|
12
|
-
<div class="bodyBox">
|
|
13
|
-
<div class="dk-usernameNav">
|
|
14
|
-
<div class="uleft">
|
|
15
|
-
<a>Hi Khanhnbd</a>
|
|
16
|
-
<a class="menu">Menu
|
|
17
|
-
<menu >
|
|
18
|
-
<li>Xin Chào 1
|
|
19
|
-
<ul>
|
|
20
|
-
<li>Submenu 2-2-1</li>
|
|
21
|
-
<li>Submenu 2-2-2</li>
|
|
22
|
-
</ul>
|
|
23
|
-
</li>
|
|
24
|
-
</menu>
|
|
25
|
-
</a>
|
|
26
|
-
</div>
|
|
27
|
-
<div class="uright">
|
|
28
|
-
<a>Logout</a>
|
|
29
|
-
</div>
|
|
30
|
-
|
|
31
|
-
</div>
|
|
32
|
-
|
|
33
|
-
<div>
|
|
34
|
-
<div class="boxBorder" style="display: flex; flex-wrap: wrap;">
|
|
35
|
-
<div class="boxBorder" style="width: 200px; height: 100px;"></div>
|
|
36
|
-
<div class="boxBorder" style="width: 200px; height: 100px;"></div>
|
|
37
|
-
<div class="boxBorder" style="width: 200px; height: 100px;"></div>
|
|
38
|
-
<div class="boxBorder" style="width: 200px; height: 100px;"></div>
|
|
39
|
-
<div class="boxBorder" style="width: 200px; height: 100px;"></div>
|
|
40
|
-
<div class="boxBorder" style="width: 200px; height: 100px;"></div>
|
|
41
|
-
</div>
|
|
42
|
-
<div class="boxBorder">
|
|
43
|
-
<h4>Chi tiet giao dich</h4>
|
|
44
|
-
<div class="">
|
|
45
|
-
<div class="boxBorder">
|
|
46
|
-
<div class="grid_Line">
|
|
47
|
-
<span>Ngay 01.02.2023</span>
|
|
48
|
-
<span>800.000</span>
|
|
49
|
-
</div>
|
|
50
|
-
<div class="grid_Line" style="margin-left: 30px;">
|
|
51
|
-
<span class="f2">Logo</span>
|
|
52
|
-
<span class="f2">ADF</span>
|
|
53
|
-
<span class="f1">abcsdgasdtre</span>
|
|
54
|
-
<span class="f2">999,999</span>
|
|
55
|
-
</div>
|
|
56
|
-
<div class="grid_Line" style="margin-left: 30px;">
|
|
57
|
-
<span class="f2">Logo</span>
|
|
58
|
-
<span class="f2">ADF</span>
|
|
59
|
-
<span class="f1">abcsdgasdtreabcsdgasdtreabcsdgasdtreabcsdgasdtreabcsdgasdtreabcsdgasdtreabcsdgasdtre</span>
|
|
60
|
-
<span class="f2">999,999</span>
|
|
61
|
-
</div>
|
|
62
|
-
</div>
|
|
63
|
-
</div>
|
|
64
|
-
</div>
|
|
65
|
-
</div>
|
|
66
|
-
</div>
|
|
67
|
-
</body>
|
|
68
|
-
</html>
|
package/dk_modules/autohtml.js
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import pkg from 'handlebars';
|
|
2
|
-
const { compile } = pkg;
|
|
3
|
-
import { generateRandomToken } from './dkvar.js';
|
|
4
|
-
const configDefault = { postTo: '', allowCommit: true, allowEdit: true, primaryKey: '', column: [{ fieldName: '', title: '', dataType: '' }] };
|
|
5
|
-
configDefault.column.pop();
|
|
6
|
-
export function buildGridEdit(data, config = configDefault) {
|
|
7
|
-
let fields = getFieldTypes(data, config?.column);
|
|
8
|
-
const dataEncode = JSON.stringify(data);
|
|
9
|
-
let th_html = '';
|
|
10
|
-
let td_html = '';
|
|
11
|
-
if (fields.length == 0) {
|
|
12
|
-
fields.push({ dataType: 'string', fieldName: config.primaryKey });
|
|
13
|
-
config.column.map(p => { fields.push({ dataType: 'string', fieldName: p.fieldName }); });
|
|
14
|
-
fields = fields.filter(f => f.fieldName);
|
|
15
|
-
}
|
|
16
|
-
if (fields.length == 0) {
|
|
17
|
-
return "<h1> DATA AND CONFIGS IS EMPTY</h1>";
|
|
18
|
-
}
|
|
19
|
-
const tableFieldTypes = JSON.stringify(fields);
|
|
20
|
-
if (!config.column || config.column.length == 0) {
|
|
21
|
-
config.column = fields.map(f => { return { fieldName: f.fieldName, title: f.fieldName }; });
|
|
22
|
-
}
|
|
23
|
-
if (!config.primaryKey) {
|
|
24
|
-
config.primaryKey = fields[0].fieldName;
|
|
25
|
-
}
|
|
26
|
-
th_html = config.column.map(f => {
|
|
27
|
-
const minW = f.dataType == "string" ? 300 : 150;
|
|
28
|
-
return `<th style='min-width: ${minW}px;'>${f.title}</th>`;
|
|
29
|
-
}).join("");
|
|
30
|
-
td_html = config.column.map(f => {
|
|
31
|
-
const fieldType = fields.find(p => p.fieldName == f.fieldName)?.dataType.toLowerCase();
|
|
32
|
-
switch (fieldType) {
|
|
33
|
-
case "string": return `<td>{{${f.fieldName}}}</td>`;
|
|
34
|
-
case "boolean":
|
|
35
|
-
return `<td>{{#if this.${f.fieldName}}}
|
|
36
|
-
<input type="checkbox" checked onclick='DKTable.inputCheckboxReadOnly(event)'>
|
|
37
|
-
{{else}}
|
|
38
|
-
<input type="checkbox" onclick='DKTable.inputCheckboxReadOnly(event)'>
|
|
39
|
-
{{/if}}</td>`;
|
|
40
|
-
}
|
|
41
|
-
return `<td>{{${f.fieldName}}}</td>`;
|
|
42
|
-
}).join("");
|
|
43
|
-
const newTableId = generateRandomToken(20);
|
|
44
|
-
const tableTemplate = `
|
|
45
|
-
<table id='${newTableId}' class='dk-table-x1'
|
|
46
|
-
data-store='${dataEncode}' data-field-type='${tableFieldTypes}'
|
|
47
|
-
data-post-to='${config.postTo}'
|
|
48
|
-
data-primary-key='${config.primaryKey}'>
|
|
49
|
-
<thead>
|
|
50
|
-
<tr>${th_html}</tr>
|
|
51
|
-
</thead>
|
|
52
|
-
<tbody>
|
|
53
|
-
{{#each rows}}
|
|
54
|
-
<tr ${(config.allowEdit ? "onClick='DKTable.rowClick(event)'" : "")} data-primary-value='{{${config.primaryKey}}}'>${td_html}</tr>
|
|
55
|
-
{{/each}}
|
|
56
|
-
</tbody>
|
|
57
|
-
</table>
|
|
58
|
-
<div class='dk-actionsBar'>
|
|
59
|
-
${(config.allowCommit ? `<button class="btn-success" onClick="DKTable.CommitDataTable(document.getElementById('${newTableId}'))">Save</button>` : "")}
|
|
60
|
-
${(config.allowCommit ? `<button class="btn-outline-danger" onClick="DKTable.DeleteRowCurrent(document.getElementById('${newTableId}'))">Remove</button>` : "")}
|
|
61
|
-
${(config.allowCommit ? `<button class="btn-primary" onClick="DKTable.AddNewRow(document.getElementById('${newTableId}'))">Add</button>` : "")}
|
|
62
|
-
</div>
|
|
63
|
-
<script>
|
|
64
|
-
function onInit${newTableId}(){
|
|
65
|
-
document.getElementById('${newTableId}').addEventListener('keydown', function(event) {
|
|
66
|
-
const keyCode = event.keyCode || event.which;
|
|
67
|
-
DKTable.keyDownOnTable(keyCode,this);
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
onInit${newTableId}();
|
|
71
|
-
</script>
|
|
72
|
-
`;
|
|
73
|
-
|
|
74
|
-
// Biên dịch và in HTML
|
|
75
|
-
const template = compile(tableTemplate);
|
|
76
|
-
const html = template({ rows: data });
|
|
77
|
-
return html;
|
|
78
|
-
}
|
|
79
|
-
function getFieldTypes(array, columns = []) {
|
|
80
|
-
if (columns?.length > 0) {
|
|
81
|
-
return columns;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (!Array.isArray(array)) {
|
|
85
|
-
console.error('Đối số phải là một mảng.');
|
|
86
|
-
return [];
|
|
87
|
-
}
|
|
88
|
-
const fields = Object.keys(array[0]);
|
|
89
|
-
const fieldTypes = {};
|
|
90
|
-
array.forEach(item => {
|
|
91
|
-
fields.forEach(field => {
|
|
92
|
-
if (!fieldTypes[field]) {
|
|
93
|
-
fieldTypes[field] = typeof item[field];
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
return fields.map(p => { return { fieldName: p, dataType: fieldTypes[p] } });
|
|
99
|
-
}
|