From 8c1279c2e93d9c095d745d661c1f1468f80b4a57 Mon Sep 17 00:00:00 2001 From: Jonathan DURAND Date: Mon, 14 Apr 2025 16:20:15 +0200 Subject: [PATCH 01/10] Update filter column generation --- dist/dom/FootersLxDom.d.ts | 12 +++++++ lib/core/Filters.ts | 71 +++++++++++++++++++------------------- lib/core/LyxeaDatatable.ts | 27 +++++++++++---- lib/dom/FiltersLxDom.ts | 3 ++ lib/dom/FootersLxDom.ts | 62 +++++++++++++++++++++++++++++++++ package.json | 1 + 6 files changed, 134 insertions(+), 42 deletions(-) create mode 100644 dist/dom/FootersLxDom.d.ts create mode 100644 lib/dom/FootersLxDom.ts diff --git a/dist/dom/FootersLxDom.d.ts b/dist/dom/FootersLxDom.d.ts new file mode 100644 index 0000000..fa0c5af --- /dev/null +++ b/dist/dom/FootersLxDom.d.ts @@ -0,0 +1,12 @@ +import AbstractLxDom from './AbstractLxDom'; +import { LxConfigObject } from '../core/LyxeaDatatable'; +declare class FooterLxDom extends AbstractLxDom { + tableRef: HTMLElement | null; + footerRef: HTMLElement | null; + config: LxConfigObject; + constructor(ref: HTMLElement, config: LxConfigObject); + appendTableFooter: () => void; + getFooterElement: () => HTMLElement | null; + build(id?: string, className?: string): Promise; +} +export default FooterLxDom; diff --git a/lib/core/Filters.ts b/lib/core/Filters.ts index 3caff12..e39c2fb 100644 --- a/lib/core/Filters.ts +++ b/lib/core/Filters.ts @@ -1,47 +1,46 @@ -import FiltersLxDom from '@dom/FiltersLxDom'; -import { CustomDatatableConfig } from './LyxeaDatatable'; +import { LxConfigObject } from './LyxeaDatatable'; import DataTable from 'datatables.net-dt'; +import FooterLxDom from '@dom/FootersLxDom'; class Filters { - #domBuilder?: FiltersLxDom; - #headerLength: number; - #instance?: DataTable; - - constructor(config: CustomDatatableConfig, instance?: DataTable) { - this.#headerLength = this.#calculateHeaderLength(config); - this.#instance = instance; + tableRef: HTMLElement | null; + config: LxConfigObject; + footerUiBuilder: FooterLxDom; + + constructor(ref: HTMLElement, config: LxConfigObject) { + this.tableRef = ref; + this.config = config; + this.footerUiBuilder = new FooterLxDom(this.tableRef, config); } - #calculateHeaderLength(config: CustomDatatableConfig): number { - let sum = 0; - if (config.columns) { - sum += config.columns.length; - } - if (config.lxConfig && config.lxConfig.headers) { - config.lxConfig.headers.forEach((header) => { - sum += header.columns.length; - }); - } - - return sum; - } - - init(headerEl?: HTMLElement): HTMLElement | undefined { - if (!headerEl) return; - if (!this.#instance) throw new Error('Instance is not defined'); - - this.#domBuilder = new FiltersLxDom(headerEl); - return this.#domBuilder.generate( - this.#headerLength, - this.#instance, - this._filterEvent - ) as HTMLElement; + async build(id = 'main_filter', className = 'main_filter'): Promise { + return this.footerUiBuilder.build(id, className); } - _filterEvent(e: Event) { - const input = e.target as HTMLInputElement; + init(dtInstance: DataTable, type: String) { // @ts-ignore - this.column(input.dataset.index).search(input.value).draw(); + dtInstance.columns() + .every(function () { + // @ts-ignore + let title = this.footer().textContent; + + // Create input element + if(type == 'input'){ + let input = document.createElement('input'); + input.placeholder = title; + // @ts-ignore + this.footer().replaceChildren(input); + + // Event listener for user input + input.addEventListener('keyup', () => { + // @ts-ignore + if (this.search() !== this.value) { + // @ts-ignore + this.search(input.value).draw(); + } + }); + } + }); } } diff --git a/lib/core/LyxeaDatatable.ts b/lib/core/LyxeaDatatable.ts index d8f4a2a..017eecb 100644 --- a/lib/core/LyxeaDatatable.ts +++ b/lib/core/LyxeaDatatable.ts @@ -94,7 +94,9 @@ class LyxeaDatatable #standardColumnBuilder?: DtColumns; #customColumnBuilder?: DtHeaders; #dtButtons?: DtButtons; + // @ts-ignore #headerElement?: HTMLElement; + filterColumn?: Filters; constructor(ref: string, config?: CustomDatatableConfig) { super(); @@ -178,8 +180,10 @@ class LyxeaDatatable If columns in the standard object and in lxconfig, header generation is only based on lxconfig. This allows you to generate the header with all the columns (and not just the columns defined in lxconfig). */ - if (lxConfig.headers && standardColumns && standardColumns.length) { - lxConfig.headers?.unshift({ columns: [...standardColumns] }); + if (standardColumns?.length) { + lxConfig.headers = lxConfig.headers ? + [{ columns: [...standardColumns] }, ...lxConfig.headers] : + [{ columns: [...standardColumns] }]; } new LxRenderer(lxConfig); const headersBuilder = this.#customColumnBuilder @@ -193,6 +197,11 @@ class LyxeaDatatable }); this.#headerElement = await headerUiBuilder.build(); + if (lxConfig && lxConfig.filters) { + this.filterColumn = new Filters(this.refElement, lxConfig); + await this.filterColumn.build(); + } + /** * Get the data if not set */ @@ -263,10 +272,16 @@ class LyxeaDatatable * Adding filter inputs */ if (lxConfig && lxConfig.filters) { - // @ts-ignore - this.#headerElement = new Filters(this.config, dtInstance).init( - this.#headerElement - ); + this.filterColumn?.init(dtInstance, 'input'); + if(this.config?.scrollX){ + jquery(`${this._ref}_wrapper .dt-scroll-foot tfoot tr th`).removeAttr('data-dt-column'); + var footer = jquery(`${this._ref}_wrapper .dt-scroll-foot tfoot tr`); + jquery(`${this._ref}_wrapper .dt-scroll-head thead`).append(footer); + } else { + jquery(`${this._ref} tfoot tr th`).removeAttr('data-dt-column'); + var footer = jquery(`${this._ref} tfoot tr`); + jquery(`${this._ref} thead`).append(footer); + } } /** diff --git a/lib/dom/FiltersLxDom.ts b/lib/dom/FiltersLxDom.ts index 68ebd8c..06f0d11 100644 --- a/lib/dom/FiltersLxDom.ts +++ b/lib/dom/FiltersLxDom.ts @@ -1,6 +1,9 @@ import AbstractLxDom from './AbstractLxDom'; import DataTable from 'datatables.net'; +/** + * Deprecated + */ class FiltersLxDom extends AbstractLxDom { #headerElement: Node; constructor(header: Node) { diff --git a/lib/dom/FootersLxDom.ts b/lib/dom/FootersLxDom.ts new file mode 100644 index 0000000..9846934 --- /dev/null +++ b/lib/dom/FootersLxDom.ts @@ -0,0 +1,62 @@ +import AbstractLxDom from './AbstractLxDom'; +import { LxConfigObject } from '@core/LyxeaDatatable'; +import DomError from './DomError'; + +class FooterLxDom extends AbstractLxDom { + tableRef: HTMLElement | null; + footerRef: HTMLElement | null = null; + config: LxConfigObject; + + + constructor(ref: HTMLElement, config : LxConfigObject) { + super(); + this.tableRef = ref; + this.config = config; + + this.appendTableFooter(); + this.getFooterElement(); + } + + appendTableFooter = () => { + if(!this.tableRef?.querySelector('tfoot')) + this.tableRef?.append(this.$element('tfoot', {})); + } + + getFooterElement = (): HTMLElement | null => { + this.footerRef = this.tableRef?.querySelector('tfoot') ?? null; + return this.footerRef; + }; + + + async build(id = 'main_footer', className = 'main_footer'): Promise { + if (!this.footerRef) throw new DomError('Cannot select the dom footer ref'); + if (!this.config.headers?.length) return this.footerRef; + + const groupFooterCells: Array = []; + this.config.headers?.forEach(header => { + header.columns?.forEach(column => { + groupFooterCells.push( + this.$element('th', { + classList: ['colspan-border'], + attributes: { + rowspan: '1', + colspan: '1', + }, + //content: column.title, + style: column.style, + }) + ); + }) + }) + const groupFooterWrapper = this.$element('tr', { + attributes: { class: className, id: id }, + children: groupFooterCells, + }) + this.footerRef?.append(groupFooterWrapper); + + return this.footerRef; + } + +} + +export default FooterLxDom; diff --git a/package.json b/package.json index c41d3ee..37976f1 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "scripts": { "dev": "vite", "build": "tsc && vite build", + "watch": "tsc && vite build --watch", "preview": "vite preview", "test": "export NODE_ENV=test && jest", "coverage": "jest --coverage", From 0adb5e77e61dd27532e522cfd769bd553d70623f Mon Sep 17 00:00:00 2001 From: Jonathan DURAND Date: Wed, 16 Apr 2025 14:45:51 +0200 Subject: [PATCH 02/10] feat(filter): Add input with fa-search icon --- lib/core/Filters.ts | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/core/Filters.ts b/lib/core/Filters.ts index e39c2fb..99a36f6 100644 --- a/lib/core/Filters.ts +++ b/lib/core/Filters.ts @@ -26,11 +26,23 @@ class Filters { // Create input element if(type == 'input'){ + // Create a container div for the input and icon + let container = document.createElement('div'); + container.classList.add('column_search_container'); + // Create the input element let input = document.createElement('input'); + input.setAttribute("type", "text"); + input.classList.add('column_search'); input.placeholder = title; + // Create the icon element + let icon = document.createElement('i'); + icon.classList.add('fa', 'fa-search'); + // Append the input and icon to the container + container.appendChild(input); + container.appendChild(icon); + // Replace the footer content with the container // @ts-ignore - this.footer().replaceChildren(input); - + this.footer().replaceChildren(container); // Event listener for user input input.addEventListener('keyup', () => { // @ts-ignore @@ -42,6 +54,7 @@ class Filters { } }); } + } export default Filters; From 8fc3097d6cbf47d6cb94b0e3664d4e3fa2bfebbc Mon Sep 17 00:00:00 2001 From: Jonathan DURAND Date: Fri, 18 Apr 2025 10:39:33 +0200 Subject: [PATCH 03/10] feat(datatable): improve scrollYFitToScreen config handling - Add utility method _convertToScrollYFitToScreenConfig to safely convert boolean config to ScrollYFitToScreen object - Add proper type checking for scrollYFitToScreen configuration - Ensure consistent handling of staticMargin parameter --- lib/core/LyxeaDatatable.ts | 72 +++++++++++++++++++++++---- lib/plugins/action/dom/ActionLxDom.ts | 2 +- 2 files changed, 64 insertions(+), 10 deletions(-) diff --git a/lib/core/LyxeaDatatable.ts b/lib/core/LyxeaDatatable.ts index 017eecb..72ce8f2 100644 --- a/lib/core/LyxeaDatatable.ts +++ b/lib/core/LyxeaDatatable.ts @@ -6,7 +6,7 @@ import 'datatables.net-buttons/js/buttons.colVis.mjs'; import 'datatables.net-buttons/js/buttons.html5.mjs'; import 'datatables.net-buttons/js/buttons.print.mjs'; -import DataTable, { Config, ConfigColumns } from 'datatables.net-dt'; +import DataTable, { Config, ConfigColumns, ConfigButtons, ButtonConfig } from 'datatables.net-dt'; import AbstractLyxeaDatatable from './AbstractLyxeaDatatable'; import DtHeaders from './DtHeaders'; import Dao from '@dao/Dao'; @@ -40,17 +40,22 @@ export type CustomRenderer = | Array | Array; +export type ScrollYFitToScreen = { + addStaticMargin?: number; +}; + export interface CustomDatatableConfig extends Config { lxConfig?: LxConfigObject; data?: Array; } export type LxConfigObject = { + keepFixedHeaderInDT?: boolean; url?: string; headers?: LxHeadersConfig; filters?: boolean; handleBootrapTabChange?: boolean; - scrollYFitToScreen?: boolean; + scrollYFitToScreen?: boolean | ScrollYFitToScreen; row_action?: { width: string; className?: string; @@ -261,7 +266,7 @@ class LyxeaDatatable if (!this.config.buttons) this.config.buttons = this.#dtButtons.getDefaults(); - this.#dtButtons.parse(this.config.buttons); + this.#dtButtons.parse(this.config.buttons as true | ConfigButtons | (string | ButtonConfig)[]); jquery(`${this._ref}`).on('init.dt', (e, settings) => { if (e.namespace !== 'dt') { @@ -287,10 +292,11 @@ class LyxeaDatatable /** * Fit scrollY to screen */ - if (lxConfig && lxConfig.scrollYFitToScreen) { - this.scrollYFitToScreen(); - // Force redraw (FitToScreen has an effect on the draw event) - dtInstance.draw(); + if (lxConfig?.scrollYFitToScreen) { + const scrollYConfig = this._convertToScrollYFitToScreenConfig(lxConfig.scrollYFitToScreen); + this._scrollYFitToScreen(scrollYConfig); + // Force redraw (FitToScreen has an effect on the draw event) + dtInstance.draw(); } }); /** @@ -306,13 +312,50 @@ class LyxeaDatatable if (lxConfig && lxConfig.handleBootrapTabChange) this.handleBootrapTabChange(this.instance); + if (lxConfig?.keepFixedHeaderInDT && this._ref && this.instance?.fixedHeader && this.instance?.fixedHeader.enabled()) { + this.__keepFixedHeaderInDT(); + } return this; } __filterDataWithKey() {} - scrollYFitToScreen() { + + __keepFixedHeaderInDT() { + const onScroll = () => { + // Vérifie si FixedHeader est actif (présence de .dtfh-floatingparent) + // Et on le déplace en haut du tableau + + // Récupère l’élément DOM du tableau + const table = document.querySelector(this._ref); + if (!table) return; + + const refClean = this._ref.startsWith('#') || this._ref.startsWith('.') + ? this._ref.slice(1) + : this._ref; + const expectedAriaDescribedBy = `${refClean}_info`; + // Cherche tous les floating headers possibles + const floatingHeaders = document.querySelectorAll('.dtfh-floatingparent'); + // On cherche celui qui correspond à notre datatable + const floatingHeader = Array.from(floatingHeaders).find(header => { + const innerTable = header.querySelector('table'); + return innerTable?.getAttribute('aria-describedby') === expectedAriaDescribedBy; + }); + // Vérifie que le header n’est pas déjà dans le tableau + if (floatingHeader && !table.contains(floatingHeader)) { + // Insère le header tout en haut de la table + table.insertBefore(floatingHeader, table.firstChild); + } + // Supprimer l’event listener si on ne veut le faire qu’une fois : + // window.removeEventListener('scroll', onScroll); + }; + + // Ajoute l'écouteur + window.addEventListener('scroll', onScroll); + } + _scrollYFitToScreen(config: ScrollYFitToScreen) { const self = this; + const staticMargin = config && config.addStaticMargin ? config.addStaticMargin : 0; jquery(`${this._ref}`).on('draw.dt', (e, _) => { if (e.namespace !== 'dt') { return; @@ -349,6 +392,7 @@ class LyxeaDatatable (acc, node) => acc + (node as HTMLElement).offsetHeight, 0 ); + console.log("dtLayoutRowsHeight", dtLayoutRowsHeight); const myHeight = window.innerHeight - // La taille de la fenêtre complete tabTop - // L'ordonnée du haut du tableau @@ -357,7 +401,7 @@ class LyxeaDatatable dtScrollHeadHeight - // La taille du header (lorsqu'on utilise `layout`) dtScrollFootHeight - // La taille du footer (lorsqu'on utilise `layout`) dtLayoutRowsHeight - // La taille de toutes les rows (lorsqu'on utilise `layout`) - 10; // valeur statique pour assurer une marge + staticMargin; // valeur statique pour assurer une marge const dtScrollBody = document.querySelector( `${self._ref}_wrapper .dt-scroll-body` ) as HTMLElement; @@ -384,6 +428,16 @@ class LyxeaDatatable }); }); } + + // Créer une fonction utilitaire pour convertir le paramètre + _convertToScrollYFitToScreenConfig(config: boolean | ScrollYFitToScreen): ScrollYFitToScreen { + if (typeof config === 'boolean' && config === true) { + return { + addStaticMargin: 0 + }; + } + return config as ScrollYFitToScreen; + } } export default LyxeaDatatable; diff --git a/lib/plugins/action/dom/ActionLxDom.ts b/lib/plugins/action/dom/ActionLxDom.ts index 8f784cc..1f41270 100644 --- a/lib/plugins/action/dom/ActionLxDom.ts +++ b/lib/plugins/action/dom/ActionLxDom.ts @@ -34,7 +34,7 @@ class ActionLxDom extends AbstractLxDom { name: name, 'aria-label': label ?? name, }, - style: { ...defaultStyle, ...style } ?? defaultStyle, + style: { ...defaultStyle, ...style }, onClick: Array.isArray(effect) ? effect : [effect], }); } From 44fe2da1fe8fb332cc0c5f19fda97807ae005188 Mon Sep 17 00:00:00 2001 From: Jonathan DURAND Date: Fri, 18 Apr 2025 12:50:23 +0200 Subject: [PATCH 04/10] fix(keepFixedHeaderInDT) : Migrate to an Observer instead of scroll event --- lib/core/LyxeaDatatable.ts | 63 ++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/lib/core/LyxeaDatatable.ts b/lib/core/LyxeaDatatable.ts index 72ce8f2..fb264ce 100644 --- a/lib/core/LyxeaDatatable.ts +++ b/lib/core/LyxeaDatatable.ts @@ -312,7 +312,7 @@ class LyxeaDatatable if (lxConfig && lxConfig.handleBootrapTabChange) this.handleBootrapTabChange(this.instance); - if (lxConfig?.keepFixedHeaderInDT && this._ref && this.instance?.fixedHeader && this.instance?.fixedHeader.enabled()) { + if (lxConfig?.keepFixedHeaderInDT && this._ref) { this.__keepFixedHeaderInDT(); } return this; @@ -320,39 +320,42 @@ class LyxeaDatatable __filterDataWithKey() {} - __keepFixedHeaderInDT() { - const onScroll = () => { - // Vérifie si FixedHeader est actif (présence de .dtfh-floatingparent) - // Et on le déplace en haut du tableau - - // Récupère l’élément DOM du tableau - const table = document.querySelector(this._ref); - if (!table) return; - - const refClean = this._ref.startsWith('#') || this._ref.startsWith('.') - ? this._ref.slice(1) - : this._ref; - const expectedAriaDescribedBy = `${refClean}_info`; - // Cherche tous les floating headers possibles - const floatingHeaders = document.querySelectorAll('.dtfh-floatingparent'); - // On cherche celui qui correspond à notre datatable - const floatingHeader = Array.from(floatingHeaders).find(header => { - const innerTable = header.querySelector('table'); - return innerTable?.getAttribute('aria-describedby') === expectedAriaDescribedBy; - }); - // Vérifie que le header n’est pas déjà dans le tableau - if (floatingHeader && !table.contains(floatingHeader)) { - // Insère le header tout en haut de la table - table.insertBefore(floatingHeader, table.firstChild); + const observer = new MutationObserver((mutationsList) => { + for (const mutation of mutationsList) { + for (const addedNode of mutation.addedNodes) { + if (!(addedNode instanceof HTMLElement)) continue; + + // Si on trouve un .dtfh-floatingparent + if (addedNode.classList.contains('dtfh-floatingparent')) { + + const table = document.querySelector(this._ref); + if (!table) return; + + const refClean = this._ref.startsWith('#') || this._ref.startsWith('.') + ? this._ref.slice(1) + : this._ref; + const expectedAriaDescribedBy = `${refClean}_info`; + + const innerTable = addedNode.querySelector('table'); + if (innerTable?.getAttribute('aria-describedby') === expectedAriaDescribedBy) { + if (!table.contains(addedNode)) { + table.insertBefore(addedNode, table.firstChild); + } + } + } + } } - // Supprimer l’event listener si on ne veut le faire qu’une fois : - // window.removeEventListener('scroll', onScroll); - }; + }); - // Ajoute l'écouteur - window.addEventListener('scroll', onScroll); + // Observe tout le document (ou tu peux cibler un conteneur plus précis) + observer.observe(document.body, { + childList: true, + subtree: true + }); } + + _scrollYFitToScreen(config: ScrollYFitToScreen) { const self = this; const staticMargin = config && config.addStaticMargin ? config.addStaticMargin : 0; From c474a9431238ea9f49b406f7d837139b8fb03684 Mon Sep 17 00:00:00 2001 From: Jonathan DURAND Date: Fri, 18 Apr 2025 13:26:24 +0200 Subject: [PATCH 05/10] fix(action): Remove defaut cell style ! --- lib/plugins/action/Action.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/plugins/action/Action.ts b/lib/plugins/action/Action.ts index d3b04cb..2705227 100644 --- a/lib/plugins/action/Action.ts +++ b/lib/plugins/action/Action.ts @@ -111,7 +111,7 @@ class Action { if (action.onError) action.onError(err, rowData); } }); - this.#domBuilder.defineDefaultCellStyle(td as HTMLElement); + //this.#domBuilder.defineDefaultCellStyle(td as HTMLElement); if (this.#celllClassName) (td as HTMLElement).classList.add(this.#celllClassName); td.appendChild(btn); From 8de20566710421634b3e35bd297ba0972c6f8a7c Mon Sep 17 00:00:00 2001 From: Jonathan DURAND Date: Fri, 18 Apr 2025 13:27:02 +0200 Subject: [PATCH 06/10] fix(Renderer): Apply renderer only on display mode for prevent date sorted --- lib/dto/Renderer.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/dto/Renderer.ts b/lib/dto/Renderer.ts index b59dc4d..3c1fb32 100644 --- a/lib/dto/Renderer.ts +++ b/lib/dto/Renderer.ts @@ -13,10 +13,12 @@ type MultiRender = Array<(d: T, type: any, row: any, meta: any) => T>; $.fn.dataTable.render.multi = (renderArray: MultiRender) => (d: T, type: any, row: any, meta: any) => { - renderArray.forEach((render) => { - if (render) d = render(d, type, row, meta); - }); - return d; + if (type == 'display') { + renderArray.forEach((render) => { + if (render) d = render(d, type, row, meta); + }); + return d; + } }; class LxRenderer { From 6b4a31e140cbd49ff9fdb954f52c8ba64209b518 Mon Sep 17 00:00:00 2001 From: Jonathan DURAND Date: Fri, 18 Apr 2025 17:20:03 +0200 Subject: [PATCH 07/10] fix(renderer): keep raw data for sort. TODO : Need to keep raw data for export, like CUT_LONG_TEXT render ... --- lib/dto/Renderer.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/dto/Renderer.ts b/lib/dto/Renderer.ts index 3c1fb32..0f53637 100644 --- a/lib/dto/Renderer.ts +++ b/lib/dto/Renderer.ts @@ -13,12 +13,15 @@ type MultiRender = Array<(d: T, type: any, row: any, meta: any) => T>; $.fn.dataTable.render.multi = (renderArray: MultiRender) => (d: T, type: any, row: any, meta: any) => { - if (type == 'display') { - renderArray.forEach((render) => { - if (render) d = render(d, type, row, meta); - }); + if (type !== 'display') { + // pour tri, filtrage, etc. => retourne valeur brute return d; } + + renderArray.forEach((render) => { + if (render) d = render(d, type, row, meta); + }); + return d; }; class LxRenderer { From 4605066ed2a936bc5a54efa17ad7de078d43eb95 Mon Sep 17 00:00:00 2001 From: Jonathan DURAND Date: Wed, 23 Apr 2025 13:01:35 +0200 Subject: [PATCH 08/10] fix(renderer): Revert to single renderer for this moment; fix all renderer to work with render or createdCell as needed --- lib/dto/Renderer.ts | 252 +++++++++++++++++++++------------------- lib/dto/Renderer.ts.bck | 136 ++++++++++++++++++++++ 2 files changed, 271 insertions(+), 117 deletions(-) create mode 100644 lib/dto/Renderer.ts.bck diff --git a/lib/dto/Renderer.ts b/lib/dto/Renderer.ts index 0f53637..487628a 100644 --- a/lib/dto/Renderer.ts +++ b/lib/dto/Renderer.ts @@ -1,136 +1,154 @@ import { LxConfigObject } from '@core/LyxeaDatatable'; import '../utils/fixToFixed'; -import $ from 'jquery'; import dayjs from 'dayjs'; -export type RendederConfig = {}; - -type MultiRender = Array<(d: T, type: any, row: any, meta: any) => T>; - -/** Multi render function to handle array of modifiers */ -// original idea : https://datatables.net/forums/discussion/43160/multi-render-renderer -// @ts-ignore -$.fn.dataTable.render.multi = - (renderArray: MultiRender) => - (d: T, type: any, row: any, meta: any) => { - if (type !== 'display') { - // pour tri, filtrage, etc. => retourne valeur brute - return d; +const CustomRenderers = { + DATE_DAY: { + render: function (data: any, type: any) { + if (type === 'display' || type === 'filter') { + return dayjs(data).format('DD/MM/YYYY'); + } + return data; + } + }, + DATE_WITH_SECOND: { + render: function (data: any, type: any) { + if (type === 'display' || type === 'filter') { + return dayjs(data).format('DD/MM/YYYY HH:mm:ss'); + } + return data; + } + }, + LOCAL_NUMBER: { + render: function (data: any, type: any) { + if (type === 'display' || type === 'filter') { + return data.toLocaleString(); + } + return data; + } + }, + BOOLEAN_OUI_NON: { + render: function (data: any, type: any) { + if (type === 'display' || type === 'filter') { + return data === true ? 'Oui' : 'Non'; + } + return data; + }, + }, + NUMBER_FIXED_2: { + render: function (data: any) { + if (typeof data === 'number') { + return data.toFixed(2); + } else if (typeof data === 'string') { + const float = parseFloat(data); + if (isNaN(float)) return data; + else return float.toFixed(2); + } + }, + }, + NUMBER_2_DIGIT_MAX: { + render: function (data: any) { + if (typeof data === 'number') { + if (data % 1 === 0) return data; + else return data.toFixed(2); + } else if (typeof data === 'string') { + const float = parseFloat(data); + if (isNaN(float)) return data; + if (float % 1 === 0) return data; + else return float.toFixed(2); + } else { + return data; + } + }, + }, + PARSE_INT: { + render: function (data: any) { + return parseInt(data); + } + }, + UPPERCASE: { + render: (data: any) => + typeof data === 'string' ? data.toUpperCase() : data + }, + LOWERCASE: { + render: (data: any) => + typeof data === 'string' ? data.toLowerCase() : data + }, + CUT_LONG_TEXT: { + createdCell: function (td: any, cellData: any) { + if (typeof cellData === 'string') { + if (cellData.length > 30) { + td.title = cellData; + td.innerText = cellData.substring(0, 28) + '…'; + } + } + } + }, + CHECKBOX: { + checkboxes: { + selectRow: true, } + }, + _dynamic: [ + { + pattern: /^DATE_TO_FORMAT_(.+)$/, + handler: (match: any) => { + const format = match[1]; + return { + render: function (data: any, type: any) { + if (type === 'display' || type === 'filter') { + //return moment(data).format(format); + return dayjs(data).format(format); + } + return data; + } + }; + } + } + ] +}; - renderArray.forEach((render) => { - if (render) d = render(d, type, row, meta); - }); - return d; - }; +function resolveRenderer(nameOrObject: any) { + if (typeof nameOrObject === 'string') { + if (nameOrObject in CustomRenderers) { + // @ts-ignore + return CustomRenderers[nameOrObject]; + } + for (const dyn of CustomRenderers._dynamic || []) { + const match = nameOrObject.match(dyn.pattern); + if (match) { + return dyn.handler(match); + } + } + return {}; + } + return nameOrObject; +} class LxRenderer { - renderers: Array; constructor(config: LxConfigObject) { - this.renderers = []; config.headers && config.headers.map((headers) => { for (const config of headers.columns) { if (!config.renderer) continue; - if (!Array.isArray(config.renderer)) - config.renderer = Array(config.renderer); - - const multiRender = config.renderer.map((renderer) => { - if (typeof renderer === 'string') { - if (renderer.startsWith('DATE_TO_FORMAT_')) { - return (data: any) => { - const format = renderer.split('_').pop(); - return dayjs(data).format(format); - }; - } - - switch (renderer) { - case 'DATE_DAY': - return (data: any) => dayjs(data).format('DD/MM/YYYY'); - case 'DATE': - return (data: any) => dayjs(data).format('DD/MM/YYYY HH:mm'); - case 'DATE_WITH_SECOND': - return (data: any) => - dayjs(data).format('DD/MM/YYYY HH:mm:ss'); - case 'LOCAL_NUMBER': - return (data: any) => data.toLocaleString(); - case 'BOOLEAN_YESNO': - return this.booleanString; - case 'NUMBER_FIXED_2': - return this.numberToFixed; - case 'NUMBER_2_DIGIT_MAX': - return this.number2DigitMax; - case 'CUT_LONG_TEXT': - return this.cutLongText; - case 'PARSE_INT': - return (data: any) => parseInt(data); - case 'CHECKBOX': - // @ts-ignore - config.checkboxes = { - selectRow: true, - }; - break; - case 'UPPERCASE': - return this.uppercase; - } - } - }); - - // @ts-ignore - config.render = $.fn.dataTable.render.multi(multiRender); + if (Array.isArray(config.renderer)) { + console.warn('Multiple renderers are not supported yet. Please use a single renderer.'); + config.renderer = config.renderer[0]; + } + const renderConf = resolveRenderer(config.renderer); + if (renderConf.render) { + config.render = renderConf.render; + } + if (renderConf.createdCell) { + config.createdCell = renderConf.createdCell; + } + if (renderConf.checkboxes) { + // @ts-ignore + config.checkboxes = renderConf.checkboxes; + } } }); } - - number2DigitMax(data: any | null) { - if (typeof data === 'number') { - if (data % 1 === 0) return data; - else return data.toFixed(2); - } else if (typeof data === 'string') { - const float = parseFloat(data); - if (isNaN(float)) return data; - if (float % 1 === 0) return data; - else return float.toFixed(2); - } else { - return data; - } - } - - booleanString = (data: boolean) => (data === true ? 'Oui' : 'Non'); - - cutLongText = (data: any) => { - if (data.length < 30) return data; - var esc = function (t: any) { - return t - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"'); - }; - - const shortened = esc(data).substr(0, 30); - const d = esc(data); - return ( - '' + - shortened + - '…' - ); - }; - - uppercase = (data: any) => - typeof data === 'string' ? data.toUpperCase() : data; - - numberToFixed = (data: any) => { - if (typeof data === 'number') { - return data.toFixed(2); - } else if (typeof data === 'string') { - const float = parseFloat(data); - if (isNaN(float)) return data; - else return float.toFixed(2); - } - }; } export default LxRenderer; diff --git a/lib/dto/Renderer.ts.bck b/lib/dto/Renderer.ts.bck new file mode 100644 index 0000000..0f53637 --- /dev/null +++ b/lib/dto/Renderer.ts.bck @@ -0,0 +1,136 @@ +import { LxConfigObject } from '@core/LyxeaDatatable'; +import '../utils/fixToFixed'; +import $ from 'jquery'; +import dayjs from 'dayjs'; + +export type RendederConfig = {}; + +type MultiRender = Array<(d: T, type: any, row: any, meta: any) => T>; + +/** Multi render function to handle array of modifiers */ +// original idea : https://datatables.net/forums/discussion/43160/multi-render-renderer +// @ts-ignore +$.fn.dataTable.render.multi = + (renderArray: MultiRender) => + (d: T, type: any, row: any, meta: any) => { + if (type !== 'display') { + // pour tri, filtrage, etc. => retourne valeur brute + return d; + } + + renderArray.forEach((render) => { + if (render) d = render(d, type, row, meta); + }); + return d; + }; + +class LxRenderer { + renderers: Array; + constructor(config: LxConfigObject) { + this.renderers = []; + config.headers && + config.headers.map((headers) => { + for (const config of headers.columns) { + if (!config.renderer) continue; + if (!Array.isArray(config.renderer)) + config.renderer = Array(config.renderer); + + const multiRender = config.renderer.map((renderer) => { + if (typeof renderer === 'string') { + if (renderer.startsWith('DATE_TO_FORMAT_')) { + return (data: any) => { + const format = renderer.split('_').pop(); + return dayjs(data).format(format); + }; + } + + switch (renderer) { + case 'DATE_DAY': + return (data: any) => dayjs(data).format('DD/MM/YYYY'); + case 'DATE': + return (data: any) => dayjs(data).format('DD/MM/YYYY HH:mm'); + case 'DATE_WITH_SECOND': + return (data: any) => + dayjs(data).format('DD/MM/YYYY HH:mm:ss'); + case 'LOCAL_NUMBER': + return (data: any) => data.toLocaleString(); + case 'BOOLEAN_YESNO': + return this.booleanString; + case 'NUMBER_FIXED_2': + return this.numberToFixed; + case 'NUMBER_2_DIGIT_MAX': + return this.number2DigitMax; + case 'CUT_LONG_TEXT': + return this.cutLongText; + case 'PARSE_INT': + return (data: any) => parseInt(data); + case 'CHECKBOX': + // @ts-ignore + config.checkboxes = { + selectRow: true, + }; + break; + case 'UPPERCASE': + return this.uppercase; + } + } + }); + + // @ts-ignore + config.render = $.fn.dataTable.render.multi(multiRender); + } + }); + } + + number2DigitMax(data: any | null) { + if (typeof data === 'number') { + if (data % 1 === 0) return data; + else return data.toFixed(2); + } else if (typeof data === 'string') { + const float = parseFloat(data); + if (isNaN(float)) return data; + if (float % 1 === 0) return data; + else return float.toFixed(2); + } else { + return data; + } + } + + booleanString = (data: boolean) => (data === true ? 'Oui' : 'Non'); + + cutLongText = (data: any) => { + if (data.length < 30) return data; + var esc = function (t: any) { + return t + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); + }; + + const shortened = esc(data).substr(0, 30); + const d = esc(data); + return ( + '' + + shortened + + '…' + ); + }; + + uppercase = (data: any) => + typeof data === 'string' ? data.toUpperCase() : data; + + numberToFixed = (data: any) => { + if (typeof data === 'number') { + return data.toFixed(2); + } else if (typeof data === 'string') { + const float = parseFloat(data); + if (isNaN(float)) return data; + else return float.toFixed(2); + } + }; +} + +export default LxRenderer; From 5699707ee29f59213d0862f9f8cdd826f9580619 Mon Sep 17 00:00:00 2001 From: Jonathan DURAND Date: Wed, 23 Apr 2025 13:56:49 +0200 Subject: [PATCH 09/10] prettier --- lib/core/Filters.ts | 67 +++++++++++++++++----------------- lib/core/LyxeaDatatable.ts | 74 +++++++++++++++++++++++--------------- lib/dom/FootersLxDom.ts | 26 +++++++------- lib/dto/Renderer.ts | 28 ++++++++------- 4 files changed, 107 insertions(+), 88 deletions(-) diff --git a/lib/core/Filters.ts b/lib/core/Filters.ts index 99a36f6..6e23bcf 100644 --- a/lib/core/Filters.ts +++ b/lib/core/Filters.ts @@ -13,48 +13,49 @@ class Filters { this.footerUiBuilder = new FooterLxDom(this.tableRef, config); } - async build(id = 'main_filter', className = 'main_filter'): Promise { + async build( + id = 'main_filter', + className = 'main_filter' + ): Promise { return this.footerUiBuilder.build(id, className); } init(dtInstance: DataTable, type: String) { // @ts-ignore - dtInstance.columns() - .every(function () { - // @ts-ignore - let title = this.footer().textContent; + dtInstance.columns().every(function () { + // @ts-ignore + let title = this.footer().textContent; - // Create input element - if(type == 'input'){ - // Create a container div for the input and icon - let container = document.createElement('div'); - container.classList.add('column_search_container'); - // Create the input element - let input = document.createElement('input'); - input.setAttribute("type", "text"); - input.classList.add('column_search'); - input.placeholder = title; - // Create the icon element - let icon = document.createElement('i'); - icon.classList.add('fa', 'fa-search'); - // Append the input and icon to the container - container.appendChild(input); - container.appendChild(icon); - // Replace the footer content with the container + // Create input element + if (type == 'input') { + // Create a container div for the input and icon + let container = document.createElement('div'); + container.classList.add('column_search_container'); + // Create the input element + let input = document.createElement('input'); + input.setAttribute('type', 'text'); + input.classList.add('column_search'); + input.placeholder = title; + // Create the icon element + let icon = document.createElement('i'); + icon.classList.add('fa', 'fa-search'); + // Append the input and icon to the container + container.appendChild(input); + container.appendChild(icon); + // Replace the footer content with the container + // @ts-ignore + this.footer().replaceChildren(container); + // Event listener for user input + input.addEventListener('keyup', () => { // @ts-ignore - this.footer().replaceChildren(container); - // Event listener for user input - input.addEventListener('keyup', () => { - // @ts-ignore - if (this.search() !== this.value) { - // @ts-ignore - this.search(input.value).draw(); - } - }); - } + if (this.search() !== this.value) { + // @ts-ignore + this.search(input.value).draw(); + } + }); + } }); } - } export default Filters; diff --git a/lib/core/LyxeaDatatable.ts b/lib/core/LyxeaDatatable.ts index fb264ce..8504563 100644 --- a/lib/core/LyxeaDatatable.ts +++ b/lib/core/LyxeaDatatable.ts @@ -6,7 +6,12 @@ import 'datatables.net-buttons/js/buttons.colVis.mjs'; import 'datatables.net-buttons/js/buttons.html5.mjs'; import 'datatables.net-buttons/js/buttons.print.mjs'; -import DataTable, { Config, ConfigColumns, ConfigButtons, ButtonConfig } from 'datatables.net-dt'; +import DataTable, { + Config, + ConfigColumns, + ConfigButtons, + ButtonConfig, +} from 'datatables.net-dt'; import AbstractLyxeaDatatable from './AbstractLyxeaDatatable'; import DtHeaders from './DtHeaders'; import Dao from '@dao/Dao'; @@ -41,7 +46,7 @@ export type CustomRenderer = | Array; export type ScrollYFitToScreen = { - addStaticMargin?: number; + addStaticMargin?: number; }; export interface CustomDatatableConfig extends Config { @@ -186,9 +191,9 @@ class LyxeaDatatable This allows you to generate the header with all the columns (and not just the columns defined in lxconfig). */ if (standardColumns?.length) { - lxConfig.headers = lxConfig.headers ? - [{ columns: [...standardColumns] }, ...lxConfig.headers] : - [{ columns: [...standardColumns] }]; + lxConfig.headers = lxConfig.headers + ? [{ columns: [...standardColumns] }, ...lxConfig.headers] + : [{ columns: [...standardColumns] }]; } new LxRenderer(lxConfig); const headersBuilder = this.#customColumnBuilder @@ -266,7 +271,9 @@ class LyxeaDatatable if (!this.config.buttons) this.config.buttons = this.#dtButtons.getDefaults(); - this.#dtButtons.parse(this.config.buttons as true | ConfigButtons | (string | ButtonConfig)[]); + this.#dtButtons.parse( + this.config.buttons as true | ConfigButtons | (string | ButtonConfig)[] + ); jquery(`${this._ref}`).on('init.dt', (e, settings) => { if (e.namespace !== 'dt') { @@ -278,8 +285,10 @@ class LyxeaDatatable */ if (lxConfig && lxConfig.filters) { this.filterColumn?.init(dtInstance, 'input'); - if(this.config?.scrollX){ - jquery(`${this._ref}_wrapper .dt-scroll-foot tfoot tr th`).removeAttr('data-dt-column'); + if (this.config?.scrollX) { + jquery(`${this._ref}_wrapper .dt-scroll-foot tfoot tr th`).removeAttr( + 'data-dt-column' + ); var footer = jquery(`${this._ref}_wrapper .dt-scroll-foot tfoot tr`); jquery(`${this._ref}_wrapper .dt-scroll-head thead`).append(footer); } else { @@ -293,10 +302,12 @@ class LyxeaDatatable * Fit scrollY to screen */ if (lxConfig?.scrollYFitToScreen) { - const scrollYConfig = this._convertToScrollYFitToScreenConfig(lxConfig.scrollYFitToScreen); - this._scrollYFitToScreen(scrollYConfig); - // Force redraw (FitToScreen has an effect on the draw event) - dtInstance.draw(); + const scrollYConfig = this._convertToScrollYFitToScreenConfig( + lxConfig.scrollYFitToScreen + ); + this._scrollYFitToScreen(scrollYConfig); + // Force redraw (FitToScreen has an effect on the draw event) + dtInstance.draw(); } }); /** @@ -325,20 +336,23 @@ class LyxeaDatatable for (const mutation of mutationsList) { for (const addedNode of mutation.addedNodes) { if (!(addedNode instanceof HTMLElement)) continue; - + // Si on trouve un .dtfh-floatingparent if (addedNode.classList.contains('dtfh-floatingparent')) { - const table = document.querySelector(this._ref); if (!table) return; - - const refClean = this._ref.startsWith('#') || this._ref.startsWith('.') - ? this._ref.slice(1) - : this._ref; + + const refClean = + this._ref.startsWith('#') || this._ref.startsWith('.') + ? this._ref.slice(1) + : this._ref; const expectedAriaDescribedBy = `${refClean}_info`; - + const innerTable = addedNode.querySelector('table'); - if (innerTable?.getAttribute('aria-describedby') === expectedAriaDescribedBy) { + if ( + innerTable?.getAttribute('aria-describedby') === + expectedAriaDescribedBy + ) { if (!table.contains(addedNode)) { table.insertBefore(addedNode, table.firstChild); } @@ -347,18 +361,18 @@ class LyxeaDatatable } } }); - + // Observe tout le document (ou tu peux cibler un conteneur plus précis) observer.observe(document.body, { childList: true, - subtree: true + subtree: true, }); } - _scrollYFitToScreen(config: ScrollYFitToScreen) { const self = this; - const staticMargin = config && config.addStaticMargin ? config.addStaticMargin : 0; + const staticMargin = + config && config.addStaticMargin ? config.addStaticMargin : 0; jquery(`${this._ref}`).on('draw.dt', (e, _) => { if (e.namespace !== 'dt') { return; @@ -395,7 +409,7 @@ class LyxeaDatatable (acc, node) => acc + (node as HTMLElement).offsetHeight, 0 ); - console.log("dtLayoutRowsHeight", dtLayoutRowsHeight); + console.log('dtLayoutRowsHeight', dtLayoutRowsHeight); const myHeight = window.innerHeight - // La taille de la fenêtre complete tabTop - // L'ordonnée du haut du tableau @@ -433,11 +447,13 @@ class LyxeaDatatable } // Créer une fonction utilitaire pour convertir le paramètre - _convertToScrollYFitToScreenConfig(config: boolean | ScrollYFitToScreen): ScrollYFitToScreen { + _convertToScrollYFitToScreenConfig( + config: boolean | ScrollYFitToScreen + ): ScrollYFitToScreen { if (typeof config === 'boolean' && config === true) { - return { - addStaticMargin: 0 - }; + return { + addStaticMargin: 0, + }; } return config as ScrollYFitToScreen; } diff --git a/lib/dom/FootersLxDom.ts b/lib/dom/FootersLxDom.ts index 9846934..eda6fb0 100644 --- a/lib/dom/FootersLxDom.ts +++ b/lib/dom/FootersLxDom.ts @@ -7,8 +7,7 @@ class FooterLxDom extends AbstractLxDom { footerRef: HTMLElement | null = null; config: LxConfigObject; - - constructor(ref: HTMLElement, config : LxConfigObject) { + constructor(ref: HTMLElement, config: LxConfigObject) { super(); this.tableRef = ref; this.config = config; @@ -18,23 +17,25 @@ class FooterLxDom extends AbstractLxDom { } appendTableFooter = () => { - if(!this.tableRef?.querySelector('tfoot')) + if (!this.tableRef?.querySelector('tfoot')) this.tableRef?.append(this.$element('tfoot', {})); - } + }; getFooterElement = (): HTMLElement | null => { this.footerRef = this.tableRef?.querySelector('tfoot') ?? null; return this.footerRef; }; - - async build(id = 'main_footer', className = 'main_footer'): Promise { + async build( + id = 'main_footer', + className = 'main_footer' + ): Promise { if (!this.footerRef) throw new DomError('Cannot select the dom footer ref'); if (!this.config.headers?.length) return this.footerRef; - + const groupFooterCells: Array = []; - this.config.headers?.forEach(header => { - header.columns?.forEach(column => { + this.config.headers?.forEach((header) => { + header.columns?.forEach((column) => { groupFooterCells.push( this.$element('th', { classList: ['colspan-border'], @@ -46,17 +47,16 @@ class FooterLxDom extends AbstractLxDom { style: column.style, }) ); - }) - }) + }); + }); const groupFooterWrapper = this.$element('tr', { attributes: { class: className, id: id }, children: groupFooterCells, - }) + }); this.footerRef?.append(groupFooterWrapper); return this.footerRef; } - } export default FooterLxDom; diff --git a/lib/dto/Renderer.ts b/lib/dto/Renderer.ts index 487628a..4f91bcc 100644 --- a/lib/dto/Renderer.ts +++ b/lib/dto/Renderer.ts @@ -9,7 +9,7 @@ const CustomRenderers = { return dayjs(data).format('DD/MM/YYYY'); } return data; - } + }, }, DATE_WITH_SECOND: { render: function (data: any, type: any) { @@ -17,7 +17,7 @@ const CustomRenderers = { return dayjs(data).format('DD/MM/YYYY HH:mm:ss'); } return data; - } + }, }, LOCAL_NUMBER: { render: function (data: any, type: any) { @@ -25,7 +25,7 @@ const CustomRenderers = { return data.toLocaleString(); } return data; - } + }, }, BOOLEAN_OUI_NON: { render: function (data: any, type: any) { @@ -64,15 +64,15 @@ const CustomRenderers = { PARSE_INT: { render: function (data: any) { return parseInt(data); - } + }, }, UPPERCASE: { render: (data: any) => - typeof data === 'string' ? data.toUpperCase() : data + typeof data === 'string' ? data.toUpperCase() : data, }, LOWERCASE: { render: (data: any) => - typeof data === 'string' ? data.toLowerCase() : data + typeof data === 'string' ? data.toLowerCase() : data, }, CUT_LONG_TEXT: { createdCell: function (td: any, cellData: any) { @@ -82,12 +82,12 @@ const CustomRenderers = { td.innerText = cellData.substring(0, 28) + '…'; } } - } + }, }, CHECKBOX: { checkboxes: { selectRow: true, - } + }, }, _dynamic: [ { @@ -101,11 +101,11 @@ const CustomRenderers = { return dayjs(data).format(format); } return data; - } + }, }; - } - } - ] + }, + }, + ], }; function resolveRenderer(nameOrObject: any) { @@ -132,7 +132,9 @@ class LxRenderer { for (const config of headers.columns) { if (!config.renderer) continue; if (Array.isArray(config.renderer)) { - console.warn('Multiple renderers are not supported yet. Please use a single renderer.'); + console.warn( + 'Multiple renderers are not supported yet. Please use a single renderer.' + ); config.renderer = config.renderer[0]; } const renderConf = resolveRenderer(config.renderer); From 181b4db88177303a8e7544dde7e2d3b133a6a331 Mon Sep 17 00:00:00 2001 From: Jonathan DURAND Date: Wed, 23 Apr 2025 14:18:12 +0200 Subject: [PATCH 10/10] commit dist... --- dist/core/AbstractLyxeaDatatable.d.ts | 1 + dist/core/DtButtons.d.ts | 1 + dist/core/DtColumns.d.ts | 3 +- dist/core/DtHeaders.d.ts | 1 + dist/core/Filters.d.ts | 16 +- dist/core/LyxeaDatatable.d.ts | 21 +- dist/dao/Dao.d.ts | 3 +- dist/dom/FiltersLxDom.d.ts | 8 +- dist/dom/FootersLxDom.d.ts | 3 +- dist/dom/HeadersLxDom.d.ts | 5 +- dist/dto/Renderer.d.ts | 8 +- dist/lx_dt.js | 55206 +++++++++++---------- dist/main.d.ts | 3 +- dist/plugins/action/Action.d.ts | 1 + dist/plugins/action/CustomAction.d.ts | 1 + dist/plugins/action/dom/ActionLxDom.d.ts | 3 +- dist/types/LxDt_interface.d.ts | 3 +- 17 files changed, 27717 insertions(+), 27570 deletions(-) diff --git a/dist/core/AbstractLyxeaDatatable.d.ts b/dist/core/AbstractLyxeaDatatable.d.ts index 39e6965..3230158 100644 --- a/dist/core/AbstractLyxeaDatatable.d.ts +++ b/dist/core/AbstractLyxeaDatatable.d.ts @@ -1,4 +1,5 @@ import { CustomDatatableConfig, ParsedConfig } from './LyxeaDatatable'; + declare class AbstractLyxeaDatatable { instance: any | null; constructor(); diff --git a/dist/core/DtButtons.d.ts b/dist/core/DtButtons.d.ts index 96d54dc..179b353 100644 --- a/dist/core/DtButtons.d.ts +++ b/dist/core/DtButtons.d.ts @@ -1,4 +1,5 @@ import { ButtonConfig, ConfigButtons } from 'datatables.net-dt'; + declare class DtButtons { getDefaults(): (string | { text: string; diff --git a/dist/core/DtColumns.d.ts b/dist/core/DtColumns.d.ts index 4a5a56a..3a8c833 100644 --- a/dist/core/DtColumns.d.ts +++ b/dist/core/DtColumns.d.ts @@ -1,5 +1,6 @@ import { ConfigColumns } from 'datatables.net-dt'; import { LxDefaultKeyDef } from './LyxeaDatatable'; + declare class DtColumns { #private; constructor(colsDef?: Array); @@ -8,7 +9,7 @@ declare class DtColumns { /** * @description set default value from columnsDefaultKey config key */ - static setDefaultKeyValue(defaultKeyConfig: LxDefaultKeyDef | null | undefined, colmunsConfig: Array): ConfigColumns[]; + static setDefaultKeyValue(defaultKeyConfig: (LxDefaultKeyDef | null) | undefined, colmunsConfig: Array): ConfigColumns[]; static mergeColumns(baseColumns: Array, customColumns: Array): Array; } export default DtColumns; diff --git a/dist/core/DtHeaders.d.ts b/dist/core/DtHeaders.d.ts index e6c63ba..c0c03e2 100644 --- a/dist/core/DtHeaders.d.ts +++ b/dist/core/DtHeaders.d.ts @@ -1,5 +1,6 @@ import { ConfigColumns } from 'datatables.net-dt'; import { CustomConfigColumns, LxConfigObject, LxHeaderDef, LxHeadersConfig } from './LyxeaDatatable'; + export declare enum HeaderGroup { NONE = "NONE" } diff --git a/dist/core/Filters.d.ts b/dist/core/Filters.d.ts index 881aefc..7036422 100644 --- a/dist/core/Filters.d.ts +++ b/dist/core/Filters.d.ts @@ -1,9 +1,13 @@ -import { CustomDatatableConfig } from './LyxeaDatatable'; -import DataTable from 'datatables.net-dt'; +import { LxConfigObject } from './LyxeaDatatable'; +import { default as DataTable } from 'datatables.net-dt'; +import { default as FooterLxDom } from '../dom/FootersLxDom'; + declare class Filters { - #private; - constructor(config: CustomDatatableConfig, instance?: DataTable); - init(headerEl?: HTMLElement): HTMLElement | undefined; - _filterEvent(e: Event): void; + tableRef: HTMLElement | null; + config: LxConfigObject; + footerUiBuilder: FooterLxDom; + constructor(ref: HTMLElement, config: LxConfigObject); + build(id?: string, className?: string): Promise; + init(dtInstance: DataTable, type: String): void; } export default Filters; diff --git a/dist/core/LyxeaDatatable.d.ts b/dist/core/LyxeaDatatable.d.ts index 0bbfd1e..fe46703 100644 --- a/dist/core/LyxeaDatatable.d.ts +++ b/dist/core/LyxeaDatatable.d.ts @@ -1,10 +1,12 @@ -import DataTable, { Config, ConfigColumns } from 'datatables.net-dt'; -import AbstractLyxeaDatatable from './AbstractLyxeaDatatable'; -import Dao from '../dao/Dao'; -import Dto from '../dto/Dto'; +import { default as DataTable, Config, ConfigColumns } from 'datatables.net-dt'; +import { default as AbstractLyxeaDatatable } from './AbstractLyxeaDatatable'; +import { default as Dao } from '../dao/Dao'; +import { default as Dto } from '../dto/Dto'; import { ILyxeaDatatable } from 'lib/types/LxDt_interface'; -import Transformers from '../dto/Transformers'; +import { default as Transformers } from '../dto/Transformers'; import { ActionArgs } from '../plugins/action/Action'; +import { default as Filters } from './Filters'; + /** * @types */ @@ -13,15 +15,20 @@ export interface CustomConfigColumns extends ConfigColumns { style?: Record>; } export type CustomRenderer = string | Function | Array | Array | Array; +export type ScrollYFitToScreen = { + addStaticMargin?: number; +}; export interface CustomDatatableConfig extends Config { lxConfig?: LxConfigObject; data?: Array; } export type LxConfigObject = { + keepFixedHeaderInDT?: boolean; url?: string; headers?: LxHeadersConfig; filters?: boolean; handleBootrapTabChange?: boolean; + scrollYFitToScreen?: boolean | ScrollYFitToScreen; row_action?: { width: string; className?: string; @@ -56,6 +63,7 @@ declare class LyxeaDatatable extends AbstractLyxeaDatatable implements ILyxea dao: Dao; dto: Dto; tranformer: Transformers; + filterColumn?: Filters; constructor(ref: string, config?: CustomDatatableConfig); /** * Get the default datatable config if not set @@ -69,6 +77,9 @@ declare class LyxeaDatatable extends AbstractLyxeaDatatable implements ILyxea */ init(): Promise>; __filterDataWithKey(): void; + __keepFixedHeaderInDT(): void; + _scrollYFitToScreen(config: ScrollYFitToScreen): void; handleBootrapTabChange(instance: DataTable): void; + _convertToScrollYFitToScreenConfig(config: boolean | ScrollYFitToScreen): ScrollYFitToScreen; } export default LyxeaDatatable; diff --git a/dist/dao/Dao.d.ts b/dist/dao/Dao.d.ts index ddd4c0e..7c50434 100644 --- a/dist/dao/Dao.d.ts +++ b/dist/dao/Dao.d.ts @@ -1,4 +1,5 @@ -import State from '../utils/State'; +import { default as State } from '../utils/State'; + export type DaoState = { loading: boolean; data: Array | null; diff --git a/dist/dom/FiltersLxDom.d.ts b/dist/dom/FiltersLxDom.d.ts index a7991a2..00494ce 100644 --- a/dist/dom/FiltersLxDom.d.ts +++ b/dist/dom/FiltersLxDom.d.ts @@ -1,5 +1,9 @@ -import AbstractLxDom from './AbstractLxDom'; -import DataTable from 'datatables.net'; +import { default as AbstractLxDom } from './AbstractLxDom'; +import { default as DataTable } from 'datatables.net'; + +/** + * Deprecated + */ declare class FiltersLxDom extends AbstractLxDom { #private; constructor(header: Node); diff --git a/dist/dom/FootersLxDom.d.ts b/dist/dom/FootersLxDom.d.ts index fa0c5af..afe3ad2 100644 --- a/dist/dom/FootersLxDom.d.ts +++ b/dist/dom/FootersLxDom.d.ts @@ -1,5 +1,6 @@ -import AbstractLxDom from './AbstractLxDom'; +import { default as AbstractLxDom } from './AbstractLxDom'; import { LxConfigObject } from '../core/LyxeaDatatable'; + declare class FooterLxDom extends AbstractLxDom { tableRef: HTMLElement | null; footerRef: HTMLElement | null; diff --git a/dist/dom/HeadersLxDom.d.ts b/dist/dom/HeadersLxDom.d.ts index 4338e4c..ce52ba0 100644 --- a/dist/dom/HeadersLxDom.d.ts +++ b/dist/dom/HeadersLxDom.d.ts @@ -1,6 +1,7 @@ -import DtHeaders from '../core/DtHeaders'; -import AbstractLxDom from './AbstractLxDom'; +import { default as DtHeaders } from '../core/DtHeaders'; +import { default as AbstractLxDom } from './AbstractLxDom'; import { LxConfigObject } from '../core/LyxeaDatatable'; + export type HeaderLxDomArgs = { headers: DtHeaders; config: LxConfigObject; diff --git a/dist/dto/Renderer.d.ts b/dist/dto/Renderer.d.ts index 75887dd..d7c7a0f 100644 --- a/dist/dto/Renderer.d.ts +++ b/dist/dto/Renderer.d.ts @@ -1,12 +1,6 @@ import { LxConfigObject } from '../core/LyxeaDatatable'; -export type RendederConfig = {}; + declare class LxRenderer { - renderers: Array; constructor(config: LxConfigObject); - number2DigitMax(data: any | null): any; - booleanString: (data: boolean) => "Oui" | "Non"; - cutLongText: (data: any) => any; - uppercase: (data: any) => any; - numberToFixed: (data: any) => string | undefined; } export default LxRenderer; diff --git a/dist/lx_dt.js b/dist/lx_dt.js index e6278ef..ba5f6d6 100644 --- a/dist/lx_dt.js +++ b/dist/lx_dt.js @@ -1,57 +1,94 @@ -import Ca from "jquery"; -/*! DataTables 2.0.0 +var Td = Object.defineProperty; +var vf = Object.getOwnPropertySymbols; +var Fd = Object.prototype.hasOwnProperty, Id = Object.prototype.propertyIsEnumerable; +var Is = (a, p, g) => p in a ? Td(a, p, { enumerable: !0, configurable: !0, writable: !0, value: g }) : a[p] = g, Vi = (a, p) => { + for (var g in p || (p = {})) + Fd.call(p, g) && Is(a, g, p[g]); + if (vf) + for (var g of vf(p)) + Id.call(p, g) && Is(a, g, p[g]); + return a; +}; +var mr = (a, p, g) => (Is(a, typeof p != "symbol" ? p + "" : p, g), g), Ds = (a, p, g) => { + if (!p.has(a)) + throw TypeError("Cannot " + g); +}; +var un = (a, p, g) => (Ds(a, p, "read from private field"), g ? g.call(a) : p.get(a)), ta = (a, p, g) => { + if (p.has(a)) + throw TypeError("Cannot add the same private member more than once"); + p instanceof WeakSet ? p.add(a) : p.set(a, g); +}, Rn = (a, p, g, w) => (Ds(a, p, "write to private field"), w ? w.call(a, g) : p.set(a, g), g); +var Lo = (a, p, g) => (Ds(a, p, "access private method"), g); +var ea = (a, p, g) => new Promise((w, L) => { + var B = (t) => { + try { + d(g.next(t)); + } catch (i) { + L(i); + } + }, f = (t) => { + try { + d(g.throw(t)); + } catch (i) { + L(i); + } + }, d = (t) => t.done ? w(t.value) : Promise.resolve(t.value).then(B, f); + d((g = g.apply(a, p)).next()); +}); +import Wn from "jquery"; +/*! DataTables 2.2.2 * © SpryMedia Ltd - datatables.net/license */ -var Xt = Ca, ge = function(s, p) { - if (ge.factory(s, p)) - return ge; - if (this instanceof ge) - return Xt(s).DataTable(p); - p = s; - var b = this, A = p === void 0, R = this.length; - return A && (p = {}), this.api = function() { - return new Sr(this); +var Xt = Wn, de = function(a, p) { + if (de.factory(a, p)) + return de; + if (this instanceof de) + return Xt(a).DataTable(p); + p = a; + var g = this, w = p === void 0, L = this.length; + return w && (p = {}), this.api = function() { + return new Fr(this); }, this.each(function() { - var B = {}, u = R > 1 ? ( + var B = {}, f = L > 1 ? ( // optimisation for single table case - $0(B, p, !0) - ) : p, d = 0, t, o = this.getAttribute("id"), r = !1, n = ge.defaults, i = Xt(this); + Cf(B, p, !0) + ) : p, d = 0, t, i = this.getAttribute("id"), r = de.defaults, n = Xt(this); if (this.nodeName.toLowerCase() != "table") { - qn(null, 0, "Non-table node initialisation (" + this.nodeName + ")", 2); + ca(null, 0, "Non-table node initialisation (" + this.nodeName + ")", 2); return; } - Xt(this).trigger("options.dt", u), G0(n), cf(n.column), Ba(n, n, !0), Ba(n.column, n.column, !0), Ba(n, Xt.extend(u, i.data()), !0); - var f = ge.settings; - for (d = 0, t = f.length; d < t; d++) { - var l = f[d]; - if (l.nTable == this || l.nTHead && l.nTHead.parentNode == this || l.nTFoot && l.nTFoot.parentNode == this) { - var c = u.bRetrieve !== void 0 ? u.bRetrieve : n.bRetrieve, h = u.bDestroy !== void 0 ? u.bDestroy : n.bDestroy; - if (A || c) - return l.oInstance; - if (h) { - new ge.Api(l).destroy(); + Xt(this).trigger("options.dt", f), gf(r), Wf(r.column), za(r, r, !0), za(r.column, r.column, !0), za(r, Xt.extend(f, n.data()), !0); + var o = de.settings; + for (d = 0, t = o.length; d < t; d++) { + var h = o[d]; + if (h.nTable == this || h.nTHead && h.nTHead.parentNode == this || h.nTFoot && h.nTFoot.parentNode == this) { + var u = f.bRetrieve !== void 0 ? f.bRetrieve : r.bRetrieve, l = f.bDestroy !== void 0 ? f.bDestroy : r.bDestroy; + if (w || u) + return h.oInstance; + if (l) { + new de.Api(h).destroy(); break; } else { - qn(l, 0, "Cannot reinitialise DataTable", 3); + ca(h, 0, "Cannot reinitialise DataTable", 3); return; } } - if (l.sTableId == this.id) { - f.splice(d, 1); + if (h.sTableId == this.id) { + o.splice(d, 1); break; } } - (o === null || o === "") && (o = "DataTables_Table_" + ge.ext._unique++, this.id = o); - var a = Xt.extend(!0, {}, ge.models.oSettings, { - sDestroyWidth: i[0].style.width, - sInstance: o, - sTableId: o, + (i === null || i === "") && (i = "DataTables_Table_" + de.ext._unique++, this.id = i); + var c = Xt.extend(!0, {}, de.models.oSettings, { + sDestroyWidth: n[0].style.width, + sInstance: i, + sTableId: i, colgroup: Xt("").prependTo(this), - fastData: function(C, E, F) { - return ta(a, C, E, F); + fastData: function(I, O, M) { + return ha(c, I, O, M); } }); - a.nTable = this, a.oInit = u, f.push(a), a.api = new Sr(a), a.oInstance = b.length === 1 ? b : i.dataTable(), G0(u), u.aLengthMenu && !u.iDisplayLength && (u.iDisplayLength = Array.isArray(u.aLengthMenu[0]) ? u.aLengthMenu[0][0] : Xt.isPlainObject(u.aLengthMenu[0]) ? u.aLengthMenu[0].value : u.aLengthMenu[0]), u = $0(Xt.extend(!0, {}, n), u), La(a.oFeatures, u, [ + c.nTable = this, c.oInit = f, o.push(c), c.api = new Fr(c), c.oInstance = g.length === 1 ? g : n.dataTable(), gf(f), f.aLengthMenu && !f.iDisplayLength && (f.iDisplayLength = Array.isArray(f.aLengthMenu[0]) ? f.aLengthMenu[0][0] : Xt.isPlainObject(f.aLengthMenu[0]) ? f.aLengthMenu[0].value : f.aLengthMenu[0]), f = Cf(Xt.extend(!0, {}, r), f), Ha(c.oFeatures, f, [ "bPaginate", "bLengthChange", "bFilter", @@ -63,7 +100,7 @@ var Xt = Ca, ge = function(s, p) { "bSortClasses", "bServerSide", "bDeferRender" - ]), La(a, u, [ + ]), Ha(c, f, [ "ajax", "fnFormatNumber", "sServerMethod", @@ -82,84 +119,86 @@ var Xt = Ca, ge = function(s, p) { "rowId", "caption", "layout", + "orderDescReverse", + "typeDetect", ["iCookieDuration", "iStateDuration"], // backwards compat ["oSearch", "oPreviousSearch"], ["aoSearchCols", "aoPreSearchCols"], ["iDisplayLength", "_iDisplayLength"] - ]), La(a.oScroll, u, [ + ]), Ha(c.oScroll, f, [ ["sScrollX", "sX"], ["sScrollXInner", "sXInner"], ["sScrollY", "sY"], ["bScrollCollapse", "bCollapse"] - ]), La(a.oLanguage, u, "fnInfoCallback"), $n(a, "aoDrawCallback", u.fnDrawCallback), $n(a, "aoStateSaveParams", u.fnStateSaveParams), $n(a, "aoStateLoadParams", u.fnStateLoadParams), $n(a, "aoStateLoaded", u.fnStateLoaded), $n(a, "aoRowCallback", u.fnRowCallback), $n(a, "aoRowCreatedCallback", u.fnCreatedRow), $n(a, "aoHeaderCallback", u.fnHeaderCallback), $n(a, "aoFooterCallback", u.fnFooterCallback), $n(a, "aoInitComplete", u.fnInitComplete), $n(a, "aoPreDrawCallback", u.fnPreDrawCallback), a.rowIdFn = ui(u.rowId), Xh(a); - var v = a.oClasses; - Xt.extend(v, ge.ext.classes, u.oClasses), i.addClass(v.table), a.oFeatures.bPaginate || (u.iDisplayStart = 0), a.iInitDisplayStart === void 0 && (a.iInitDisplayStart = u.iDisplayStart, a._iDisplayStart = u.iDisplayStart); - var y = a.oLanguage; - Xt.extend(!0, y, u.oLanguage), y.sUrl ? (Xt.ajax({ - dataType: "json", - url: y.sUrl, - success: function(C) { - Ba(n.oLanguage, C), Xt.extend(!0, y, C, a.oInit.oLanguage), Nr(a, null, "i18n", [a]), Fo(a); - }, - error: function() { - qn(a, 0, "i18n file loading error", 21), Fo(a); - } - }), r = !0) : Nr(a, null, "i18n", [a]); - var g = [], e = this.getElementsByTagName("thead"), m = xf(a, e[0]); - if (u.aoColumns) - g = u.aoColumns; - else if (m.length) - for (d = 0, t = m[0].length; d < t; d++) - g.push(null); - for (d = 0, t = g.length; d < t; d++) - hf(a); - Kh(a, u.aoColumnDefs, g, m, function(C, E) { - gs(a, C, E); + ]), Ha(c.oLanguage, f, "fnInfoCallback"), ua(c, "aoDrawCallback", f.fnDrawCallback), ua(c, "aoStateSaveParams", f.fnStateSaveParams), ua(c, "aoStateLoadParams", f.fnStateLoadParams), ua(c, "aoStateLoaded", f.fnStateLoaded), ua(c, "aoRowCallback", f.fnRowCallback), ua(c, "aoRowCreatedCallback", f.fnCreatedRow), ua(c, "aoHeaderCallback", f.fnHeaderCallback), ua(c, "aoFooterCallback", f.fnFooterCallback), ua(c, "aoInitComplete", f.fnInitComplete), ua(c, "aoPreDrawCallback", f.fnPreDrawCallback), c.rowIdFn = wi(f.rowId), Ld(c); + var s = c.oClasses; + Xt.extend(s, de.ext.classes, f.oClasses), n.addClass(s.table), c.oFeatures.bPaginate || (f.iDisplayStart = 0), c.iInitDisplayStart === void 0 && (c.iInitDisplayStart = f.iDisplayStart, c._iDisplayStart = f.iDisplayStart); + var v = f.iDeferLoading; + if (v !== null) { + c.deferLoading = !0; + var y = Array.isArray(v); + c._iRecordsDisplay = y ? v[0] : v, c._iRecordsTotal = y ? v[1] : v; + } + var x = [], e = this.getElementsByTagName("thead"), b = Yf(c, e[0]); + if (f.aoColumns) + x = f.aoColumns; + else if (b.length) + for (d = 0, t = b[0].length; d < t; d++) + x.push(null); + for (d = 0, t = x.length; d < t; d++) + Hf(c); + kd(c, f.aoColumnDefs, x, b, function(I, O) { + zs(c, I, O); }); - var w = i.children("tbody").find("tr").eq(0); - if (w.length) { - var D = function(C, E) { - return C.getAttribute("data-" + E) !== null ? E : null; + var A = n.children("tbody").find("tr").eq(0); + if (A.length) { + var P = function(I, O) { + return I.getAttribute("data-" + O) !== null ? O : null; }; - Xt(w[0]).children("th, td").each(function(C, E) { - var F = a.aoColumns[C]; - if (F || qn(a, 0, "Incorrect column count", 18), F.mData === C) { - var x = D(E, "sort") || D(E, "order"), P = D(E, "filter") || D(E, "search"); - (x !== null || P !== null) && (F.mData = { - _: C + ".display", - sort: x !== null ? C + ".@data-" + x : void 0, - type: x !== null ? C + ".@data-" + x : void 0, - filter: P !== null ? C + ".@data-" + P : void 0 - }, F._isArrayHost = !0, gs(a, C)); + Xt(A[0]).children("th, td").each(function(I, O) { + var M = c.aoColumns[I]; + if (M || ca(c, 0, "Incorrect column count", 18), M.mData === I) { + var N = P(O, "sort") || P(O, "order"), G = P(O, "filter") || P(O, "search"); + (N !== null || G !== null) && (M.mData = { + _: I + ".display", + sort: N !== null ? I + ".@data-" + N : void 0, + type: N !== null ? I + ".@data-" + N : void 0, + filter: G !== null ? I + ".@data-" + G : void 0 + }, M._isArrayHost = !0, zs(c, I)); } }); } - var I = a.oFeatures, T = function() { - if (u.aaSorting === void 0) { - var C = a.aaSorting; - for (d = 0, t = C.length; d < t; d++) - C[d][1] = a.aoColumns[d].asSorting[0]; + ua(c, "aoDrawCallback", is); + var D = c.oFeatures; + if (f.bStateSave && (D.bStateSave = !0), f.aaSorting === void 0) { + var E = c.aaSorting; + for (d = 0, t = E.length; d < t; d++) + E[d][1] = c.aoColumns[d].asSorting[0]; + } + js(c), ua(c, "aoDrawCallback", function() { + (c.bSorted || sa(c) === "ssp" || D.bDeferRender) && js(c); + }); + var T = n.children("caption"); + c.caption && (T.length === 0 && (T = Xt("").appendTo(n)), T.html(c.caption)), T.length && (T[0]._captionSide = T.css("caption-side"), c.captionNode = T[0]), e.length === 0 && (e = Xt("").appendTo(n)), c.nTHead = e[0]; + var C = n.children("tbody"); + C.length === 0 && (C = Xt("").insertAfter(e)), c.nTBody = C[0]; + var F = n.children("tfoot"); + F.length === 0 && (F = Xt("").appendTo(n)), c.nTFoot = F[0], c.aiDisplay = c.aiDisplayMaster.slice(), c.bInitialised = !0; + var m = c.oLanguage; + Xt.extend(!0, m, f.oLanguage), m.sUrl ? Xt.ajax({ + dataType: "json", + url: m.sUrl, + success: function(I) { + za(r.oLanguage, I), Xt.extend(!0, m, I, c.oInit.oLanguage), zr(c, null, "i18n", [c], !0), Ho(c); + }, + error: function() { + ca(c, 0, "i18n file loading error", 21), Ho(c); } - ms(a), $n(a, "aoDrawCallback", function() { - (a.bSorted || Zn(a) === "ssp" || I.bDeferRender) && ms(a); - }); - var E = i.children("caption"); - a.caption && (E.length === 0 && (E = Xt("").appendTo(i)), E.html(a.caption)), E.length && (E[0]._captionSide = E.css("caption-side"), a.captionNode = E[0]), e.length === 0 && (e = Xt("").appendTo(i)), a.nTHead = e[0], Xt("tr", e).addClass(v.thead.row); - var F = i.children("tbody"); - F.length === 0 && (F = Xt("").insertAfter(e)), a.nTBody = F[0]; - var x = i.children("tfoot"); - if (x.length === 0 && (x = Xt("").appendTo(i)), a.nTFoot = x[0], Xt("tr", x).addClass(v.tfoot.row), u.aaData) - for (d = 0; d < u.aaData.length; d++) - Za(a, u.aaData[d]); - else - Zn(a) == "dom" && Ps(a, Xt(a.nTBody).children("tr")); - a.aiDisplay = a.aiDisplayMaster.slice(), a.bInitialised = !0, r === !1 && Fo(a); - }; - $n(a, "aoDrawCallback", Wo), u.bStateSave ? (I.bStateSave = !0, dd(a, u, T)) : T(); - }), b = null, this; + }) : (zr(c, null, "i18n", [c], !0), Ho(c)); + }), g = null, this; }; -ge.ext = Vr = { +de.ext = En = { /** * Buttons. For use with the Buttons extension for DataTables. This is * defined here so other extensions can define buttons regardless of load @@ -579,7 +618,7 @@ ge.ext = Vr = { * @type function * @depreciated Since 1.10 */ - fnVersionCheck: ge.fnVersionCheck, + fnVersionCheck: de.fnVersionCheck, /** * Index for what 'this' index API functions should use * @type int @@ -591,19 +630,19 @@ ge.ext = Vr = { * @type string * @deprecated Since v1.10 */ - sVersion: ge.version + sVersion: de.version }; -Xt.extend(Vr, { - afnFiltering: Vr.search, - aTypes: Vr.type.detect, - ofnSearch: Vr.type.search, - oSort: Vr.type.order, - afnSortData: Vr.order, - aoFeatures: Vr.feature, - oStdClasses: Vr.classes, - oPagination: Vr.pager +Xt.extend(En, { + afnFiltering: En.search, + aTypes: En.type.detect, + ofnSearch: En.type.search, + oSort: En.type.order, + afnSortData: En.order, + aoFeatures: En.feature, + oStdClasses: En.classes, + oPagination: En.pager }); -Xt.extend(ge.ext.classes, { +Xt.extend(de.ext.classes, { container: "dt-container", empty: { row: "dt-empty" @@ -611,6 +650,15 @@ Xt.extend(ge.ext.classes, { info: { container: "dt-info" }, + layout: { + row: "dt-layout-row", + cell: "dt-layout-cell", + tableRow: "dt-layout-table", + tableCell: "", + start: "dt-layout-start", + end: "dt-layout-end", + full: "dt-layout-full" + }, length: { container: "dt-length", select: "dt-input" @@ -659,113 +707,123 @@ Xt.extend(ge.ext.classes, { active: "current", button: "dt-paging-button", container: "dt-paging", - disabled: "disabled" + disabled: "disabled", + nav: "" } }); -var Vr, Sr, Ke, Xr, ls = {}, Wh = /[\r\n\u2028]/g, Cs = /<.*?>/g, Hh = /^\d{2,4}[./-]\d{1,2}[./-]\d{1,2}([T ]{1}\d{1,2}[:.]\d{2}([.:]\d{2})?)?$/, jh = new RegExp("(\\" + ["/", ".", "*", "+", "?", "|", "(", ")", "[", "]", "{", "}", "\\", "$", "^", "-"].join("|\\") + ")", "g"), Es = /['\u00A0,$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfkɃΞ]/gi, Aa = function(s) { - return !s || s === !0 || s === "-"; -}, sf = function(s) { - var p = parseInt(s, 10); - return !isNaN(p) && isFinite(s) ? p : null; -}, ff = function(s, p) { - return ls[p] || (ls[p] = new RegExp(ys(p), "g")), typeof s == "string" && p !== "." ? s.replace(/\./g, "").replace(ls[p], ".") : s; -}, Ts = function(s, p, b) { - var A = typeof s, R = A === "string"; - return A === "number" || A === "bigint" || Aa(s) ? !0 : (p && R && (s = ff(s, p)), b && R && (s = s.replace(Es, "")), !isNaN(parseFloat(s)) && isFinite(s)); -}, Gh = function(s) { - return Aa(s) || typeof s == "string"; -}, lf = function(s, p, b) { - if (Aa(s)) +var En, Fr, Qe, Qr, Ps = {}, Dd = /[\r\n\u2028]/g, Js = /<([^>]*>)/g, Pd = Math.pow(2, 28), pf = /^\d{2,4}[./-]\d{1,2}[./-]\d{1,2}([T ]{1}\d{1,2}[:.]\d{2}([.:]\d{2})?)?$/, Od = new RegExp("(\\" + ["/", ".", "*", "+", "?", "|", "(", ")", "[", "]", "{", "}", "\\", "$", "^", "-"].join("|\\") + ")", "g"), Qs = /['\u00A0,$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfkɃΞ]/gi, ia = function(a) { + return !a || a === !0 || a === "-"; +}, kf = function(a) { + var p = parseInt(a, 10); + return !isNaN(p) && isFinite(a) ? p : null; +}, Uf = function(a, p) { + return Ps[p] || (Ps[p] = new RegExp(Hs(p), "g")), typeof a == "string" && p !== "." ? a.replace(/\./g, "").replace(Ps[p], ".") : a; +}, Qi = function(a, p, g, w) { + var L = typeof a, B = L === "string"; + return L === "number" || L === "bigint" || w && ia(a) ? !0 : (p && B && (a = Uf(a, p)), g && B && (a = a.replace(Qs, "")), !isNaN(parseFloat(a)) && isFinite(a)); +}, Bd = function(a) { + return ia(a) || typeof a == "string"; +}, Go = function(a, p, g, w) { + if (w && ia(a)) return !0; - if (typeof s == "string" && s.match(/<(input|select)/i)) + if (typeof a == "string" && a.match(/<(input|select)/i)) return null; - var A = Gh(s); - return A && Ts(li(s), p, b) ? !0 : null; -}, Xn = function(s, p, b) { - var A = [], R = 0, B = s.length; - if (b !== void 0) - for (; R < B; R++) - s[R] && s[R][p] && A.push(s[R][p][b]); + var L = Bd(a); + return L && Qi(Pa(a), p, g, w) ? !0 : null; +}, Ln = function(a, p, g) { + var w = [], L = 0, B = a.length; + if (g !== void 0) + for (; L < B; L++) + a[L] && a[L][p] && w.push(a[L][p][g]); else - for (; R < B; R++) - s[R] && A.push(s[R][p]); - return A; -}, Gi = function(s, p, b, A) { - var R = [], B = 0, u = p.length; - if (A !== void 0) - for (; B < u; B++) - s[p[B]][b] && R.push(s[p[B]][b][A]); + for (; L < B; L++) + a[L] && w.push(a[L][p]); + return w; +}, eo = function(a, p, g, w) { + var L = [], B = 0, f = p.length; + if (w !== void 0) + for (; B < f; B++) + a[p[B]] && a[p[B]][g] && L.push(a[p[B]][g][w]); else - for (; B < u; B++) - s[p[B]] && R.push(s[p[B]][b]); - return R; -}, Pa = function(s, p) { - var b = [], A; - p === void 0 ? (p = 0, A = s) : (A = p, p = s); - for (var R = p; R < A; R++) - b.push(R); - return b; -}, uf = function(s) { - for (var p = [], b = 0, A = s.length; b < A; b++) - s[b] && p.push(s[b]); + for (; B < f; B++) + a[p[B]] && L.push(a[p[B]][g]); + return L; +}, Ua = function(a, p) { + var g = [], w; + p === void 0 ? (p = 0, w = a) : (w = p, p = a); + for (var L = p; L < w; L++) + g.push(L); + return g; +}, zf = function(a) { + for (var p = [], g = 0, w = a.length; g < w; g++) + a[g] && p.push(a[g]); return p; -}, li = function(s) { - return s.replace(Cs, "").replace(/