@doyosi/laraisy 1.0.1 → 1.0.3
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/LICENSE +1 -1
- package/package.json +1 -1
- package/src/CodeInput.js +48 -48
- package/src/DSAlert.js +352 -352
- package/src/DSAvatar.js +207 -207
- package/src/DSDelete.js +274 -274
- package/src/DSForm.js +568 -568
- package/src/DSGridOrTable.js +453 -453
- package/src/DSLocaleSwitcher.js +239 -239
- package/src/DSLogout.js +293 -293
- package/src/DSNotifications.js +365 -365
- package/src/DSRestore.js +181 -181
- package/src/DSSelect.js +1071 -1071
- package/src/DSSelectBox.js +563 -563
- package/src/DSSimpleSlider.js +517 -517
- package/src/DSSvgFetch.js +69 -69
- package/src/DSTable/DSTableExport.js +68 -68
- package/src/DSTable/DSTableFilter.js +224 -224
- package/src/DSTable/DSTablePagination.js +136 -136
- package/src/DSTable/DSTableSearch.js +40 -40
- package/src/DSTable/DSTableSelection.js +192 -192
- package/src/DSTable/DSTableSort.js +58 -58
- package/src/DSTable.js +353 -353
- package/src/DSTabs.js +488 -488
- package/src/DSUpload.js +887 -887
- package/dist/CodeInput.d.ts +0 -10
- package/dist/DSAlert.d.ts +0 -112
- package/dist/DSAvatar.d.ts +0 -45
- package/dist/DSDelete.d.ts +0 -61
- package/dist/DSForm.d.ts +0 -151
- package/dist/DSGridOrTable/DSGOTRenderer.d.ts +0 -60
- package/dist/DSGridOrTable/DSGOTViewToggle.d.ts +0 -26
- package/dist/DSGridOrTable.d.ts +0 -296
- package/dist/DSLocaleSwitcher.d.ts +0 -71
- package/dist/DSLogout.d.ts +0 -76
- package/dist/DSNotifications.d.ts +0 -54
- package/dist/DSRestore.d.ts +0 -56
- package/dist/DSSelect.d.ts +0 -221
- package/dist/DSSelectBox.d.ts +0 -123
- package/dist/DSSimpleSlider.d.ts +0 -136
- package/dist/DSSvgFetch.d.ts +0 -17
- package/dist/DSTable/DSTableExport.d.ts +0 -11
- package/dist/DSTable/DSTableFilter.d.ts +0 -40
- package/dist/DSTable/DSTablePagination.d.ts +0 -12
- package/dist/DSTable/DSTableSearch.d.ts +0 -8
- package/dist/DSTable/DSTableSelection.d.ts +0 -46
- package/dist/DSTable/DSTableSort.d.ts +0 -8
- package/dist/DSTable.d.ts +0 -116
- package/dist/DSTabs.d.ts +0 -156
- package/dist/DSUpload.d.ts +0 -220
- package/dist/index.d.ts +0 -17
package/src/DSGridOrTable.js
CHANGED
|
@@ -1,453 +1,453 @@
|
|
|
1
|
-
import DSTablePagination from './DSTable/DSTablePagination.js';
|
|
2
|
-
import DSTableSearch from './DSTable/DSTableSearch.js';
|
|
3
|
-
import DSTableSort from './DSTable/DSTableSort.js';
|
|
4
|
-
import DSTableFilter from './DSTable/DSTableFilter.js';
|
|
5
|
-
import DSTableExport from './DSTable/DSTableExport.js';
|
|
6
|
-
import DSTableSelection from './DSTable/DSTableSelection.js';
|
|
7
|
-
import DSGOTRenderer from './DSGridOrTable/DSGOTRenderer.js';
|
|
8
|
-
import DSGOTViewToggle from './DSGridOrTable/DSGOTViewToggle.js';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* @typedef {Object} DSGridOrTableOptions
|
|
12
|
-
* @property {'table'|'grid'|'gridable'} [type] - Display type
|
|
13
|
-
* @property {'grid'|'table'} [defaultView] - For 'gridable' mode: initial view
|
|
14
|
-
* @property {boolean} [showToggle] - Show view toggle buttons
|
|
15
|
-
* @property {boolean} [pagination] - Enable pagination
|
|
16
|
-
* @property {boolean} [search] - Enable search
|
|
17
|
-
* @property {boolean} [sort] - Enable sorting
|
|
18
|
-
* @property {boolean} [filter] - Enable filtering
|
|
19
|
-
* @property {boolean} [export] - Enable export
|
|
20
|
-
* @property {boolean} [selection] - Enable selection
|
|
21
|
-
* @property {'ajax'|'html'|'json'} [table_source] - Data source type
|
|
22
|
-
* @property {string} [ajax_url] - URL for AJAX requests
|
|
23
|
-
* @property {Object} [ajax_data] - Additional data for AJAX requests
|
|
24
|
-
* @property {'GET'|'POST'|'PUT'} [ajax_method] - HTTP method
|
|
25
|
-
* @property {'xhr'|'axios'|'fetch'} [ajax_function] - Fetcher implementation
|
|
26
|
-
* @property {Object} [rowTemplate] - Template config for table rows
|
|
27
|
-
* @property {Object} [gridTemplate] - Template config for grid items
|
|
28
|
-
* @property {Object|number} [gridColumns] - Grid column configuration
|
|
29
|
-
* @property {number} [gridGap] - Tailwind gap value
|
|
30
|
-
* @property {string} [gridContainerClass] - Grid container class
|
|
31
|
-
* @property {string} [tableSelector] - Selector for table element
|
|
32
|
-
* @property {string} [bodySelector] - Selector for tbody element
|
|
33
|
-
* @property {string} [gridSelector] - Selector for grid container
|
|
34
|
-
* @property {string} [toggleSelector] - Selector for view toggle
|
|
35
|
-
* @property {string} [emptyMessage] - Message when no data found
|
|
36
|
-
* @property {string} [errorMessage] - Message on error
|
|
37
|
-
* @property {Function} [success] - Success callback
|
|
38
|
-
* @property {Function} [error] - Error callback
|
|
39
|
-
*/
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* DSGridOrTable
|
|
43
|
-
*
|
|
44
|
-
* A flexible data display plugin supporting Table, Grid, or switchable (Gridable) layouts.
|
|
45
|
-
* Built on top of DSTable architecture with extended rendering capabilities.
|
|
46
|
-
*
|
|
47
|
-
* @example
|
|
48
|
-
* // Table mode (like standard DSTable)
|
|
49
|
-
* const table = new DSGridOrTable('#container', {
|
|
50
|
-
* type: 'table',
|
|
51
|
-
* ajax_url: '/api/data',
|
|
52
|
-
* rowTemplate: { source: 'response', response: 'html' }
|
|
53
|
-
* });
|
|
54
|
-
*
|
|
55
|
-
* @example
|
|
56
|
-
* // Grid mode (card layout)
|
|
57
|
-
* const grid = new DSGridOrTable('#container', {
|
|
58
|
-
* type: 'grid',
|
|
59
|
-
* ajax_url: '/api/data',
|
|
60
|
-
* gridTemplate: { source: 'response', response: 'grid_html' }
|
|
61
|
-
* });
|
|
62
|
-
*
|
|
63
|
-
* @example
|
|
64
|
-
* // Gridable mode (toggle between table and grid)
|
|
65
|
-
* const gridable = new DSGridOrTable('#container', {
|
|
66
|
-
* type: 'gridable',
|
|
67
|
-
* ajax_url: '/api/data',
|
|
68
|
-
* rowTemplate: { source: 'response', response: 'html' },
|
|
69
|
-
* gridTemplate: { source: 'response', response: 'grid_html' },
|
|
70
|
-
* defaultView: 'grid',
|
|
71
|
-
* showToggle: true
|
|
72
|
-
* });
|
|
73
|
-
*/
|
|
74
|
-
export class DSGridOrTable {
|
|
75
|
-
static defaults = {
|
|
76
|
-
// Display type
|
|
77
|
-
type: 'table', // 'table' | 'grid' | 'gridable'
|
|
78
|
-
defaultView: 'grid', // For 'gridable' mode: 'grid' | 'table'
|
|
79
|
-
showToggle: true, // For 'gridable' mode: show view toggle buttons
|
|
80
|
-
|
|
81
|
-
// Standard features (same as DSTable)
|
|
82
|
-
pagination: true,
|
|
83
|
-
pagination_translations: {
|
|
84
|
-
prev: 'Previous',
|
|
85
|
-
next: 'Next',
|
|
86
|
-
goto: 'Go to',
|
|
87
|
-
stats: 'Showing {from} to {to} of {total} entries'
|
|
88
|
-
},
|
|
89
|
-
search: true,
|
|
90
|
-
sort: true,
|
|
91
|
-
filter: true,
|
|
92
|
-
export: true,
|
|
93
|
-
selection: true,
|
|
94
|
-
|
|
95
|
-
// Data source
|
|
96
|
-
table_source: 'ajax', // 'ajax' | 'html' | 'json'
|
|
97
|
-
ajax_url: null,
|
|
98
|
-
ajax_data: {},
|
|
99
|
-
ajax_method: 'GET',
|
|
100
|
-
ajax_function: 'axios', // 'xhr' | 'axios' | 'fetch'
|
|
101
|
-
|
|
102
|
-
// Callbacks
|
|
103
|
-
success: null,
|
|
104
|
-
error: null,
|
|
105
|
-
beforeSend: null,
|
|
106
|
-
afterSend: null,
|
|
107
|
-
|
|
108
|
-
// Template configurations
|
|
109
|
-
rowTemplate: {
|
|
110
|
-
source: 'response', // 'function' | 'html' | 'response'
|
|
111
|
-
response: 'html', // Property path in response data
|
|
112
|
-
function: null, // Function that returns HTML: (row, index) => '<tr>...</tr>'
|
|
113
|
-
html: null // Template string with {{placeholders}}
|
|
114
|
-
},
|
|
115
|
-
gridTemplate: {
|
|
116
|
-
source: 'response',
|
|
117
|
-
response: 'grid_html',
|
|
118
|
-
function: null,
|
|
119
|
-
html: null
|
|
120
|
-
},
|
|
121
|
-
|
|
122
|
-
// Grid layout options
|
|
123
|
-
gridColumns: {
|
|
124
|
-
default: 2,
|
|
125
|
-
sm: 1,
|
|
126
|
-
md: 2,
|
|
127
|
-
lg: 3,
|
|
128
|
-
xl: 4
|
|
129
|
-
},
|
|
130
|
-
gridGap: 4, // Tailwind gap value (gap-4)
|
|
131
|
-
gridContainerClass: 'ds-grid-container',
|
|
132
|
-
|
|
133
|
-
// Selectors
|
|
134
|
-
tableSelector: 'table',
|
|
135
|
-
bodySelector: 'tbody',
|
|
136
|
-
gridSelector: '.ds-grid-container',
|
|
137
|
-
toggleSelector: '.ds-view-toggle',
|
|
138
|
-
messageSelector: '.ds-table-message',
|
|
139
|
-
search_selector: null,
|
|
140
|
-
|
|
141
|
-
// Empty/Error states
|
|
142
|
-
emptyMessage: 'No data found',
|
|
143
|
-
emptyIcon: 'search_off',
|
|
144
|
-
errorMessage: 'Error loading data',
|
|
145
|
-
|
|
146
|
-
// Filter selectors (passed to DSTableFilter)
|
|
147
|
-
filter_selectors: {}
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* @param {string|HTMLElement} wrapper
|
|
152
|
-
* @param {DSGridOrTableOptions} options
|
|
153
|
-
*/
|
|
154
|
-
constructor(wrapper, options = {}) {
|
|
155
|
-
this.wrapper = typeof wrapper === 'string' ? document.querySelector(wrapper) : wrapper;
|
|
156
|
-
if (!this.wrapper) throw new Error('DSGridOrTable: Wrapper element not found');
|
|
157
|
-
|
|
158
|
-
// Merge configs with special handling for nested objects
|
|
159
|
-
/** @type {DSGridOrTableOptions} */
|
|
160
|
-
this.config = this._mergeDeep({}, DSGridOrTable.defaults, options);
|
|
161
|
-
|
|
162
|
-
// State
|
|
163
|
-
this.data = [];
|
|
164
|
-
this.meta = {};
|
|
165
|
-
this.params = {
|
|
166
|
-
page: 1,
|
|
167
|
-
per_page: 15,
|
|
168
|
-
sort_by: null,
|
|
169
|
-
sort_order: 'asc',
|
|
170
|
-
search: null,
|
|
171
|
-
filters: {}
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
this.modules = {};
|
|
175
|
-
this.isLoading = false;
|
|
176
|
-
this.currentView = this.config.defaultView;
|
|
177
|
-
|
|
178
|
-
this._init();
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
_mergeDeep(target, ...sources) {
|
|
182
|
-
if (!sources.length) return target;
|
|
183
|
-
const source = sources.shift();
|
|
184
|
-
|
|
185
|
-
if (this._isObject(target) && this._isObject(source)) {
|
|
186
|
-
for (const key in source) {
|
|
187
|
-
if (this._isObject(source[key])) {
|
|
188
|
-
if (!target[key]) Object.assign(target, { [key]: {} });
|
|
189
|
-
this._mergeDeep(target[key], source[key]);
|
|
190
|
-
} else {
|
|
191
|
-
Object.assign(target, { [key]: source[key] });
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
return this._mergeDeep(target, ...sources);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
_isObject(item) {
|
|
199
|
-
return item && typeof item === 'object' && !Array.isArray(item);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
_init() {
|
|
203
|
-
// Find elements based on type
|
|
204
|
-
this.table = this.wrapper.querySelector(this.config.tableSelector);
|
|
205
|
-
this.tbody = this.wrapper.querySelector(this.config.bodySelector) || this.table?.querySelector('tbody');
|
|
206
|
-
this.gridContainer = this.wrapper.querySelector(this.config.gridSelector);
|
|
207
|
-
|
|
208
|
-
// Create grid container if needed and not exists
|
|
209
|
-
if ((this.config.type === 'grid' || this.config.type === 'gridable') && !this.gridContainer) {
|
|
210
|
-
this.gridContainer = document.createElement('div');
|
|
211
|
-
this.gridContainer.className = this._buildGridClasses();
|
|
212
|
-
if (this.table) {
|
|
213
|
-
this.table.parentNode.insertBefore(this.gridContainer, this.table.nextSibling);
|
|
214
|
-
} else {
|
|
215
|
-
this.wrapper.insertBefore(this.gridContainer, this.wrapper.firstChild);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// Initialize the renderer module
|
|
220
|
-
this.renderer = new DSGOTRenderer(this);
|
|
221
|
-
|
|
222
|
-
// Initialize view toggle for gridable mode
|
|
223
|
-
if (this.config.type === 'gridable' && this.config.showToggle) {
|
|
224
|
-
this.viewToggle = new DSGOTViewToggle(this);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// Initialize standard modules (reuse DSTable modules)
|
|
228
|
-
if (this.config.pagination) this.modules.pagination = new DSTablePagination(this);
|
|
229
|
-
if (this.config.search) this.modules.search = new DSTableSearch(this);
|
|
230
|
-
if (this.config.sort && this.table) this.modules.sort = new DSTableSort(this);
|
|
231
|
-
if (this.config.filter) this.modules.filter = new DSTableFilter(this);
|
|
232
|
-
if (this.config.export) this.modules.export = new DSTableExport(this);
|
|
233
|
-
if (this.config.selection && this.table) this.modules.selection = new DSTableSelection(this);
|
|
234
|
-
|
|
235
|
-
// Set initial visibility based on type
|
|
236
|
-
this._setInitialVisibility();
|
|
237
|
-
|
|
238
|
-
// Initial data load
|
|
239
|
-
this.loadData();
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
_buildGridClasses() {
|
|
243
|
-
const { gridColumns, gridGap, gridContainerClass } = this.config;
|
|
244
|
-
let classes = `${gridContainerClass} grid gap-${gridGap}`;
|
|
245
|
-
|
|
246
|
-
// Build responsive column classes
|
|
247
|
-
if (typeof gridColumns === 'number') {
|
|
248
|
-
classes += ` grid-cols-${gridColumns}`;
|
|
249
|
-
} else if (typeof gridColumns === 'object') {
|
|
250
|
-
classes += ` grid-cols-${gridColumns.default || 1}`;
|
|
251
|
-
if (gridColumns.sm) classes += ` sm:grid-cols-${gridColumns.sm}`;
|
|
252
|
-
if (gridColumns.md) classes += ` md:grid-cols-${gridColumns.md}`;
|
|
253
|
-
if (gridColumns.lg) classes += ` lg:grid-cols-${gridColumns.lg}`;
|
|
254
|
-
if (gridColumns.xl) classes += ` xl:grid-cols-${gridColumns.xl}`;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
return classes;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
_setInitialVisibility() {
|
|
261
|
-
if (this.config.type === 'table') {
|
|
262
|
-
if (this.gridContainer) this.gridContainer.classList.add('hidden');
|
|
263
|
-
if (this.table) this.table.classList.remove('hidden');
|
|
264
|
-
} else if (this.config.type === 'grid') {
|
|
265
|
-
if (this.table) this.table.classList.add('hidden');
|
|
266
|
-
if (this.gridContainer) this.gridContainer.classList.remove('hidden');
|
|
267
|
-
} else { // gridable
|
|
268
|
-
if (this.currentView === 'grid') {
|
|
269
|
-
if (this.table) this.table.classList.add('hidden');
|
|
270
|
-
if (this.gridContainer) this.gridContainer.classList.remove('hidden');
|
|
271
|
-
} else {
|
|
272
|
-
if (this.gridContainer) this.gridContainer.classList.add('hidden');
|
|
273
|
-
if (this.table) this.table.classList.remove('hidden');
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// ================= DATA LOADING =================
|
|
279
|
-
|
|
280
|
-
async loadData() {
|
|
281
|
-
if (this.isLoading) return;
|
|
282
|
-
this.isLoading = true;
|
|
283
|
-
this._toggleLoading(true);
|
|
284
|
-
|
|
285
|
-
if (this.config.beforeSend) this.config.beforeSend({ params: this.params });
|
|
286
|
-
|
|
287
|
-
try {
|
|
288
|
-
if (this.config.table_source === 'ajax') {
|
|
289
|
-
await this._loadFromAjax();
|
|
290
|
-
} else if (this.config.table_source === 'json') {
|
|
291
|
-
this._handleDataSuccess(this.config.data || []);
|
|
292
|
-
} else if (this.config.table_source === 'html') {
|
|
293
|
-
this.isLoading = false;
|
|
294
|
-
this._toggleLoading(false);
|
|
295
|
-
}
|
|
296
|
-
} catch (error) {
|
|
297
|
-
console.error('DSGridOrTable: Error loading data', error);
|
|
298
|
-
if (this.config.error) this.config.error(error);
|
|
299
|
-
this.renderer.showError(this.config.errorMessage);
|
|
300
|
-
this.isLoading = false;
|
|
301
|
-
this._toggleLoading(false);
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
async _loadFromAjax() {
|
|
306
|
-
const url = this.config.ajax_url;
|
|
307
|
-
const method = this.config.ajax_method;
|
|
308
|
-
const data = { ...this.config.ajax_data, ...this.params };
|
|
309
|
-
|
|
310
|
-
let response;
|
|
311
|
-
|
|
312
|
-
if (this.config.ajax_function === 'axios' && window.axios) {
|
|
313
|
-
response = await window.axios({
|
|
314
|
-
method,
|
|
315
|
-
url,
|
|
316
|
-
params: method === 'GET' ? data : undefined,
|
|
317
|
-
data: method !== 'GET' ? data : undefined
|
|
318
|
-
});
|
|
319
|
-
this._handleDataSuccess(response.data);
|
|
320
|
-
} else if (this.config.ajax_function === 'fetch' || window.fetch) {
|
|
321
|
-
const queryString = new URLSearchParams(data).toString();
|
|
322
|
-
const fetchUrl = method === 'GET' ? `${url}?${queryString}` : url;
|
|
323
|
-
const options = {
|
|
324
|
-
method,
|
|
325
|
-
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
|
|
326
|
-
body: method !== 'GET' ? JSON.stringify(data) : undefined
|
|
327
|
-
};
|
|
328
|
-
const res = await fetch(fetchUrl, options);
|
|
329
|
-
const json = await res.json();
|
|
330
|
-
this._handleDataSuccess(json);
|
|
331
|
-
} else {
|
|
332
|
-
throw new Error('DSGridOrTable: No valid ajax function found');
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
_handleDataSuccess(response) {
|
|
337
|
-
if (response.data) {
|
|
338
|
-
this.data = response.data;
|
|
339
|
-
this.meta = response.meta || {};
|
|
340
|
-
} else if (Array.isArray(response)) {
|
|
341
|
-
this.data = response;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
this.renderer.render();
|
|
345
|
-
|
|
346
|
-
if (this.config.success) this.config.success(response);
|
|
347
|
-
if (this.config.afterSend) this.config.afterSend(response);
|
|
348
|
-
|
|
349
|
-
// Notify modules
|
|
350
|
-
Object.values(this.modules).forEach(m => m.onDataLoaded && m.onDataLoaded(response));
|
|
351
|
-
|
|
352
|
-
this.isLoading = false;
|
|
353
|
-
this._toggleLoading(false);
|
|
354
|
-
this._emit('dataLoaded', response);
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
// ================= LOADING STATE =================
|
|
358
|
-
|
|
359
|
-
_toggleLoading(loading) {
|
|
360
|
-
if (loading) {
|
|
361
|
-
this.wrapper.classList.add('loading-state');
|
|
362
|
-
this.renderer.showSkeleton();
|
|
363
|
-
} else {
|
|
364
|
-
this.wrapper.classList.remove('loading-state');
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
// ================= VIEW SWITCHING =================
|
|
369
|
-
|
|
370
|
-
/**
|
|
371
|
-
* Switch between grid and table views (for gridable mode)
|
|
372
|
-
* @param {string} view - 'grid' or 'table'
|
|
373
|
-
*/
|
|
374
|
-
setView(view) {
|
|
375
|
-
if (this.config.type !== 'gridable') return;
|
|
376
|
-
if (view !== 'grid' && view !== 'table') return;
|
|
377
|
-
if (view === this.currentView) return;
|
|
378
|
-
|
|
379
|
-
this.currentView = view;
|
|
380
|
-
this._setInitialVisibility();
|
|
381
|
-
this.renderer.render();
|
|
382
|
-
|
|
383
|
-
if (this.viewToggle) this.viewToggle.update();
|
|
384
|
-
|
|
385
|
-
this._emit('viewChange', { view });
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
/**
|
|
389
|
-
* Toggle between grid and table views
|
|
390
|
-
*/
|
|
391
|
-
toggleView() {
|
|
392
|
-
const newView = this.currentView === 'grid' ? 'table' : 'grid';
|
|
393
|
-
this.setView(newView);
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
/**
|
|
397
|
-
* Get current view mode
|
|
398
|
-
* @returns {string} 'grid' or 'table'
|
|
399
|
-
*/
|
|
400
|
-
getView() {
|
|
401
|
-
return this.currentView;
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
// ================= PUBLIC API =================
|
|
405
|
-
|
|
406
|
-
refresh() {
|
|
407
|
-
this.params.page = 1;
|
|
408
|
-
this.loadData();
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
setParam(key, value) {
|
|
412
|
-
this.params[key] = value;
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
getParam(key) {
|
|
416
|
-
return this.params[key];
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
registerModule(name, instance) {
|
|
420
|
-
this.modules[name] = instance;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
/**
|
|
424
|
-
* Get the current render target element
|
|
425
|
-
* @returns {HTMLElement}
|
|
426
|
-
*/
|
|
427
|
-
getRenderTarget() {
|
|
428
|
-
if (this.config.type === 'grid') return this.gridContainer;
|
|
429
|
-
if (this.config.type === 'table') return this.tbody;
|
|
430
|
-
return this.currentView === 'grid' ? this.gridContainer : this.tbody;
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
// ================= EVENTS =================
|
|
434
|
-
|
|
435
|
-
on(event, handler) {
|
|
436
|
-
this.wrapper.addEventListener(`dsgot:${event}`, handler);
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
_emit(event, detail = {}) {
|
|
440
|
-
this.wrapper.dispatchEvent(new CustomEvent(`dsgot:${event}`, { bubbles: true, detail }));
|
|
441
|
-
// Also emit dstable events for compatibility with DSTable modules
|
|
442
|
-
this.wrapper.dispatchEvent(new CustomEvent(`dstable:${event}`, { bubbles: true, detail }));
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
// ================= UTILITIES =================
|
|
446
|
-
|
|
447
|
-
_getNestedValue(obj, path) {
|
|
448
|
-
if (!path) return undefined;
|
|
449
|
-
return path.split('.').reduce((o, i) => (o ? o[i] : undefined), obj);
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
export default DSGridOrTable;
|
|
1
|
+
import DSTablePagination from './DSTable/DSTablePagination.js';
|
|
2
|
+
import DSTableSearch from './DSTable/DSTableSearch.js';
|
|
3
|
+
import DSTableSort from './DSTable/DSTableSort.js';
|
|
4
|
+
import DSTableFilter from './DSTable/DSTableFilter.js';
|
|
5
|
+
import DSTableExport from './DSTable/DSTableExport.js';
|
|
6
|
+
import DSTableSelection from './DSTable/DSTableSelection.js';
|
|
7
|
+
import DSGOTRenderer from './DSGridOrTable/DSGOTRenderer.js';
|
|
8
|
+
import DSGOTViewToggle from './DSGridOrTable/DSGOTViewToggle.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @typedef {Object} DSGridOrTableOptions
|
|
12
|
+
* @property {'table'|'grid'|'gridable'} [type] - Display type
|
|
13
|
+
* @property {'grid'|'table'} [defaultView] - For 'gridable' mode: initial view
|
|
14
|
+
* @property {boolean} [showToggle] - Show view toggle buttons
|
|
15
|
+
* @property {boolean} [pagination] - Enable pagination
|
|
16
|
+
* @property {boolean} [search] - Enable search
|
|
17
|
+
* @property {boolean} [sort] - Enable sorting
|
|
18
|
+
* @property {boolean} [filter] - Enable filtering
|
|
19
|
+
* @property {boolean} [export] - Enable export
|
|
20
|
+
* @property {boolean} [selection] - Enable selection
|
|
21
|
+
* @property {'ajax'|'html'|'json'} [table_source] - Data source type
|
|
22
|
+
* @property {string} [ajax_url] - URL for AJAX requests
|
|
23
|
+
* @property {Object} [ajax_data] - Additional data for AJAX requests
|
|
24
|
+
* @property {'GET'|'POST'|'PUT'} [ajax_method] - HTTP method
|
|
25
|
+
* @property {'xhr'|'axios'|'fetch'} [ajax_function] - Fetcher implementation
|
|
26
|
+
* @property {Object} [rowTemplate] - Template config for table rows
|
|
27
|
+
* @property {Object} [gridTemplate] - Template config for grid items
|
|
28
|
+
* @property {Object|number} [gridColumns] - Grid column configuration
|
|
29
|
+
* @property {number} [gridGap] - Tailwind gap value
|
|
30
|
+
* @property {string} [gridContainerClass] - Grid container class
|
|
31
|
+
* @property {string} [tableSelector] - Selector for table element
|
|
32
|
+
* @property {string} [bodySelector] - Selector for tbody element
|
|
33
|
+
* @property {string} [gridSelector] - Selector for grid container
|
|
34
|
+
* @property {string} [toggleSelector] - Selector for view toggle
|
|
35
|
+
* @property {string} [emptyMessage] - Message when no data found
|
|
36
|
+
* @property {string} [errorMessage] - Message on error
|
|
37
|
+
* @property {Function} [success] - Success callback
|
|
38
|
+
* @property {Function} [error] - Error callback
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* DSGridOrTable
|
|
43
|
+
*
|
|
44
|
+
* A flexible data display plugin supporting Table, Grid, or switchable (Gridable) layouts.
|
|
45
|
+
* Built on top of DSTable architecture with extended rendering capabilities.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* // Table mode (like standard DSTable)
|
|
49
|
+
* const table = new DSGridOrTable('#container', {
|
|
50
|
+
* type: 'table',
|
|
51
|
+
* ajax_url: '/api/data',
|
|
52
|
+
* rowTemplate: { source: 'response', response: 'html' }
|
|
53
|
+
* });
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* // Grid mode (card layout)
|
|
57
|
+
* const grid = new DSGridOrTable('#container', {
|
|
58
|
+
* type: 'grid',
|
|
59
|
+
* ajax_url: '/api/data',
|
|
60
|
+
* gridTemplate: { source: 'response', response: 'grid_html' }
|
|
61
|
+
* });
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* // Gridable mode (toggle between table and grid)
|
|
65
|
+
* const gridable = new DSGridOrTable('#container', {
|
|
66
|
+
* type: 'gridable',
|
|
67
|
+
* ajax_url: '/api/data',
|
|
68
|
+
* rowTemplate: { source: 'response', response: 'html' },
|
|
69
|
+
* gridTemplate: { source: 'response', response: 'grid_html' },
|
|
70
|
+
* defaultView: 'grid',
|
|
71
|
+
* showToggle: true
|
|
72
|
+
* });
|
|
73
|
+
*/
|
|
74
|
+
export class DSGridOrTable {
|
|
75
|
+
static defaults = {
|
|
76
|
+
// Display type
|
|
77
|
+
type: 'table', // 'table' | 'grid' | 'gridable'
|
|
78
|
+
defaultView: 'grid', // For 'gridable' mode: 'grid' | 'table'
|
|
79
|
+
showToggle: true, // For 'gridable' mode: show view toggle buttons
|
|
80
|
+
|
|
81
|
+
// Standard features (same as DSTable)
|
|
82
|
+
pagination: true,
|
|
83
|
+
pagination_translations: {
|
|
84
|
+
prev: 'Previous',
|
|
85
|
+
next: 'Next',
|
|
86
|
+
goto: 'Go to',
|
|
87
|
+
stats: 'Showing {from} to {to} of {total} entries'
|
|
88
|
+
},
|
|
89
|
+
search: true,
|
|
90
|
+
sort: true,
|
|
91
|
+
filter: true,
|
|
92
|
+
export: true,
|
|
93
|
+
selection: true,
|
|
94
|
+
|
|
95
|
+
// Data source
|
|
96
|
+
table_source: 'ajax', // 'ajax' | 'html' | 'json'
|
|
97
|
+
ajax_url: null,
|
|
98
|
+
ajax_data: {},
|
|
99
|
+
ajax_method: 'GET',
|
|
100
|
+
ajax_function: 'axios', // 'xhr' | 'axios' | 'fetch'
|
|
101
|
+
|
|
102
|
+
// Callbacks
|
|
103
|
+
success: null,
|
|
104
|
+
error: null,
|
|
105
|
+
beforeSend: null,
|
|
106
|
+
afterSend: null,
|
|
107
|
+
|
|
108
|
+
// Template configurations
|
|
109
|
+
rowTemplate: {
|
|
110
|
+
source: 'response', // 'function' | 'html' | 'response'
|
|
111
|
+
response: 'html', // Property path in response data
|
|
112
|
+
function: null, // Function that returns HTML: (row, index) => '<tr>...</tr>'
|
|
113
|
+
html: null // Template string with {{placeholders}}
|
|
114
|
+
},
|
|
115
|
+
gridTemplate: {
|
|
116
|
+
source: 'response',
|
|
117
|
+
response: 'grid_html',
|
|
118
|
+
function: null,
|
|
119
|
+
html: null
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
// Grid layout options
|
|
123
|
+
gridColumns: {
|
|
124
|
+
default: 2,
|
|
125
|
+
sm: 1,
|
|
126
|
+
md: 2,
|
|
127
|
+
lg: 3,
|
|
128
|
+
xl: 4
|
|
129
|
+
},
|
|
130
|
+
gridGap: 4, // Tailwind gap value (gap-4)
|
|
131
|
+
gridContainerClass: 'ds-grid-container',
|
|
132
|
+
|
|
133
|
+
// Selectors
|
|
134
|
+
tableSelector: 'table',
|
|
135
|
+
bodySelector: 'tbody',
|
|
136
|
+
gridSelector: '.ds-grid-container',
|
|
137
|
+
toggleSelector: '.ds-view-toggle',
|
|
138
|
+
messageSelector: '.ds-table-message',
|
|
139
|
+
search_selector: null,
|
|
140
|
+
|
|
141
|
+
// Empty/Error states
|
|
142
|
+
emptyMessage: 'No data found',
|
|
143
|
+
emptyIcon: 'search_off',
|
|
144
|
+
errorMessage: 'Error loading data',
|
|
145
|
+
|
|
146
|
+
// Filter selectors (passed to DSTableFilter)
|
|
147
|
+
filter_selectors: {}
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* @param {string|HTMLElement} wrapper
|
|
152
|
+
* @param {DSGridOrTableOptions} options
|
|
153
|
+
*/
|
|
154
|
+
constructor(wrapper, options = {}) {
|
|
155
|
+
this.wrapper = typeof wrapper === 'string' ? document.querySelector(wrapper) : wrapper;
|
|
156
|
+
if (!this.wrapper) throw new Error('DSGridOrTable: Wrapper element not found');
|
|
157
|
+
|
|
158
|
+
// Merge configs with special handling for nested objects
|
|
159
|
+
/** @type {DSGridOrTableOptions} */
|
|
160
|
+
this.config = this._mergeDeep({}, DSGridOrTable.defaults, options);
|
|
161
|
+
|
|
162
|
+
// State
|
|
163
|
+
this.data = [];
|
|
164
|
+
this.meta = {};
|
|
165
|
+
this.params = {
|
|
166
|
+
page: 1,
|
|
167
|
+
per_page: 15,
|
|
168
|
+
sort_by: null,
|
|
169
|
+
sort_order: 'asc',
|
|
170
|
+
search: null,
|
|
171
|
+
filters: {}
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
this.modules = {};
|
|
175
|
+
this.isLoading = false;
|
|
176
|
+
this.currentView = this.config.defaultView;
|
|
177
|
+
|
|
178
|
+
this._init();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
_mergeDeep(target, ...sources) {
|
|
182
|
+
if (!sources.length) return target;
|
|
183
|
+
const source = sources.shift();
|
|
184
|
+
|
|
185
|
+
if (this._isObject(target) && this._isObject(source)) {
|
|
186
|
+
for (const key in source) {
|
|
187
|
+
if (this._isObject(source[key])) {
|
|
188
|
+
if (!target[key]) Object.assign(target, { [key]: {} });
|
|
189
|
+
this._mergeDeep(target[key], source[key]);
|
|
190
|
+
} else {
|
|
191
|
+
Object.assign(target, { [key]: source[key] });
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return this._mergeDeep(target, ...sources);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
_isObject(item) {
|
|
199
|
+
return item && typeof item === 'object' && !Array.isArray(item);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
_init() {
|
|
203
|
+
// Find elements based on type
|
|
204
|
+
this.table = this.wrapper.querySelector(this.config.tableSelector);
|
|
205
|
+
this.tbody = this.wrapper.querySelector(this.config.bodySelector) || this.table?.querySelector('tbody');
|
|
206
|
+
this.gridContainer = this.wrapper.querySelector(this.config.gridSelector);
|
|
207
|
+
|
|
208
|
+
// Create grid container if needed and not exists
|
|
209
|
+
if ((this.config.type === 'grid' || this.config.type === 'gridable') && !this.gridContainer) {
|
|
210
|
+
this.gridContainer = document.createElement('div');
|
|
211
|
+
this.gridContainer.className = this._buildGridClasses();
|
|
212
|
+
if (this.table) {
|
|
213
|
+
this.table.parentNode.insertBefore(this.gridContainer, this.table.nextSibling);
|
|
214
|
+
} else {
|
|
215
|
+
this.wrapper.insertBefore(this.gridContainer, this.wrapper.firstChild);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Initialize the renderer module
|
|
220
|
+
this.renderer = new DSGOTRenderer(this);
|
|
221
|
+
|
|
222
|
+
// Initialize view toggle for gridable mode
|
|
223
|
+
if (this.config.type === 'gridable' && this.config.showToggle) {
|
|
224
|
+
this.viewToggle = new DSGOTViewToggle(this);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Initialize standard modules (reuse DSTable modules)
|
|
228
|
+
if (this.config.pagination) this.modules.pagination = new DSTablePagination(this);
|
|
229
|
+
if (this.config.search) this.modules.search = new DSTableSearch(this);
|
|
230
|
+
if (this.config.sort && this.table) this.modules.sort = new DSTableSort(this);
|
|
231
|
+
if (this.config.filter) this.modules.filter = new DSTableFilter(this);
|
|
232
|
+
if (this.config.export) this.modules.export = new DSTableExport(this);
|
|
233
|
+
if (this.config.selection && this.table) this.modules.selection = new DSTableSelection(this);
|
|
234
|
+
|
|
235
|
+
// Set initial visibility based on type
|
|
236
|
+
this._setInitialVisibility();
|
|
237
|
+
|
|
238
|
+
// Initial data load
|
|
239
|
+
this.loadData();
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
_buildGridClasses() {
|
|
243
|
+
const { gridColumns, gridGap, gridContainerClass } = this.config;
|
|
244
|
+
let classes = `${gridContainerClass} grid gap-${gridGap}`;
|
|
245
|
+
|
|
246
|
+
// Build responsive column classes
|
|
247
|
+
if (typeof gridColumns === 'number') {
|
|
248
|
+
classes += ` grid-cols-${gridColumns}`;
|
|
249
|
+
} else if (typeof gridColumns === 'object') {
|
|
250
|
+
classes += ` grid-cols-${gridColumns.default || 1}`;
|
|
251
|
+
if (gridColumns.sm) classes += ` sm:grid-cols-${gridColumns.sm}`;
|
|
252
|
+
if (gridColumns.md) classes += ` md:grid-cols-${gridColumns.md}`;
|
|
253
|
+
if (gridColumns.lg) classes += ` lg:grid-cols-${gridColumns.lg}`;
|
|
254
|
+
if (gridColumns.xl) classes += ` xl:grid-cols-${gridColumns.xl}`;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return classes;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
_setInitialVisibility() {
|
|
261
|
+
if (this.config.type === 'table') {
|
|
262
|
+
if (this.gridContainer) this.gridContainer.classList.add('hidden');
|
|
263
|
+
if (this.table) this.table.classList.remove('hidden');
|
|
264
|
+
} else if (this.config.type === 'grid') {
|
|
265
|
+
if (this.table) this.table.classList.add('hidden');
|
|
266
|
+
if (this.gridContainer) this.gridContainer.classList.remove('hidden');
|
|
267
|
+
} else { // gridable
|
|
268
|
+
if (this.currentView === 'grid') {
|
|
269
|
+
if (this.table) this.table.classList.add('hidden');
|
|
270
|
+
if (this.gridContainer) this.gridContainer.classList.remove('hidden');
|
|
271
|
+
} else {
|
|
272
|
+
if (this.gridContainer) this.gridContainer.classList.add('hidden');
|
|
273
|
+
if (this.table) this.table.classList.remove('hidden');
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// ================= DATA LOADING =================
|
|
279
|
+
|
|
280
|
+
async loadData() {
|
|
281
|
+
if (this.isLoading) return;
|
|
282
|
+
this.isLoading = true;
|
|
283
|
+
this._toggleLoading(true);
|
|
284
|
+
|
|
285
|
+
if (this.config.beforeSend) this.config.beforeSend({ params: this.params });
|
|
286
|
+
|
|
287
|
+
try {
|
|
288
|
+
if (this.config.table_source === 'ajax') {
|
|
289
|
+
await this._loadFromAjax();
|
|
290
|
+
} else if (this.config.table_source === 'json') {
|
|
291
|
+
this._handleDataSuccess(this.config.data || []);
|
|
292
|
+
} else if (this.config.table_source === 'html') {
|
|
293
|
+
this.isLoading = false;
|
|
294
|
+
this._toggleLoading(false);
|
|
295
|
+
}
|
|
296
|
+
} catch (error) {
|
|
297
|
+
console.error('DSGridOrTable: Error loading data', error);
|
|
298
|
+
if (this.config.error) this.config.error(error);
|
|
299
|
+
this.renderer.showError(this.config.errorMessage);
|
|
300
|
+
this.isLoading = false;
|
|
301
|
+
this._toggleLoading(false);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
async _loadFromAjax() {
|
|
306
|
+
const url = this.config.ajax_url;
|
|
307
|
+
const method = this.config.ajax_method;
|
|
308
|
+
const data = { ...this.config.ajax_data, ...this.params };
|
|
309
|
+
|
|
310
|
+
let response;
|
|
311
|
+
|
|
312
|
+
if (this.config.ajax_function === 'axios' && window.axios) {
|
|
313
|
+
response = await window.axios({
|
|
314
|
+
method,
|
|
315
|
+
url,
|
|
316
|
+
params: method === 'GET' ? data : undefined,
|
|
317
|
+
data: method !== 'GET' ? data : undefined
|
|
318
|
+
});
|
|
319
|
+
this._handleDataSuccess(response.data);
|
|
320
|
+
} else if (this.config.ajax_function === 'fetch' || window.fetch) {
|
|
321
|
+
const queryString = new URLSearchParams(data).toString();
|
|
322
|
+
const fetchUrl = method === 'GET' ? `${url}?${queryString}` : url;
|
|
323
|
+
const options = {
|
|
324
|
+
method,
|
|
325
|
+
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
|
|
326
|
+
body: method !== 'GET' ? JSON.stringify(data) : undefined
|
|
327
|
+
};
|
|
328
|
+
const res = await fetch(fetchUrl, options);
|
|
329
|
+
const json = await res.json();
|
|
330
|
+
this._handleDataSuccess(json);
|
|
331
|
+
} else {
|
|
332
|
+
throw new Error('DSGridOrTable: No valid ajax function found');
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
_handleDataSuccess(response) {
|
|
337
|
+
if (response.data) {
|
|
338
|
+
this.data = response.data;
|
|
339
|
+
this.meta = response.meta || {};
|
|
340
|
+
} else if (Array.isArray(response)) {
|
|
341
|
+
this.data = response;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
this.renderer.render();
|
|
345
|
+
|
|
346
|
+
if (this.config.success) this.config.success(response);
|
|
347
|
+
if (this.config.afterSend) this.config.afterSend(response);
|
|
348
|
+
|
|
349
|
+
// Notify modules
|
|
350
|
+
Object.values(this.modules).forEach(m => m.onDataLoaded && m.onDataLoaded(response));
|
|
351
|
+
|
|
352
|
+
this.isLoading = false;
|
|
353
|
+
this._toggleLoading(false);
|
|
354
|
+
this._emit('dataLoaded', response);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// ================= LOADING STATE =================
|
|
358
|
+
|
|
359
|
+
_toggleLoading(loading) {
|
|
360
|
+
if (loading) {
|
|
361
|
+
this.wrapper.classList.add('loading-state');
|
|
362
|
+
this.renderer.showSkeleton();
|
|
363
|
+
} else {
|
|
364
|
+
this.wrapper.classList.remove('loading-state');
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// ================= VIEW SWITCHING =================
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Switch between grid and table views (for gridable mode)
|
|
372
|
+
* @param {string} view - 'grid' or 'table'
|
|
373
|
+
*/
|
|
374
|
+
setView(view) {
|
|
375
|
+
if (this.config.type !== 'gridable') return;
|
|
376
|
+
if (view !== 'grid' && view !== 'table') return;
|
|
377
|
+
if (view === this.currentView) return;
|
|
378
|
+
|
|
379
|
+
this.currentView = view;
|
|
380
|
+
this._setInitialVisibility();
|
|
381
|
+
this.renderer.render();
|
|
382
|
+
|
|
383
|
+
if (this.viewToggle) this.viewToggle.update();
|
|
384
|
+
|
|
385
|
+
this._emit('viewChange', { view });
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Toggle between grid and table views
|
|
390
|
+
*/
|
|
391
|
+
toggleView() {
|
|
392
|
+
const newView = this.currentView === 'grid' ? 'table' : 'grid';
|
|
393
|
+
this.setView(newView);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Get current view mode
|
|
398
|
+
* @returns {string} 'grid' or 'table'
|
|
399
|
+
*/
|
|
400
|
+
getView() {
|
|
401
|
+
return this.currentView;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// ================= PUBLIC API =================
|
|
405
|
+
|
|
406
|
+
refresh() {
|
|
407
|
+
this.params.page = 1;
|
|
408
|
+
this.loadData();
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
setParam(key, value) {
|
|
412
|
+
this.params[key] = value;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
getParam(key) {
|
|
416
|
+
return this.params[key];
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
registerModule(name, instance) {
|
|
420
|
+
this.modules[name] = instance;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Get the current render target element
|
|
425
|
+
* @returns {HTMLElement}
|
|
426
|
+
*/
|
|
427
|
+
getRenderTarget() {
|
|
428
|
+
if (this.config.type === 'grid') return this.gridContainer;
|
|
429
|
+
if (this.config.type === 'table') return this.tbody;
|
|
430
|
+
return this.currentView === 'grid' ? this.gridContainer : this.tbody;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// ================= EVENTS =================
|
|
434
|
+
|
|
435
|
+
on(event, handler) {
|
|
436
|
+
this.wrapper.addEventListener(`dsgot:${event}`, handler);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
_emit(event, detail = {}) {
|
|
440
|
+
this.wrapper.dispatchEvent(new CustomEvent(`dsgot:${event}`, { bubbles: true, detail }));
|
|
441
|
+
// Also emit dstable events for compatibility with DSTable modules
|
|
442
|
+
this.wrapper.dispatchEvent(new CustomEvent(`dstable:${event}`, { bubbles: true, detail }));
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// ================= UTILITIES =================
|
|
446
|
+
|
|
447
|
+
_getNestedValue(obj, path) {
|
|
448
|
+
if (!path) return undefined;
|
|
449
|
+
return path.split('.').reduce((o, i) => (o ? o[i] : undefined), obj);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
export default DSGridOrTable;
|