diff --git a/public/js/components/Cis/Profil/Profil.js b/public/js/components/Cis/Profil/Profil.js index 0df4a86c2..5e656da77 100644 --- a/public/js/components/Cis/Profil/Profil.js +++ b/public/js/components/Cis/Profil/Profil.js @@ -24,7 +24,7 @@ Vue.$collapseFormatter = function (data) { let item2 = document.createElement("div"); item2.classList.add("col-6"); - item.innerHTML = "placeholder"; + item.innerHTML = "..."; item2.innerHTML = col.value ? col.value : "-"; list.appendChild(item); diff --git a/public/js/components/filter/Filter.js b/public/js/components/filter/Filter.js index 2c8cf59be..f25d07e7f 100644 --- a/public/js/components/filter/Filter.js +++ b/public/js/components/filter/Filter.js @@ -22,6 +22,9 @@ import TableDownload from './Table/Download.js'; import collapseAutoClose from '../../directives/collapseAutoClose.js'; import moduleLayoutFitDataStretchFrozen from '../../tabulator/layouts/fitDataStretchFrozen.js'; +import InternalToExternalEventBroadcastModule from "../../tabulator/customModules/InternalToExternalEventBroadcastModule.js" + +import { debounce } from "../../helpers/DebounceHelper.js"; import ApiFilter from '../../api/factory/filter.js'; import ApiPhrases from '../../api/factory/phrasen.js'; @@ -123,6 +126,27 @@ export const CoreFilterCmpt = { group: false, page: false, }, + collapsedHeadingLocalizationTimer: null, + localizeCollapsedColumnHeadings: + debounce( + () => { + const columnHeadings = this.tabulator?.getLang()?.columns; + if (!columnHeadings) return; + + this.$refs.table + .querySelectorAll(".collapsedColumnHeading") + .forEach((collapsedColumnHeadingElement) => { + const field = + collapsedColumnHeadingElement.getAttribute( + "tabulator-column-field", + ); + if (!field?.length) return; + + collapsedColumnHeadingElement.innerHTML = + columnHeadings[field]; + }); + }, 200) + , }; }, computed: { @@ -368,6 +392,11 @@ export const CoreFilterCmpt = { this.localizeCollapsedColumnHeadings(); } }); + this.tabulator.on('layoutRefreshed', () => { + if (tabulatorOptions.locale && tabulatorOptions.responsiveLayoutCollapseFormatter) { + this.localizeCollapsedColumnHeadings(); + } + }); }, async configureTabulatorLocalizations(tabulatorOptions) { tabulatorOptions.locale = this.$p.user_language.value; @@ -472,21 +501,6 @@ export const CoreFilterCmpt = { return tabulatorOptions; }, - async localizeCollapsedColumnHeadings() { - const columnHeadings = this.tabulator?.getLang()?.columns; - if (!columnHeadings) return; - - this.$refs.table - .querySelectorAll(".collapsedColumnHeading") - .forEach((collapsedColumnHeadingElement) => { - const field = - collapsedColumnHeadingElement.getAttribute("tabulator-column-field"); - if (!field?.length) return; - - collapsedColumnHeadingElement.innerHTML = - columnHeadings[field]; - }); - }, updateTabulator() { if (this.tabulator) { if (this.tableBuilt) @@ -814,6 +828,8 @@ export const CoreFilterCmpt = { alert('"nwNewEntry" listener is mandatory when sideMenu is true'); this.uuid = _uuid++; this.$emit('uuidDefined', this.uuid) + + Tabulator.registerModule(InternalToExternalEventBroadcastModule); }, mounted() { this.initTabulator().then(() => { diff --git a/public/js/helpers/DebounceHelper.js b/public/js/helpers/DebounceHelper.js new file mode 100644 index 000000000..af5e80019 --- /dev/null +++ b/public/js/helpers/DebounceHelper.js @@ -0,0 +1,7 @@ +export const debounce = (callback, wait) => { + let timeoutId = null; + return (context) => { + window.clearTimeout(timeoutId); + timeoutId = window.setTimeout(() => callback(), wait); + } +} \ No newline at end of file diff --git a/public/js/helpers/StringHelpers.js b/public/js/helpers/StringHelpers.js index a67d0138f..e68d1d381 100644 --- a/public/js/helpers/StringHelpers.js +++ b/public/js/helpers/StringHelpers.js @@ -1,4 +1,49 @@ export function capitalize(string) { - if (!string) return ''; + if (!string) return ""; return string[0].toUpperCase() + string.slice(1); -} \ No newline at end of file +} + +export function convertCase(string, from, to) { + const possibleCases = ["kebab", "snake", "camel"]; + if ( + from === to || + !possibleCases.includes(from) || + !possibleCases.includes(to) + ) + return string; + + const individualWords = + from === "kebab" + ? string.split("-") + : from === "snake" + ? string.split("_") + : splitWordsInCamelCase(string); + + const formattedIndividualWords = ["snake", "kebab"].includes(to) + ? individualWords.map((word) => word.toLowerCase()) + : individualWords.map((word, index) => { + if (!index) return word.toLowerCase(); + return word.slice(0, 1).toUpperCase() + word.slice(1).toLowerCase(); + }); + + const joinCharacter = to === "snake" ? "_" : to === "kebab" ? "-" : ""; + return formattedIndividualWords.join(joinCharacter); +} + +function splitWordsInCamelCase(string) { + const lastUpperCaseLetterIndex = string + .split("") + .findLastIndex((character) => { + return character.toUpperCase() === character; + }); + + if (lastUpperCaseLetterIndex < 1) { + return [string]; + } + + let splitWords = splitWordsInCamelCase( + string.slice(0, lastUpperCaseLetterIndex), + ); + splitWords.push(string.slice(lastUpperCaseLetterIndex)); + return splitWords; +} diff --git a/public/js/tabulator/customModules/InternalToExternalEventBroadcastModule.js b/public/js/tabulator/customModules/InternalToExternalEventBroadcastModule.js new file mode 100644 index 000000000..85099d9ce --- /dev/null +++ b/public/js/tabulator/customModules/InternalToExternalEventBroadcastModule.js @@ -0,0 +1,32 @@ +// changes within tabulator are often not adequately broadcast to the external component +// this module exposes tabulator's internal events +// if external event name is not specified, the dispatched external event will be the camelCase version of the kebab-case internal event + +import Module from "../../../../vendor/olifolkerd/tabulator5/src/js/core/Module.js"; +import { convertCase } from "../../helpers/StringHelpers.js"; + +export default class InternalToExternalEventBroadcastModule extends Module { + static moduleName = "internalToExternalEventBroadcastModule"; + static moduleInitNumber = 1; + + constructor(table) { + super(table); + + this.eventsToBroadcast = [ + { + internal: "layout-refreshed", + external: null, + }, + ]; + } + + initialize() { + this.eventsToBroadcast.forEach((event) => { + this.subscribe(event.internal, () => { + this.dispatchExternal(event.external ?? convertCase(event.internal, "kebab", "camel")); + }); + }); + } + + +}