@massimo-cassandro/minimo 0.10.10 → 0.11.0
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/design-tokens/components/snackbar.minimo.tokens.jsonc +106 -12
- package/design-tokens/shadows.minimo.tokens.jsonc +19 -0
- package/design-tokens/z-index.minimo.tokens.jsonc +4 -0
- package/design-tokens-src/_readme.md +1 -1
- package/design-tokens-src/badge.minimo.tokens.mjs +36 -0
- package/design-tokens-src/btn-close.minimo.tokens.mjs +101 -0
- package/design-tokens-src/components/snackbar.minimo.tokens.mjs +113 -21
- package/design-tokens-src/flex-grid.minimo.tokens.mjs +18 -0
- package/design-tokens-src/shadows.minimo.tokens.mjs +16 -0
- package/design-tokens-src/z-index.minimo.tokens.mjs +14 -0
- package/design-tokens-utilities/build-tokens-src/transforms.mjs +2 -1
- package/package.json +3 -3
- package/src/components/snackbar/snackbar.js +57 -63
- package/src/components/snackbar/snackbar.module.css +80 -45
- package/src/css/buttons/btn-close.css +3 -2
- package/src/css/forms/forms.css +1 -0
- package/src/custom-properties.css +22 -4
- package/src/minimo.css +3 -3
- package/src/web-components/s-datatable-component/docs.md +187 -0
- package/src/web-components/s-datatable-component/s-datatable-component.js +517 -0
- package/src/web-components/{simple-datatable/simple-datatable.module.css → s-datatable-component/s-datatable-component.module.css} +1 -1
- package/src/web-components/{simple-datatable → s-datatable-component}/src/parse-cols.js +1 -1
- package/design-tokens-src/badge.minimo.tokens.jsonc +0 -36
- package/design-tokens-src/btn-close.minimo.tokens.jsonc +0 -101
- package/design-tokens-src/flex-grid.minimo.tokens.jsonc +0 -18
- package/design-tokens-src/gradients-shadowes.minimo.tokens.jsonc +0 -4
- package/design-tokens-src/z-index.minimo.tokens.jsonc +0 -8
- package/src/web-components/simple-datatable/simple-datatable.js +0 -218
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
import { DataTable } from 'simple-datatables';
|
|
2
|
+
|
|
3
|
+
import { parseCols } from './src/parse-cols.js';
|
|
4
|
+
|
|
5
|
+
import * as styles from './s-datatable-component.module.css';
|
|
6
|
+
|
|
7
|
+
import caretLeftIcon from '../../icons/caret-left.svg?inline';
|
|
8
|
+
import caretRightIcon from '../../icons/caret-right.svg?inline';
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Impementazione di simple-datatable (https://fiduswriter.github.io/simple-datatables/documentation/)
|
|
13
|
+
* per generare una tabella da dati json e da un oggetto `cols` di configurazione
|
|
14
|
+
*
|
|
15
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
16
|
+
* PARAMETRI
|
|
17
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
18
|
+
* Tutti i parametri sono leggibili sia da attributo HTML che da script (init).
|
|
19
|
+
* Ordine di precedenza: script > attributo HTML > default interno.
|
|
20
|
+
*
|
|
21
|
+
* @typedef {object} ColDefinition
|
|
22
|
+
* @property {string} _heading Intestazione della colonna (obbligatorio).
|
|
23
|
+
* @property {string} _field Chiave del campo nell'oggetto dato (obbligatorio).
|
|
24
|
+
* @property {string} [_title] Testo del tooltip sull'intestazione.
|
|
25
|
+
* @property {string} [_renderTpl] Template HTML per il contenuto della cella.
|
|
26
|
+
* I segnaposto `[[key]]` vengono sostituiti con i
|
|
27
|
+
* valori corrispondenti dell'oggetto riga.
|
|
28
|
+
* @property {'id'|'email'|'boolean'|'sf_datetime'} [_renderMode]
|
|
29
|
+
* Modalità di visualizzazione predefinita:
|
|
30
|
+
* - `id` – colonna numerica, non ricercabile, allineata a destra
|
|
31
|
+
* - `email` – inserisce andate a capo prima e dopo la `@`
|
|
32
|
+
* - `boolean` – icona segno di spunta / croce con colore semantico
|
|
33
|
+
* - `sf_datetime` – data e ora da oggetto Symfony (con pre-elaborazione in `_load`)
|
|
34
|
+
*
|
|
35
|
+
* @param {string} json URL da cui recuperare i dati (struttura attesa: `{ data: [...] }`).
|
|
36
|
+
* Ignorato se `data` è presente.
|
|
37
|
+
* Eventuali altre chiavi aggiuntive (oltre a `data`) vengono ignorate
|
|
38
|
+
*
|
|
39
|
+
* @param {Array<object>} data Dati inline, come array di oggetti plain.
|
|
40
|
+
* Ha precedenza su `json` se entrambi sono specificati.
|
|
41
|
+
* Come attributo HTML è utile principalmente in contesti SSR
|
|
42
|
+
* (Twig, Blade, ecc.) dove il JSON viene serializzato server-side;
|
|
43
|
+
* per grandi dataset è preferibile `json`.
|
|
44
|
+
*
|
|
45
|
+
* @param {ColDefinition[]} cols Definizione delle colonne. Le chiavi con prefisso `_` sono
|
|
46
|
+
* proprietà di questo componente; le restanti vengono passate
|
|
47
|
+
* direttamente a simple-datatables (es. `sortable`, `searchable`).
|
|
48
|
+
* Default: `[]`
|
|
49
|
+
*
|
|
50
|
+
* @param {number} perPage Numero di righe per pagina.
|
|
51
|
+
* Default: `25`
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* getNestedValue
|
|
58
|
+
*
|
|
59
|
+
* Legge un valore da un oggetto tramite un percorso di chiavi separate da punto.
|
|
60
|
+
* Supporta sia chiavi semplici ('commessa') che composte ('owner.nome').
|
|
61
|
+
* Restituisce undefined se una chiave intermedia non esiste.
|
|
62
|
+
*
|
|
63
|
+
* Esempi:
|
|
64
|
+
* getNestedValue(row, 'commessa') → row.commessa
|
|
65
|
+
* getNestedValue(row, 'owner.nome') → row.owner.nome
|
|
66
|
+
* getNestedValue(row, 'ciclo.ciclo') → row.ciclo.ciclo
|
|
67
|
+
*/
|
|
68
|
+
function getNestedValue(obj, path) {
|
|
69
|
+
return path.split('.').reduce((acc, key) => acc?.[key], obj);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class SimpleDatatableAdapter extends HTMLElement {
|
|
75
|
+
constructor() {
|
|
76
|
+
super();
|
|
77
|
+
// this.attachShadow({ mode: 'open' }); // commentare per light dom
|
|
78
|
+
|
|
79
|
+
this._config = null;
|
|
80
|
+
this._initCalledProgrammatically = false;
|
|
81
|
+
this._isConnected = false;
|
|
82
|
+
this._loadStarted = false;
|
|
83
|
+
|
|
84
|
+
/** Riferimento all'istanza DataTable di simple-datatables */
|
|
85
|
+
this._dt = null;
|
|
86
|
+
|
|
87
|
+
/** Filtro da applicare dopo il prossimo reload (vedi reload()) */
|
|
88
|
+
this._pendingSearch = null;
|
|
89
|
+
this._loadGeneration = 0;
|
|
90
|
+
|
|
91
|
+
// Handler bound per poterli rimuovere in disconnectedCallback
|
|
92
|
+
this._onSearch = this._handleSearch.bind(this);
|
|
93
|
+
this._onMultiSearch = this._handleMultiSearch.bind(this);
|
|
94
|
+
this._onReload = this._handleReload.bind(this);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
// ─── Lifecycle ──────────────────────────────────────────────────────────────
|
|
99
|
+
|
|
100
|
+
async connectedCallback() {
|
|
101
|
+
this._isConnected = true;
|
|
102
|
+
|
|
103
|
+
// Registra i listener sugli eventi globali
|
|
104
|
+
document.addEventListener('datatable:search', this._onSearch);
|
|
105
|
+
document.addEventListener('datatable:multisearch', this._onMultiSearch);
|
|
106
|
+
document.addEventListener('datatable:reload', this._onReload);
|
|
107
|
+
|
|
108
|
+
if (this._initCalledProgrammatically) {
|
|
109
|
+
if (!this._loadStarted) this._load();
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
this._load();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
disconnectedCallback() {
|
|
117
|
+
document.removeEventListener('datatable:search', this._onSearch);
|
|
118
|
+
document.removeEventListener('datatable:multisearch', this._onMultiSearch);
|
|
119
|
+
document.removeEventListener('datatable:reload', this._onReload);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
// ─── API pubblica ────────────────────────────────────────────────────────────
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Avvia il componente via script, passando la configurazione come oggetto.
|
|
127
|
+
* Può essere chiamato sia prima che dopo l'inserimento nel DOM.
|
|
128
|
+
*
|
|
129
|
+
* I parametri non inclusi in `config` vengono letti dall'attributo HTML
|
|
130
|
+
* corrispondente, se presente — consentendo un mix dei due approcci:
|
|
131
|
+
*
|
|
132
|
+
* <s-datatable
|
|
133
|
+
* cols='[{"_heading":"Nome","_field":"name"}]'
|
|
134
|
+
* ></s-datatable>
|
|
135
|
+
*
|
|
136
|
+
* el.init({ json: '/api/data.json', perPage: 20 });
|
|
137
|
+
* // → json e perPage da script, cols dall'attributo
|
|
138
|
+
*
|
|
139
|
+
* Per ignorare esplicitamente un attributo esistente e forzare il default
|
|
140
|
+
* interno, passare il valore `null` nel config:
|
|
141
|
+
*
|
|
142
|
+
* el.init({ json: '/api/data.json', cols: null });
|
|
143
|
+
* // → cols = null (l'attributo viene ignorato)
|
|
144
|
+
*/
|
|
145
|
+
init(config = {}) {
|
|
146
|
+
this._config = config;
|
|
147
|
+
this._initCalledProgrammatically = true;
|
|
148
|
+
|
|
149
|
+
// Azzera il flag di caricamento: init() chiamato esplicitamente deve
|
|
150
|
+
// sempre ripartire, anche se connectedCallback aveva già tentato un
|
|
151
|
+
// _load() prematuro (es. quando domBuilder appende l'elemento al DOM
|
|
152
|
+
// prima che la configurazione sia disponibile).
|
|
153
|
+
this._loadStarted = false;
|
|
154
|
+
this._loadGeneration++;
|
|
155
|
+
|
|
156
|
+
if (this._isConnected) {
|
|
157
|
+
this._load();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Ricerca testuale su una o più colonne.
|
|
163
|
+
* @param {string} term
|
|
164
|
+
* @param {number[]} [columns] indici di colonna; se omesso cerca su tutto
|
|
165
|
+
*/
|
|
166
|
+
search(term, columns) {
|
|
167
|
+
if (!this._dt) return;
|
|
168
|
+
this._dt.search(term, columns);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Ricerca multi-colonna con query indipendenti.
|
|
173
|
+
* @param {Array<{ terms: string[], columns?: number[] }>} queries
|
|
174
|
+
*/
|
|
175
|
+
multiSearch(queries) {
|
|
176
|
+
if (!this._dt) return;
|
|
177
|
+
this._dt.multiSearch(queries);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Ricarica i dati (eventualmente da un nuovo URL e/o con nuove colonne),
|
|
182
|
+
* con possibilità di applicare un filtro contestuale al termine del fetch.
|
|
183
|
+
*
|
|
184
|
+
* @param {object} [overrides]
|
|
185
|
+
* @param {string} [overrides.json] Nuovo URL dati (ignorato se `data` è presente)
|
|
186
|
+
* @param {Array} [overrides.data] Dati inline (array di oggetti); ha precedenza su `json`
|
|
187
|
+
* @param {Array} [overrides.cols] Nuove colonne
|
|
188
|
+
* @param {object} [overrides.search] Filtro da applicare dopo il caricamento.
|
|
189
|
+
* Formati supportati:
|
|
190
|
+
* - { term, columns? } → ricerca semplice (search)
|
|
191
|
+
* - { queries: [{terms, columns?}, …] } → ricerca multipla (multiSearch)
|
|
192
|
+
* I due si escludono: se presente `queries` → multiSearch, altrimenti search.
|
|
193
|
+
*/
|
|
194
|
+
async reload(overrides = {}) {
|
|
195
|
+
if (overrides.json) this._setParam('json', overrides.json);
|
|
196
|
+
if (overrides.data !== undefined) this._setParam('data', overrides.data);
|
|
197
|
+
if (overrides.cols) this._setParam('cols', overrides.cols);
|
|
198
|
+
|
|
199
|
+
// Memorizza il filtro pendente: verrà applicato dentro datatable.init,
|
|
200
|
+
// dopo che simple-datatables ha terminato di renderizzare i nuovi dati.
|
|
201
|
+
this._pendingSearch = overrides.search ?? null;
|
|
202
|
+
|
|
203
|
+
this._loadStarted = false;
|
|
204
|
+
this._loadGeneration++;
|
|
205
|
+
await this._load();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
// ─── Helpers interni ─────────────────────────────────────────────────────────
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Risolve il valore di un parametro fondendo le tre sorgenti possibili.
|
|
213
|
+
*
|
|
214
|
+
* Ordine di precedenza (dal più al meno prioritario):
|
|
215
|
+
* 1. _config – valore passato via init() o _setParam().
|
|
216
|
+
* Se presente e !== undefined sovrascrive sempre l'attributo.
|
|
217
|
+
* Passare esplicitamente `null` per ignorare l'attributo e
|
|
218
|
+
* ricevere il defaultValue.
|
|
219
|
+
* 2. Attributo HTML – se il valore inizia con [ o { viene auto-parsato
|
|
220
|
+
* da JSON (utile per cols, che può stare nell'attributo).
|
|
221
|
+
* 3. defaultValue – fallback finale.
|
|
222
|
+
*
|
|
223
|
+
* Esempi con config = { json: '/api/x.json' } e attr cols='[…]':
|
|
224
|
+
* _getParam('json') → '/api/x.json' (da config)
|
|
225
|
+
* _getParam('cols') → [… parsed …] (da attributo, auto-JSON)
|
|
226
|
+
* _getParam('perPage', 25)→ 25 (default)
|
|
227
|
+
*
|
|
228
|
+
* Per ignorare esplicitamente un attributo, passare null nel config:
|
|
229
|
+
* init({ cols: null }) → _getParam('cols') restituisce null,
|
|
230
|
+
* l'attributo viene saltato.
|
|
231
|
+
*/
|
|
232
|
+
_getParam(name, defaultValue = null) {
|
|
233
|
+
// 1. Config da script (undefined = chiave assente → scendi di livello)
|
|
234
|
+
if (this._config && this._config[name] !== undefined) {
|
|
235
|
+
return this._config[name];
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// 2. Attributo HTML
|
|
239
|
+
const attr = this.getAttribute(name);
|
|
240
|
+
if (attr !== null) {
|
|
241
|
+
// Auto-parse JSON per array e oggetti (es. cols='[…]')
|
|
242
|
+
const trimmed = attr.trim();
|
|
243
|
+
if (trimmed.startsWith('[') || trimmed.startsWith('{')) {
|
|
244
|
+
try { return JSON.parse(trimmed); } catch { /* restituisce la stringa grezza */ }
|
|
245
|
+
}
|
|
246
|
+
return attr;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// 3. Default interno
|
|
250
|
+
return defaultValue;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
_setParam(name, value) {
|
|
254
|
+
if (!this._config) this._config = {};
|
|
255
|
+
this._config[name] = value;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Ritorna true se questo elemento è il target dell'evento.
|
|
260
|
+
* Se detail.target è assente, risponde sempre;
|
|
261
|
+
* altrimenti solo se corrisponde all'id dell'elemento.
|
|
262
|
+
*/
|
|
263
|
+
_isTarget(detail) {
|
|
264
|
+
return !detail.target || detail.target === this.id;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
// ─── Handler eventi globali ──────────────────────────────────────────────────
|
|
269
|
+
|
|
270
|
+
_handleSearch(e) {
|
|
271
|
+
if (!this._isTarget(e.detail)) return;
|
|
272
|
+
const { term = '', columns } = e.detail;
|
|
273
|
+
this.search(term, columns);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
_handleMultiSearch(e) {
|
|
277
|
+
if (!this._isTarget(e.detail)) return;
|
|
278
|
+
const { queries = [] } = e.detail;
|
|
279
|
+
this.multiSearch(queries);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
_handleReload(e) {
|
|
283
|
+
if (!this._isTarget(e.detail)) return;
|
|
284
|
+
// Propaga `data` solo se esplicitamente presente nel detail
|
|
285
|
+
const overrides = { ...e.detail };
|
|
286
|
+
this.reload(overrides);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
// ─── Caricamento dati ────────────────────────────────────────────────────────
|
|
291
|
+
|
|
292
|
+
async _load() {
|
|
293
|
+
if (this._loadStarted) return;
|
|
294
|
+
this._loadStarted = true;
|
|
295
|
+
const generation = this._loadGeneration;
|
|
296
|
+
|
|
297
|
+
this.innerHTML = '<div class="spinner"><span class="visually-hidden">Caricamento dati...</span></div>';
|
|
298
|
+
|
|
299
|
+
const inlineData = this._getParam('data');
|
|
300
|
+
const jsonUrl = this._getParam('json');
|
|
301
|
+
const cols = this._getParam('cols', []);
|
|
302
|
+
|
|
303
|
+
if (inlineData == null && !jsonUrl) {
|
|
304
|
+
if (this._initCalledProgrammatically) {
|
|
305
|
+
// eslint-disable-next-line no-console
|
|
306
|
+
console.error('[s-datatable] Nessuna sorgente dati: specificare `data` o `json`.');
|
|
307
|
+
}
|
|
308
|
+
this.innerHTML = '';
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
try {
|
|
313
|
+
// Risolvi i dati grezzi: inline `data` ha precedenza su `json`
|
|
314
|
+
let rawData;
|
|
315
|
+
if (inlineData != null) {
|
|
316
|
+
rawData = Array.isArray(inlineData) ? inlineData : [];
|
|
317
|
+
} else {
|
|
318
|
+
const response = await fetch(jsonUrl);
|
|
319
|
+
const parsed = await response.json();
|
|
320
|
+
rawData = parsed.data;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
this.headings = cols.map(item =>
|
|
324
|
+
item._title
|
|
325
|
+
? `<abbr title="${item._title}">${item._heading}</abbr>`
|
|
326
|
+
: item._heading
|
|
327
|
+
);
|
|
328
|
+
|
|
329
|
+
this.data = rawData.map((row, idx) => ({
|
|
330
|
+
attributes: { 'data-jidx': idx },
|
|
331
|
+
|
|
332
|
+
cells: cols.map((col_item, col_idx) => {
|
|
333
|
+
let value = getNestedValue(row, col_item._field);
|
|
334
|
+
|
|
335
|
+
if (col_item._renderTpl) {
|
|
336
|
+
value = decodeURIComponent(col_item._renderTpl).replace(
|
|
337
|
+
/\[\[(.*?)\]\]/g,
|
|
338
|
+
(match, key) => {
|
|
339
|
+
const resolved = getNestedValue(row, key);
|
|
340
|
+
const pathParts = key.split('.');
|
|
341
|
+
const parentObj = pathParts.length > 1
|
|
342
|
+
? getNestedValue(row, pathParts.slice(0, -1).join('.'))
|
|
343
|
+
: row;
|
|
344
|
+
|
|
345
|
+
// Segnala solo se il padre esiste ma la chiave foglia manca
|
|
346
|
+
// (errore di configurazione). Se il padre è null il dato è
|
|
347
|
+
// semplicemente assente (es. Symfony restituisce owner: null).
|
|
348
|
+
if (parentObj != null && !Object.prototype.hasOwnProperty.call(parentObj, pathParts.at(-1))) {
|
|
349
|
+
// eslint-disable-next-line no-console
|
|
350
|
+
console.error(`[s-datatable] Chiave "${key}" non trovata nella struttura dati (colonna ${col_idx})`);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
return resolved ?? '';
|
|
354
|
+
}
|
|
355
|
+
);
|
|
356
|
+
} else if (col_item._renderMode === 'sf_datetime' && value != null) {
|
|
357
|
+
value = value.date.replace(' ', 'T') +
|
|
358
|
+
(value.timezone === 'UTC' ? 'Z' : '');
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
return value;
|
|
362
|
+
})
|
|
363
|
+
}));
|
|
364
|
+
|
|
365
|
+
this.columns = cols.map((col_settings, idx) => {
|
|
366
|
+
col_settings = parseCols(col_settings);
|
|
367
|
+
|
|
368
|
+
return {
|
|
369
|
+
...(Object.fromEntries(
|
|
370
|
+
Object.entries(col_settings).filter(([key]) => !key.startsWith('_'))
|
|
371
|
+
)),
|
|
372
|
+
select: idx,
|
|
373
|
+
type: col_settings.type ?? 'string',
|
|
374
|
+
searchable: col_settings.searchable ?? true,
|
|
375
|
+
sortable: col_settings.sortable ?? true,
|
|
376
|
+
};
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
} catch (err) {
|
|
380
|
+
/* eslint-disable no-console */
|
|
381
|
+
if (jsonUrl) console.error(jsonUrl);
|
|
382
|
+
console.error(err);
|
|
383
|
+
/* eslint-enable no-console */
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if (generation !== this._loadGeneration) return;
|
|
387
|
+
this._render();
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
// ─── Render ──────────────────────────────────────────────────────────────────
|
|
392
|
+
|
|
393
|
+
_render() {
|
|
394
|
+
// Distrugge l'istanza precedente prima di ricrearla (es. dopo reload)
|
|
395
|
+
if (this._dt) {
|
|
396
|
+
this._dt.destroy();
|
|
397
|
+
this._dt = null;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
this.innerHTML = '';
|
|
401
|
+
const table = document.createElement('table');
|
|
402
|
+
this.appendChild(table);
|
|
403
|
+
|
|
404
|
+
const perPage = +this._getParam('perPage', 25);
|
|
405
|
+
|
|
406
|
+
this._dt = new DataTable(table, {
|
|
407
|
+
locale: 'it',
|
|
408
|
+
searchable: true,
|
|
409
|
+
sortable: true,
|
|
410
|
+
fixedHeight: false,
|
|
411
|
+
fixedColumns: false,
|
|
412
|
+
paging: true,
|
|
413
|
+
perPage,
|
|
414
|
+
pagerDelta: 2,
|
|
415
|
+
perPageSelect: false,
|
|
416
|
+
|
|
417
|
+
labels: {
|
|
418
|
+
placeholder: 'Cerca...',
|
|
419
|
+
searchTitle: 'Cerca nella tabella',
|
|
420
|
+
pageTitle: 'Pagina {page}',
|
|
421
|
+
perPage: 'Righe per pagina',
|
|
422
|
+
noRows: 'Nessun record trovato',
|
|
423
|
+
info: 'Stai visualizzando le righe da {start} a {end}, su un totale di {rows}',
|
|
424
|
+
noResults: 'Nessun risultato per la ricerca',
|
|
425
|
+
},
|
|
426
|
+
|
|
427
|
+
classes: {
|
|
428
|
+
wrapper : styles.datatableWrapper,
|
|
429
|
+
container : 'table-responsive',
|
|
430
|
+
loading : 'datatable-loading', // ??
|
|
431
|
+
|
|
432
|
+
// barra superiore
|
|
433
|
+
top : styles.topArea,
|
|
434
|
+
search : styles.searchWrapper,
|
|
435
|
+
input : 'form-control form-control-sm',
|
|
436
|
+
// dropdown : 'datatable-dropdown', // selettore righe per pagina, disattivato
|
|
437
|
+
|
|
438
|
+
empty : styles.empty,
|
|
439
|
+
|
|
440
|
+
// table
|
|
441
|
+
table : `table table-bordered ${styles.table}`,
|
|
442
|
+
// buttons in thead per il sort
|
|
443
|
+
sorter : `btn-reset ${styles.sortBtn}`,
|
|
444
|
+
ascending : styles.sortAscending,
|
|
445
|
+
descending : styles.sortDescending,
|
|
446
|
+
|
|
447
|
+
// area inferiore
|
|
448
|
+
bottom : styles.bottomArea,
|
|
449
|
+
// info text
|
|
450
|
+
info : styles.info,
|
|
451
|
+
|
|
452
|
+
// pagination
|
|
453
|
+
// pagination : styles.paginationNav,
|
|
454
|
+
paginationList : styles.paginationList,
|
|
455
|
+
paginationListItem : styles.paginationListItem,
|
|
456
|
+
paginationListItemLink : styles.paginationListItemBtn,
|
|
457
|
+
// hidden : 'datatable-hidden',
|
|
458
|
+
disabled : styles.paginationDisabled,
|
|
459
|
+
active : styles.paginationActive,
|
|
460
|
+
|
|
461
|
+
// cursor: 'datatable-cursor',
|
|
462
|
+
// dropdown: 'datatable-dropdown',
|
|
463
|
+
// ellipsis: 'datatable-ellipsis',
|
|
464
|
+
// filter: 'datatable-filter',
|
|
465
|
+
// filterActive: 'datatable-filter-active',
|
|
466
|
+
// headercontainer: 'datatable-headercontainer',
|
|
467
|
+
// selector: 'datatable-selector',
|
|
468
|
+
},
|
|
469
|
+
|
|
470
|
+
columns: this.columns,
|
|
471
|
+
data: {
|
|
472
|
+
headings: this.headings,
|
|
473
|
+
data: this.data
|
|
474
|
+
}
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
this._dt.on('datatable.init', () => {
|
|
478
|
+
const pagination = this.querySelector(`.${styles.paginationList}`);
|
|
479
|
+
if (!pagination) return;
|
|
480
|
+
|
|
481
|
+
const items = pagination.querySelectorAll(`.${styles.paginationListItem}`);
|
|
482
|
+
if (!items.length) return;
|
|
483
|
+
|
|
484
|
+
pagination.querySelector(
|
|
485
|
+
`.${styles.paginationListItem}:first-child .${styles.paginationListItemBtn}`
|
|
486
|
+
).innerHTML = caretLeftIcon;
|
|
487
|
+
|
|
488
|
+
pagination.querySelector(
|
|
489
|
+
`.${styles.paginationListItem}:last-child .${styles.paginationListItemBtn}`
|
|
490
|
+
).innerHTML = caretRightIcon;
|
|
491
|
+
|
|
492
|
+
pagination.querySelectorAll(`.${styles.paginationListItemBtn}:has(svg)`)
|
|
493
|
+
.forEach(btn => btn.classList.add(styles.hasSvg));
|
|
494
|
+
|
|
495
|
+
// Applica eventuale filtro contestuale passato via reload({ search: … })
|
|
496
|
+
// Lo facciamo qui, dentro datatable.init, per essere certi che
|
|
497
|
+
// simple-datatables abbia completato il render dei nuovi dati.
|
|
498
|
+
if (this._pendingSearch) {
|
|
499
|
+
const ps = this._pendingSearch;
|
|
500
|
+
this._pendingSearch = null;
|
|
501
|
+
|
|
502
|
+
if (ps.queries) {
|
|
503
|
+
this._dt.multiSearch(ps.queries);
|
|
504
|
+
} else if (ps.term !== undefined) {
|
|
505
|
+
this._dt.search(ps.term, ps.columns);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
} // end _render
|
|
511
|
+
|
|
512
|
+
} // end component
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
if (!customElements.get('s-datatable')) {
|
|
516
|
+
customElements.define('s-datatable', SimpleDatatableAdapter);
|
|
517
|
+
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { classnames } from '../../../../index.js';
|
|
6
6
|
|
|
7
|
-
import * as styles from '../
|
|
7
|
+
import * as styles from '../s-datatable-component.module.css';
|
|
8
8
|
|
|
9
9
|
import checkIcon from '../../../icons/check-bold.svg?inline';
|
|
10
10
|
import xIcon from '../../../icons/x-bold.svg?inline';
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"badge": {
|
|
3
|
-
"background": {
|
|
4
|
-
"color": {
|
|
5
|
-
"$value": "{primary.100}",
|
|
6
|
-
"$type": "color"
|
|
7
|
-
}
|
|
8
|
-
},
|
|
9
|
-
"color": {
|
|
10
|
-
"$value": "{primary.100-fg}",
|
|
11
|
-
"$type": "color"
|
|
12
|
-
},
|
|
13
|
-
"font": {
|
|
14
|
-
"size": {
|
|
15
|
-
"$value": "{font.size.xs}",
|
|
16
|
-
"$type": "dimension"
|
|
17
|
-
},
|
|
18
|
-
"weight": {
|
|
19
|
-
"$value": "{font.weight.semibold}",
|
|
20
|
-
"$type": "number"
|
|
21
|
-
}
|
|
22
|
-
},
|
|
23
|
-
"lg": {
|
|
24
|
-
"font": {
|
|
25
|
-
"size": {
|
|
26
|
-
"$value": "{font.size.base}",
|
|
27
|
-
"$type": "dimension"
|
|
28
|
-
},
|
|
29
|
-
"weight": {
|
|
30
|
-
"$value": "{badge.font.weight}",
|
|
31
|
-
"$type": "number"
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
} // end badge
|
|
36
|
-
}
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"btn": {
|
|
3
|
-
"close": {
|
|
4
|
-
"size": {
|
|
5
|
-
"$value": "1.5rem",
|
|
6
|
-
"$type": "dimension"
|
|
7
|
-
},
|
|
8
|
-
"padding": {
|
|
9
|
-
"$value": "3px",
|
|
10
|
-
"$type": "dimension"
|
|
11
|
-
},
|
|
12
|
-
"border": {
|
|
13
|
-
"width": {
|
|
14
|
-
"$value": "2px",
|
|
15
|
-
"$type": "dimension"
|
|
16
|
-
},
|
|
17
|
-
"color": {
|
|
18
|
-
"$value": "{btn.close.icon.color}",
|
|
19
|
-
"$type": "color"
|
|
20
|
-
},
|
|
21
|
-
"radius": {
|
|
22
|
-
"$value": "50%",
|
|
23
|
-
"$type": "dimension"
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
},
|
|
27
|
-
"background": {
|
|
28
|
-
"color": {
|
|
29
|
-
"$value": "{body.background.color}",
|
|
30
|
-
"$type": "color"
|
|
31
|
-
},
|
|
32
|
-
|
|
33
|
-
},
|
|
34
|
-
"icon": {
|
|
35
|
-
"color": {
|
|
36
|
-
"$value": "{text.color}",
|
|
37
|
-
"$type": "color"
|
|
38
|
-
},
|
|
39
|
-
"bar": {
|
|
40
|
-
"size": {
|
|
41
|
-
"$value": "2px",
|
|
42
|
-
"$type": "dimension"
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
},
|
|
47
|
-
|
|
48
|
-
"hover": {
|
|
49
|
-
"background": {
|
|
50
|
-
"color": {
|
|
51
|
-
"$value": "{btn.close.icon.color}",
|
|
52
|
-
"$type": "color"
|
|
53
|
-
}
|
|
54
|
-
},
|
|
55
|
-
"border": {
|
|
56
|
-
"color": {
|
|
57
|
-
"$value": "{btn.close.icon.color}",
|
|
58
|
-
"$type": "color"
|
|
59
|
-
}
|
|
60
|
-
},
|
|
61
|
-
"icon": {
|
|
62
|
-
"color": {
|
|
63
|
-
"$value": "{btn.close.background.color}",
|
|
64
|
-
"$type": "color"
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
},
|
|
68
|
-
|
|
69
|
-
"focus": {
|
|
70
|
-
"outline": {
|
|
71
|
-
"width": {
|
|
72
|
-
"$value": "2px",
|
|
73
|
-
"$type": "dimension"
|
|
74
|
-
},
|
|
75
|
-
"offset": {
|
|
76
|
-
"$value": "2px",
|
|
77
|
-
"$type": "dimension"
|
|
78
|
-
},
|
|
79
|
-
"color": {
|
|
80
|
-
"$value": "{link.focus.outline.color}",
|
|
81
|
-
"$type": "color"
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
},
|
|
85
|
-
"active": {
|
|
86
|
-
"background": {
|
|
87
|
-
"color": {
|
|
88
|
-
"$value": "{btn.close.background.color}",
|
|
89
|
-
"$type": "color"
|
|
90
|
-
}
|
|
91
|
-
},
|
|
92
|
-
"icon": {
|
|
93
|
-
"color": {
|
|
94
|
-
"$value": "{link.active.color}",
|
|
95
|
-
"$type": "color"
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
} // end close
|
|
100
|
-
} // end btn
|
|
101
|
-
}
|