@optionfactory/ful 4.0.9 → 4.0.11

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/dist/ful.mjs CHANGED
@@ -1995,7 +1995,9 @@ class Select extends ParsedElement {
1995
1995
  this.#changed();
1996
1996
  this.#syncBadges();
1997
1997
  });
1998
-
1998
+ this.#input.addEventListener('change', e => {
1999
+ e.stopPropagation();
2000
+ });
1999
2001
  this.#input.addEventListener('blur', e => {
2000
2002
  e.stopPropagation();
2001
2003
  if (e.relatedTarget && this.contains(e.relatedTarget)) {
@@ -2061,6 +2063,7 @@ class Select extends ParsedElement {
2061
2063
  this.#syncBadges();
2062
2064
  this.#input.focus();
2063
2065
  this.#ddmenu.hide();
2066
+ this.#input.value = '';
2064
2067
  });
2065
2068
  this.replaceChildren(fragment);
2066
2069
  }
@@ -2424,7 +2427,7 @@ class Pagination extends ParsedElement {
2424
2427
  <nav data-tpl-aria-label="#l10n:t('navigation')" class="user-select-none">
2425
2428
  <ul class="pagination">
2426
2429
  <li class="page-item ms-auto me-2 pagination-index"> {{ #l10n:t('showing', curr.label, total) }}</li>
2427
- <li class="page-item reload me-2"><a role="button"><i data-tpl-class="config.reloadIcon"></i></a></li>
2430
+ <li class="page-item me-2 reload"><a role="button"><i data-tpl-class="config.reloadIcon"></i></a></li>
2428
2431
  <li class="page-item prev">
2429
2432
  <a data-tpl-class="prev.enabled?'page-link':'page-link disabled'" data-tpl-aria-label="#l10n:t('previous')" role="button" data-tpl-data-page="prev.index">
2430
2433
  <i aria-hidden="true" data-tpl-class="config.prevIcon"></i>
@@ -2511,60 +2514,81 @@ class TableSchemaParser {
2511
2514
  if (!schema) {
2512
2515
  throw new Error(`missing expected <schema> in ${nodeOrFragment}`);
2513
2516
  }
2514
- return Nodes.queryChildrenAll(schema, "column")
2515
- .map(el => {
2516
- return {
2517
- sorter: el.getAttribute("sorter"),
2518
- order: el.getAttribute("order"),
2519
- title: TableSchemaParser.#parseTitle(el, template),
2520
- content: TableSchemaParser.#parseContent(el, template)
2517
+ const headersTr = document.createElement("tr");
2518
+ const rowsTr = document.createElement("tr");
2519
+ rowsTr.setAttribute("data-tpl-each", "rows");
2520
+ for (const attr of schema.getAttributeNames()) {
2521
+ const value = schema.getAttribute(attr);
2522
+ headersTr.setAttribute(attr, value ?? '');
2523
+ rowsTr.setAttribute(attr, value ?? '');
2524
+ }
2525
+ const columns = Nodes.queryChildrenAll(schema, "column");
2526
+ const sort = columns.filter(v => v.hasAttribute('order')).map(v => ({sorter: v.getAttribute("sorter"), order: v.getAttribute("order")}))[0] ?? null;
2527
+ for(var column of columns){
2528
+ const maybeTitleTag = Nodes.queryChildren(column, 'title');
2529
+ const sorter = column.getAttribute("sorter");
2530
+ const order = column.getAttribute("order");
2531
+ const titleNode = maybeTitleTag ?? document.createTextNode(column.getAttribute("title") ?? '');
2532
+ maybeTitleTag?.remove();
2533
+ column.removeAttribute("sorter");
2534
+ column.removeAttribute("order");
2535
+ column.removeAttribute("title");
2536
+ const wrappedTitleNode = (!sorter && !order ) ? titleNode : (() => {
2537
+ const fulSorter = document.createElement("ful-sorter");
2538
+ if(sorter){
2539
+ fulSorter.setAttribute("sorter", sorter);
2521
2540
  }
2522
- });
2523
- }
2524
-
2525
- static #parseTitle(el, template) {
2526
- const maybeTitleTag = Nodes.queryChildren(el, 'title');
2527
- if (maybeTitleTag) {
2528
- maybeTitleTag.remove();
2541
+ if(order){
2542
+ fulSorter.setAttribute("order", order);
2543
+ }
2544
+ fulSorter.append(titleNode);
2545
+ return fulSorter;
2546
+ })();
2547
+ const th = document.createElement("th");
2548
+ const td = document.createElement("td");
2549
+ for (const attr of column.getAttributeNames()) {
2550
+ const value = column.getAttribute(attr);
2551
+ th.setAttribute(attr, value ?? '');
2552
+ td.setAttribute(attr, value ?? '');
2553
+ }
2554
+ th.append(wrappedTitleNode);
2555
+ td.append(...column.childNodes);
2556
+ headersTr.append(th);
2557
+ rowsTr.append(td);
2529
2558
  }
2530
- const fragment = maybeTitleTag ? template.withFragment(Fragments.fromChildNodes(maybeTitleTag)).render() : document.createTextNode(el.getAttribute("title") ?? '');
2531
- return {
2532
- classes: el.getAttribute("th-class"),
2533
- fragment
2534
- };
2535
- }
2536
2559
 
2537
- static #parseContent(el, template) {
2538
2560
  return {
2539
- classes: el.getAttribute("td-class"),
2540
- template: template.withFragment(Fragments.fromChildNodes(el))
2561
+ headersTemplate: template.withOverlay({inHeaders: true, inRows: false}).withFragment(Fragments.from(headersTr)),
2562
+ rowsTemplate: template.withOverlay({inHeaders: false, inRows: true}).withFragment(Fragments.from(rowsTr)),
2563
+ sort: sort,
2564
+ length: columns.length
2541
2565
  }
2542
2566
  }
2543
2567
  }
2544
2568
 
2545
- class RemoteTableLoader{
2569
+ class RemoteTableLoader {
2546
2570
  #http;
2547
2571
  #url;
2548
2572
  #method;
2549
- constructor(http, url, method){
2573
+ constructor(http, url, method) {
2550
2574
  this.#http = http;
2551
2575
  this.#url = url;
2552
2576
  this.#method = method;
2553
2577
  }
2554
- async load(pageRequest, sortRequest, filterRequest){
2578
+ async load(pageRequest, sortRequest, filterRequest) {
2555
2579
  const filters = Object.entries(filterRequest).filter(([k, v]) => v);
2556
2580
  return await this.#http.request(this.#method, this.#url)
2557
2581
  .param("page", pageRequest.page)
2558
2582
  .param("size", pageRequest.size)
2559
- .param("sort", sortRequest.order ? `${sortRequest.sorter},${sortRequest.order}` : null)
2583
+ .param("sort", sortRequest ? `${sortRequest.sorter},${sortRequest.order}` : null)
2560
2584
  .param("filters", filters.length > 0 ? JSON.stringify(Object.fromEntries(filters)) : null)
2561
2585
  .fetchJson();
2562
- }
2586
+ }
2563
2587
  }
2564
2588
 
2565
2589
 
2566
- class TableLoader{
2567
- static create({el, http}){
2590
+ class TableLoader {
2591
+ static create({ el, http }) {
2568
2592
  const url = el.getAttribute("src");
2569
2593
  const method = el.getAttribute("method") ?? 'GET';
2570
2594
  return new RemoteTableLoader(http, url, method);
@@ -2575,18 +2599,18 @@ class Table extends ParsedElement {
2575
2599
  static slots = true;
2576
2600
  static l10n = {
2577
2601
  en: {
2578
- 'notloaded': 'Start searching to see results.',
2602
+ 'initial': 'Start searching to see results.',
2579
2603
  'error': 'Error while loading data:',
2580
2604
  'nodata': 'No elements found.',
2581
2605
  },
2582
2606
  it: {
2583
- 'notloaded': 'Avvia la ricerca per visualizzare i risultati.',
2607
+ 'initial': 'Avvia la ricerca per visualizzare i risultati.',
2584
2608
  'error': 'Errore nel caricamento dei dati:',
2585
2609
  'nodata': 'Nessun elemento trovato.',
2586
2610
  }
2587
2611
  }
2588
- static conf = {
2589
- sortIcon: '',
2612
+ static config = {
2613
+ searchIcon: 'bi bi-search'
2590
2614
  }
2591
2615
  static template = `
2592
2616
  <ful-form data-tpl-if="slots.filters">
@@ -2595,38 +2619,31 @@ class Table extends ParsedElement {
2595
2619
  <div class="table-wrapper">
2596
2620
  <table class="table">
2597
2621
  <caption data-tpl-if="slots.caption">{{{{ slots.caption }}}}</caption>
2598
- <thead>
2599
- <tr>
2600
- <th data-tpl-each="schema" scope="col" data-tpl-class="title.classes">
2601
- {{{{ title.fragment }}}}
2602
- <ful-sorter data-tpl-if="sorter || order" data-tpl-sorter="sorter" data-tpl-order="order"></ful-sorter>
2603
- </th>
2604
- </tr>
2605
- </thead>
2622
+ <thead></thead>
2606
2623
  <tbody></tbody>
2607
- <tbody data-ref="no-autoload">
2624
+ <tbody data-ref="initial">
2608
2625
  <tr>
2609
- <td data-tpl-colspan="schema.length" class="text-center align-middle p-4">
2610
- <i class="bi bi-search" style="font-size: 40px; color: #BDC3CA"></i>
2611
- <p class="mt-3 mb-0" style="color: #BDC3CA">
2612
- {{ #l10n:t('notloaded') }}
2613
- </p>
2626
+ <td data-tpl-colspan="schema.length">
2627
+ <div>
2628
+ <p data-tpl-if="config.searchIcon"><i data-tpl-class="config.searchIcon"></i></p>
2629
+ {{{ #l10n:t('initial') }}}
2630
+ </div>
2614
2631
  </td>
2615
2632
  </tr>
2616
2633
  </tbody>
2617
2634
  <tbody data-ref="loading" hidden>
2618
2635
  <tr>
2619
- <td data-tpl-colspan="schema.length" class="text-center align-middle p-4">
2636
+ <td data-tpl-colspan="schema.length">
2620
2637
  <ful-spinner class="big"></ful-spinner>
2621
2638
  </td>
2622
2639
  </tr>
2623
2640
  </tbody>
2624
2641
  <tbody data-ref="feedback" hidden>
2625
2642
  <tr>
2626
- <td data-tpl-colspan="schema.length" class="text-center align-middle p-4">
2643
+ <td data-tpl-colspan="schema.length">
2627
2644
  <div class="alert alert-danger">
2628
2645
  <p>{{ #l10n:t('error') }}</p>
2629
- <p class="mb-0" data-ref="feedback-error"></p>
2646
+ <div data-ref="feedback-error"></div>
2630
2647
  </div>
2631
2648
  </td>
2632
2649
  </tr>
@@ -2645,11 +2662,7 @@ class Table extends ParsedElement {
2645
2662
  {{ #l10n:t('nodata') }}
2646
2663
  </td>
2647
2664
  </tr>
2648
- <tr data-tpl-each="pageResponse.data" data-tpl-var="row">
2649
- <td data-tpl-each="schema" data-tpl-class="content.classes">
2650
- {{{{ content.template.withOverlay(row).render() }}}}
2651
- </td>
2652
- </tr>
2665
+ {{{{ schema.rowsTemplate.withOverlay({'rows': pageResponse.data}).render() }}}}
2653
2666
  `
2654
2667
  };
2655
2668
  #schema;
@@ -2670,13 +2683,13 @@ class Table extends ParsedElement {
2670
2683
  this.#schema = schema;
2671
2684
  this.#body = table.querySelector(':scope > tbody');
2672
2685
  this.#loading = table.querySelector(":scope > tbody[data-ref=loading]");
2673
- this.#noAutoload = table.querySelector(":scope > tbody[data-ref=no-autoload]");
2686
+ this.#noAutoload = table.querySelector(":scope > tbody[data-ref=initial]");
2674
2687
  this.#feedback = table.querySelector(":scope > tbody[data-ref=feedback]");
2675
2688
  this.#paginator = Nodes.queryChildren(fragment, 'ful-pagination');
2676
2689
  this.#sorters = table.querySelectorAll(':scope > thead ful-sorter') ?? [];
2677
2690
  this.replaceChildren(fragment);
2691
+ schema.headersTemplate.renderTo(this.querySelector('thead'));
2678
2692
  await Rendering.waitForChildren(this);
2679
- const orderFromSchema = schema.find(v => v.order);
2680
2693
 
2681
2694
  const maybeForm = /** @type any */(Nodes.queryChildren(this, 'ful-form'));
2682
2695
  this.#latestRequest = {
@@ -2684,7 +2697,7 @@ class Table extends ParsedElement {
2684
2697
  page: 0,
2685
2698
  size: this.getAttribute("page-size") ? Number(this.getAttribute("page-size")) : 10
2686
2699
  },
2687
- sortRequest: { order: orderFromSchema?.order, sorter: orderFromSchema?.sorter },
2700
+ sortRequest: schema.sort,
2688
2701
  filterRequest: maybeForm?.values ?? {}
2689
2702
  };
2690
2703
  maybeForm?.addEventListener('submit:success', async (evt) => {
@@ -2719,7 +2732,7 @@ class Table extends ParsedElement {
2719
2732
  this.#noAutoload.setAttribute("hidden", "");
2720
2733
  try {
2721
2734
  const loader = Loaders.fromAttributes(this, 'loaders:table');
2722
- const pageResponse =await loader.load(pageRequest, sortRequest, filterRequest);
2735
+ const pageResponse = await loader.load(pageRequest, sortRequest, filterRequest);
2723
2736
  this.#latestRequest = { pageRequest, sortRequest, filterRequest };
2724
2737
  this.#update(pageRequest, sortRequest, filterRequest, pageResponse);
2725
2738
  } catch (/** @type any */error) {