import "./_template-customizer/_template-customizer.scss"; import customizerMarkup from "./_template-customizer/_template-customizer.html?raw"; const CSS_FILENAME_PATTERN = "%name%.scss"; const CONTROLS = [ "rtl", "style", "headerType", "contentLayout", "layoutCollapsed", "showDropdownOnHover", "layoutNavbarOptions", "layoutFooterFixed", "themes", ]; const STYLES = ["light", "dark", "system"]; const NAVBAR_OPTIONS = ["sticky", "static", "hidden"]; let layoutNavbarVar; const cl = document.documentElement.classList; if (cl.contains("layout-navbar-fixed")) layoutNavbarVar = "sticky"; else if (cl.contains("layout-navbar-hidden")) layoutNavbarVar = "hidden"; else layoutNavbarVar = "static"; const DISPLAY_CUSTOMIZER = true; const DEFAULT_THEME = document.getElementsByTagName("HTML")[0].getAttribute("data-theme") || 0; const DEFAULT_STYLE = cl.contains("dark-style") ? "dark" : "light"; const DEFAULT_TEXT_DIR = document.documentElement.getAttribute("dir") === "rtl"; const DEFAULT_MENU_COLLAPSED = !!cl.contains("layout-menu-collapsed"); const DEFAULT_SHOW_DROPDOWN_ON_HOVER = true; const DEFAULT_NAVBAR_FIXED = layoutNavbarVar; const DEFAULT_CONTENT_LAYOUT = cl.contains("layout-wide") ? "wide" : "compact"; const DEFAULT_FOOTER_FIXED = !!cl.contains("layout-footer-fixed"); let headerType; if (cl.contains("layout-menu-offcanvas")) { headerType = "static-offcanvas"; } else if (cl.contains("layout-menu-fixed")) { headerType = "fixed"; } else if (cl.contains("layout-menu-fixed-offcanvas")) { headerType = "fixed-offcanvas"; } else { headerType = "static"; } const DEFAULT_LAYOUT_TYPE = headerType; class TemplateCustomizer { constructor({ cssPath, themesPath, cssFilenamePattern, displayCustomizer, controls, defaultTextDir, defaultHeaderType, defaultContentLayout, defaultMenuCollapsed, defaultShowDropdownOnHover, defaultNavbarType, defaultFooterFixed, styles, navbarOptions, defaultStyle, availableContentLayouts, availableDirections, availableStyles, availableThemes, availableLayouts, availableHeaderTypes, availableNavbarOptions, defaultTheme, pathResolver, onSettingsChange, lang, }) { if (this._ssr) return; if (!window.Helpers) throw new Error("window.Helpers required."); this.settings = {}; this.settings.cssPath = cssPath; this.settings.themesPath = themesPath; this.settings.cssFilenamePattern = cssFilenamePattern || CSS_FILENAME_PATTERN; this.settings.displayCustomizer = typeof displayCustomizer !== "undefined" ? displayCustomizer : DISPLAY_CUSTOMIZER; this.settings.controls = controls || CONTROLS; this.settings.defaultTextDir = defaultTextDir === "rtl" ? true : false || DEFAULT_TEXT_DIR; this.settings.defaultHeaderType = defaultHeaderType || DEFAULT_LAYOUT_TYPE; this.settings.defaultMenuCollapsed = typeof defaultMenuCollapsed !== "undefined" ? defaultMenuCollapsed : DEFAULT_MENU_COLLAPSED; this.settings.defaultContentLayout = typeof defaultContentLayout !== "undefined" ? defaultContentLayout : DEFAULT_CONTENT_LAYOUT; this.settings.defaultShowDropdownOnHover = typeof defaultShowDropdownOnHover !== "undefined" ? defaultShowDropdownOnHover : DEFAULT_SHOW_DROPDOWN_ON_HOVER; this.settings.defaultNavbarType = typeof defaultNavbarType !== "undefined" ? defaultNavbarType : DEFAULT_NAVBAR_FIXED; this.settings.defaultFooterFixed = typeof defaultFooterFixed !== "undefined" ? defaultFooterFixed : DEFAULT_FOOTER_FIXED; this.settings.availableDirections = availableDirections || TemplateCustomizer.DIRECTIONS; this.settings.availableStyles = availableStyles || TemplateCustomizer.STYLES; this.settings.availableThemes = availableThemes || TemplateCustomizer.THEMES; this.settings.availableHeaderTypes = availableHeaderTypes || TemplateCustomizer.HEADER_TYPES; this.settings.availableContentLayouts = availableContentLayouts || TemplateCustomizer.CONTENT; this.settings.availableLayouts = availableLayouts || TemplateCustomizer.LAYOUTS; this.settings.availableNavbarOptions = availableNavbarOptions || TemplateCustomizer.NAVBAR_OPTIONS; this.settings.defaultTheme = this._getDefaultTheme( typeof defaultTheme !== "undefined" ? defaultTheme : DEFAULT_THEME, ); this.settings.styles = styles || STYLES; this.settings.navbarOptions = navbarOptions || NAVBAR_OPTIONS; this.settings.defaultStyle = defaultStyle || DEFAULT_STYLE; this.settings.lang = lang || "en"; this.pathResolver = pathResolver || ((p) => p); if (this.settings.styles.length < 2) { const i = this.settings.controls.indexOf("style"); if (i !== -1) { this.settings.controls = this.settings.controls .slice(0, i) .concat(this.settings.controls.slice(i + 1)); } } this.settings.onSettingsChange = typeof onSettingsChange === "function" ? onSettingsChange : () => {}; this._loadSettings(); this._listeners = []; this._controls = {}; this._initDirection(); this._initStyle(); this._initTheme(); this.setLayoutType(this.settings.headerType, false); this.setContentLayout(this.settings.contentLayout, false); this.setDropdownOnHover(this.settings.showDropdownOnHover, false); this.setLayoutNavbarOption(this.settings.layoutNavbarOptions, false); this.setLayoutFooterFixed(this.settings.layoutFooterFixed, false); this._setup(); } setRtl(rtl) { if (!this._hasControls("rtl")) return; this._setSetting("Rtl", String(rtl)); this._setCookie("direction", rtl, 365); window.location.reload(); } setContentLayout(contentLayout, updateStorage = true) { if (!this._hasControls("contentLayout")) return; this.settings.contentLayout = contentLayout; if (updateStorage) this._setSetting("contentLayout", contentLayout); window.Helpers.setContentLayout(contentLayout); if (updateStorage) this.settings.onSettingsChange.call(this, this.settings); } setStyle(style) { const layoutName = this._getLayoutName(); const isAdmin = !layoutName.includes("front"); this._setSetting("Style", style); const modeCookieName = isAdmin ? "admin-mode" : "front-mode"; const colorPrefCookieName = isAdmin ? "admin-colorPref" : "front-colorPref"; if (style !== "" && this._checkCookie(modeCookieName)) { if (style === "system") { this._setCookie(modeCookieName, "system", 365); if (window.matchMedia("(prefers-color-scheme: dark)").matches) { this._setCookie(colorPrefCookieName, "dark", 365); } else { this._setCookie(colorPrefCookieName, "light", 365); } } else { if (style === "dark") { this._setCookie(modeCookieName, "dark", 365); this._setCookie(colorPrefCookieName, "dark", 365); } else { this._setCookie(modeCookieName, "light", 365); this._setCookie(colorPrefCookieName, "light", 365); } } } else { this._setCookie(modeCookieName, style || "light", 365); } window.location.reload(); } setTheme(themeName, updateStorage = true, cb = null) { if (!this._hasControls("themes")) return; const theme = this._getThemeByName(themeName); if (!theme) return; this.settings.theme = theme; if (updateStorage) this._setSetting("Theme", themeName); this._setCookie("theme", themeName, 365); const themeUrl = this.pathResolver( this.settings.themesPath + this.settings.cssFilenamePattern.replace( "%name%", themeName + (this.settings.style !== "light" ? `-${this.settings.style}` : ""), ), ); this._loadStylesheets( { [themeUrl]: document.querySelector( ".template-customizer-theme-css", ), }, cb || (() => {}), ); if (updateStorage) this.settings.onSettingsChange.call(this, this.settings); } setLayoutType(pos, updateStorage = true) { if (!this._hasControls("headerType")) return; if ( pos !== "static" && pos !== "static-offcanvas" && pos !== "fixed" && pos !== "fixed-offcanvas" ) return; this.settings.headerType = pos; if (updateStorage) this._setSetting("LayoutType", pos); window.Helpers.setPosition( pos === "fixed" || pos === "fixed-offcanvas", pos === "static-offcanvas" || pos === "fixed-offcanvas", ); if (updateStorage) this.settings.onSettingsChange.call(this, this.settings); // Perfectscrollbar change on Layout change let menuScroll = window.Helpers.menuPsScroll; const PerfectScrollbarLib = window.PerfectScrollbar; if ( this.settings.headerType === "fixed" || this.settings.headerType === "fixed-offcanvas" ) { // Set perfectscrollbar wheelPropagation false for fixed layout if (PerfectScrollbarLib && menuScroll) { window.Helpers.menuPsScroll.destroy(); menuScroll = new PerfectScrollbarLib( document.querySelector(".menu-inner"), { suppressScrollX: true, wheelPropagation: false, }, ); window.Helpers.menuPsScroll = menuScroll; } } else if (menuScroll) { // Destroy perfectscrollbar for static layout window.Helpers.menuPsScroll.destroy(); } } setDropdownOnHover(open, updateStorage = true) { if (!this._hasControls("showDropdownOnHover")) return; this.settings.showDropdownOnHover = open; if (updateStorage) this._setSetting("ShowDropdownOnHover", open); if (window.Helpers.mainMenu) { window.Helpers.mainMenu.destroy(); config.showDropdownOnHover = open; const { Menu } = window; window.Helpers.mainMenu = new Menu( document.getElementById("layout-menu"), { orientation: "horizontal", closeChildren: true, showDropdownOnHover: config.showDropdownOnHover, }, ); } if (updateStorage) this.settings.onSettingsChange.call(this, this.settings); } setLayoutNavbarOption(navbarType, updateStorage = true) { if (!this._hasControls("layoutNavbarOptions")) return; this.settings.layoutNavbarOptions = navbarType; if (updateStorage) this._setSetting("FixedNavbarOption", navbarType); window.Helpers.setNavbar(navbarType); if (updateStorage) this.settings.onSettingsChange.call(this, this.settings); } setLayoutFooterFixed(fixed, updateStorage = true) { // if (!this._hasControls('layoutFooterFixed')) return this.settings.layoutFooterFixed = fixed; if (updateStorage) this._setSetting("FixedFooter", fixed); window.Helpers.setFooterFixed(fixed); if (updateStorage) this.settings.onSettingsChange.call(this, this.settings); } setLang(lang, updateStorage = true, force = false) { if (lang === this.settings.lang && !force) return; if (!TemplateCustomizer.LANGUAGES[lang]) throw new Error(`Language "${lang}" not found!`); const t = TemplateCustomizer.LANGUAGES[lang]; [ "panel_header", "panel_sub_header", "theming_header", "style_label", "style_switch_light", "style_switch_dark", "layout_header", "layout_label", "layout_header_label", "content_label", "layout_static", "layout_offcanvas", "layout_fixed", "layout_fixed_offcanvas", "layout_dd_open_label", "layout_navbar_label", "layout_footer_label", "misc_header", "theme_label", "direction_label", ].forEach((key) => { const el = this.container.querySelector( `.template-customizer-t-${key}`, ); // eslint-disable-next-line no-unused-expressions el && (el.textContent = t[key]); }); const tt = t.themes || {}; const themes = this.container.querySelectorAll( ".template-customizer-theme-item", ) || []; for (let i = 0, l = themes.length; i < l; i++) { const themeName = themes[i].querySelector( 'input[type="radio"]', ).value; themes[i].querySelector( ".template-customizer-theme-name", ).textContent = tt[themeName] || this._getThemeByName(themeName).title; } this.settings.lang = lang; if (updateStorage) this._setSetting("Lang", lang); if (updateStorage) this.settings.onSettingsChange.call(this, this.settings); } // Update theme settings control update() { if (this._ssr) return; const hasNavbar = !!document.querySelector(".layout-navbar"); const hasMenu = !!document.querySelector(".layout-menu"); const hasHorizontalMenu = !!document.querySelector( ".layout-menu-horizontal.menu, .layout-menu-horizontal .menu", ); const isLayout1 = !!document.querySelector( ".layout-wrapper.layout-navbar-full", ); const hasFooter = !!document.querySelector(".content-footer"); if (this._controls.showDropdownOnHover) { if (hasMenu) { this._controls.showDropdownOnHover.setAttribute( "disabled", "disabled", ); this._controls.showDropdownOnHover.classList.add("disabled"); } else { this._controls.showDropdownOnHover.removeAttribute("disabled"); this._controls.showDropdownOnHover.classList.remove("disabled"); } } if (this._controls.layoutNavbarOptions) { if (!hasNavbar) { this._controls.layoutNavbarOptions.setAttribute( "disabled", "disabled", ); this._controls.layoutNavbarOptionsW.classList.add("disabled"); } else { this._controls.layoutNavbarOptions.removeAttribute("disabled"); this._controls.layoutNavbarOptionsW.classList.remove( "disabled", ); } // Horizontal menu fixed layout - disabled fixed navbar switch if ( hasHorizontalMenu && hasNavbar && this.settings.headerType === "fixed" ) { this._controls.layoutNavbarOptions.setAttribute( "disabled", "disabled", ); this._controls.layoutNavbarOptionsW.classList.add("disabled"); } } if (this._controls.layoutFooterFixed) { if (!hasFooter) { this._controls.layoutFooterFixed.setAttribute( "disabled", "disabled", ); this._controls.layoutFooterFixedW.classList.add("disabled"); } else { this._controls.layoutFooterFixed.removeAttribute("disabled"); this._controls.layoutFooterFixedW.classList.remove("disabled"); } } if (this._controls.headerType) { // ? Uncomment If using offcanvas layout /* if (!hasMenu) { this._controls.headerType.querySelector('[value="static-offcanvas"]').setAttribute('disabled', 'disabled') this._controls.headerType.querySelector('[value="fixed-offcanvas"]').setAttribute('disabled', 'disabled') } else { this._controls.headerType.querySelector('[value="static-offcanvas"]').removeAttribute('disabled') this._controls.headerType.querySelector('[value="fixed-offcanvas"]').removeAttribute('disabled') } */ // Disable menu layouts options if menu (vertical or horizontal) is not there // if ((!hasNavbar && !hasMenu) || (!hasMenu && !isLayout1)) { if (hasMenu || hasHorizontalMenu) { // (Updated condition) this._controls.headerType.removeAttribute("disabled"); } else { this._controls.headerType.setAttribute("disabled", "disabled"); } } } // Clear local storage clearLocalStorage() { if (this._ssr) return; const layoutName = this._getLayoutName(); const keysToRemove = [ "Theme", "Style", "LayoutCollapsed", "FixedNavbarOption", "LayoutType", "contentLayout", "Rtl", "Lang", ]; keysToRemove.forEach((key) => { const localStorageKey = `templateCustomizer-${layoutName}--${key}`; localStorage.removeItem(localStorageKey); }); this._showResetBtnNotification(false); } // Clear local storage destroy() { if (this._ssr) return; this._cleanup(); this.settings = null; this.container.parentNode.removeChild(this.container); this.container = null; } _loadSettings() { // Get settings // const cl = document.documentElement.classList; const rtl = this._getSetting("Rtl"); const style = this._getSetting("Style"); const theme = this._getSetting("Theme"); const contentLayout = this._getSetting("contentLayout"); const collapsedMenu = this._getSetting("LayoutCollapsed"); // Value will be set from main.js const dropdownOnHover = this._getSetting("ShowDropdownOnHover"); // Value will be set from main.js const navbarOption = this._getSetting("FixedNavbarOption"); const fixedFooter = this._getSetting("FixedFooter"); const lType = this._getSetting("LayoutType"); const layoutName = this._getLayoutName(); const isAdmin = !layoutName.includes("front"); const modeCookieName = isAdmin ? "admin-mode" : "front-mode"; const colorPrefCookieName = isAdmin ? "admin-colorPref" : "front-colorPref"; if ( rtl !== "" || style !== "" || theme !== "" || contentLayout !== "" || collapsedMenu !== "" || navbarOption !== "" || lType !== "" ) { this._showResetBtnNotification(true); } else { this._showResetBtnNotification(false); } let type; if ( lType !== "" && ["static", "static-offcanvas", "fixed", "fixed-offcanvas"].indexOf( lType, ) !== -1 ) { type = lType; } else { type = this.settings.defaultHeaderType; } this.settings.headerType = type; // ! Set settings by following priority: Local Storage, Theme Config, HTML Classes this.settings.rtl = this._checkCookie("direction") ? this._getCookie("direction") : rtl !== "" ? rtl === "true" : this.settings.defaultTextDir; this.settings.stylesOpt = this.settings.styles.indexOf(style) !== -1 ? style : this.settings.defaultStyle; if (this._getCookie(modeCookieName) === "system") { if (window.matchMedia("(prefers-color-scheme: dark)").matches) { this._setCookie(colorPrefCookieName, "dark", 365); this.settings.style = "dark"; } else { this._setCookie(colorPrefCookieName, "light", 365); this.settings.style = "light"; } } else { if (this.settings.stylesOpt === "system") { if (window.matchMedia("(prefers-color-scheme: dark)").matches) { this.settings.style = "dark"; } else { this.settings.style = "light"; } } else { this.settings.style = this.settings.styles.indexOf(style) !== -1 ? style : this.settings.stylesOpt; } } this.settings.contentLayout = contentLayout !== "" ? contentLayout : this.settings.defaultContentLayout; this.settings.layoutCollapsed = collapsedMenu !== "" ? collapsedMenu === "true" : this.settings.defaultMenuCollapsed; this.settings.showDropdownOnHover = dropdownOnHover !== "" ? dropdownOnHover === "true" : this.settings.defaultShowDropdownOnHover; let navType; if ( navbarOption !== "" && ["static", "sticky", "hidden"].indexOf(navbarOption) !== -1 ) { navType = navbarOption; } else { navType = this.settings.defaultNavbarType; } this.settings.layoutNavbarOptions = navType; this.settings.layoutFooterFixed = fixedFooter !== "" ? fixedFooter === "true" : this.settings.defaultFooterFixed; if (this._checkCookie("theme")) { this.settings.theme = this._getThemeByName( this._getCookie("theme"), true, ); } else { this.settings.theme = this._getThemeByName( this._getSetting("Theme"), true, ); } // Filter options depending on available controls if (!this._hasControls("rtl")) this.settings.rtl = document.documentElement.getAttribute("dir") === "rtl"; if (!this._hasControls("style")) this.settings.style = cl.contains("dark-style") ? "dark" : "light"; if (!this._hasControls("contentLayout")) this.settings.contentLayout = null; if (!this._hasControls("headerType")) this.settings.headerType = null; if (!this._hasControls("layoutCollapsed")) this.settings.layoutCollapsed = null; if (!this._hasControls("layoutNavbarOptions")) this.settings.layoutNavbarOptions = null; if (!this._hasControls("themes")) this.settings.theme = null; } // Setup theme settings controls and events _setup(_container = document) { // Function to create customizer elements const createOptionElement = ( nameVal, title, inputName, isDarkStyle, image, ) => { image = image || nameVal; return this._getElementFromString(`
`); }; this._cleanup(); this.container = this._getElementFromString(customizerMarkup); // Customizer visibility condition // const customizerW = this.container; if (this.settings.displayCustomizer) customizerW.setAttribute("style", "visibility: visible"); else customizerW.setAttribute("style", "visibility: hidden"); // Open btn // const openBtn = this.container.querySelector( ".template-customizer-open-btn", ); const openBtnCb = () => { this.container.classList.add("template-customizer-open"); this.update(); if (this._updateInterval) clearInterval(this._updateInterval); this._updateInterval = setInterval(() => { this.update(); }, 500); }; openBtn.addEventListener("click", openBtnCb); this._listeners.push([openBtn, "click", openBtnCb]); // Reset btn // const resetBtn = this.container.querySelector( ".template-customizer-reset-btn", ); const resetBtnCb = () => { const layoutName = this._getLayoutName(); if (layoutName.includes("front")) { this._deleteCookie("front-mode"); this._deleteCookie("front-colorPref"); } else { this._deleteCookie("admin-mode"); this._deleteCookie("admin-colorPref"); } this.clearLocalStorage(); window.location.reload(); this._deleteCookie("colorPref"); this._deleteCookie("theme"); this._deleteCookie("direction"); }; resetBtn.addEventListener("click", resetBtnCb); this._listeners.push([resetBtn, "click", resetBtnCb]); // Close btn // const closeBtn = this.container.querySelector( ".template-customizer-close-btn", ); const closeBtnCb = () => { this.container.classList.remove("template-customizer-open"); if (this._updateInterval) { clearInterval(this._updateInterval); this._updateInterval = null; } }; closeBtn.addEventListener("click", closeBtnCb); this._listeners.push([closeBtn, "click", closeBtnCb]); // Style const styleW = this.container.querySelector( ".template-customizer-style", ); const styleOpt = styleW.querySelector( ".template-customizer-styles-options", ); if (!this._hasControls("style")) { styleW.parentNode.removeChild(styleW); } else { this.settings.availableStyles.forEach((style) => { const styleEl = createOptionElement( style.name, style.title, "customRadioIcon", cl.contains("dark-style"), ); styleOpt.appendChild(styleEl); }); styleOpt .querySelector(`input[value="${this.settings.stylesOpt}"]`) .setAttribute("checked", "checked"); // styleCb const styleCb = (e) => { this._loadingState(true); this.setStyle(e.target.value, true, () => { this._loadingState(false); }); }; styleOpt.addEventListener("change", styleCb); this._listeners.push([styleOpt, "change", styleCb]); } // Theme const themesW = this.container.querySelector( ".template-customizer-themes", ); const themesWInner = themesW.querySelector( ".template-customizer-themes-options", ); if (!this._hasControls("themes")) { themesW.parentNode.removeChild(themesW); } else { this.settings.availableThemes.forEach((theme) => { let image = ""; if (theme.name === "theme-semi-dark") { image = `semi-dark`; } else if (theme.name === "theme-bordered") { image = `border`; } else { image = `default`; } const themeEl = createOptionElement( theme.name, theme.title, "themeRadios", cl.contains("dark-style"), image, ); themesWInner.appendChild(themeEl); }); themesWInner .querySelector(`input[value="${this.settings.theme.name}"]`) .setAttribute("checked", "checked"); const themeCb = (e) => { this._loading = true; this._loadingState(true, true); this.setTheme(e.target.value, true, () => { this._loading = false; this._loadingState(false, true); }); }; themesWInner.addEventListener("change", themeCb); this._listeners.push([themesWInner, "change", themeCb]); } const themingW = this.container.querySelector( ".template-customizer-theming", ); if (!this._hasControls("style") && !this._hasControls("themes")) { themingW.parentNode.removeChild(themingW); } // Layout wrapper const layoutW = this.container.querySelector( ".template-customizer-layout", ); if ( !this._hasControls( "rtl headerType contentLayout layoutCollapsed layoutNavbarOptions", true, ) ) { layoutW.parentNode.removeChild(layoutW); } else { // RTL // const directionW = this.container.querySelector( ".template-customizer-directions", ); // ? Hide RTL control in following 2 case if (!this._hasControls("rtl") || !rtlSupport) { directionW.parentNode.removeChild(directionW); } else { const directionOpt = directionW.querySelector( ".template-customizer-directions-options", ); this.settings.availableDirections.forEach((dir) => { const dirEl = createOptionElement( dir.name, dir.title, "directionRadioIcon", cl.contains("dark-style"), ); directionOpt.appendChild(dirEl); }); directionOpt .querySelector( `input[value="${this.settings.rtl === "true" ? "rtl" : "ltr"}"]`, ) .setAttribute("checked", "checked"); const rtlCb = (e) => { this._loadingState(true); // For demo purpose, we will use EN as LTR and AR as RTL Language this._getSetting("Lang") === "ar" ? this._setSetting("Lang", "en") : this._setSetting("Lang", "ar"); this.setRtl(e.target.value === "rtl", true, () => { this._loadingState(false); }); if (e.target.value === "rtl") { window.location.href = baseUrl + "lang/ar"; } else { window.location.href = baseUrl + "lang/en"; } }; directionOpt.addEventListener("change", rtlCb); this._listeners.push([directionOpt, "change", rtlCb]); } // Header Layout Type const headerTypeW = this.container.querySelector( ".template-customizer-headerOptions", ); const templateName = document.documentElement .getAttribute("data-template") .split("-"); if (!this._hasControls("headerType")) { headerTypeW.parentNode.removeChild(headerTypeW); } else { const headerOpt = headerTypeW.querySelector( ".template-customizer-header-options", ); setTimeout(() => { if (templateName.includes("vertical")) { headerTypeW.parentNode.removeChild(headerTypeW); } }, 100); this.settings.availableHeaderTypes.forEach((header) => { const headerEl = createOptionElement( header.name, header.title, "headerRadioIcon", cl.contains("dark-style"), `horizontal-${header.name}`, ); headerOpt.appendChild(headerEl); }); headerOpt .querySelector(`input[value="${this.settings.headerType}"]`) .setAttribute("checked", "checked"); const headerTypeCb = (e) => { this.setLayoutType(e.target.value); }; headerOpt.addEventListener("change", headerTypeCb); this._listeners.push([headerOpt, "change", headerTypeCb]); } // CONTENT // const contentWrapper = this.container.querySelector( ".template-customizer-content", ); // ? Hide RTL control in following 2 case if (!this._hasControls("contentLayout")) { contentWrapper.parentNode.removeChild(contentWrapper); } else { const contentOpt = contentWrapper.querySelector( ".template-customizer-content-options", ); this.settings.availableContentLayouts.forEach((content) => { const contentEl = createOptionElement( content.name, content.title, "contentRadioIcon", cl.contains("dark-style"), ); contentOpt.appendChild(contentEl); }); contentOpt .querySelector( `input[value="${this.settings.contentLayout}"]`, ) .setAttribute("checked", "checked"); const contentCb = (e) => { this._loading = true; this._loadingState(true, true); this.setContentLayout(e.target.value, true, () => { this._loading = false; this._loadingState(false, true); }); }; contentOpt.addEventListener("change", contentCb); this._listeners.push([contentOpt, "change", contentCb]); } // Layouts Collapsed: Expanded, Collapsed const layoutCollapsedW = this.container.querySelector( ".template-customizer-layouts", ); if (!this._hasControls("layoutCollapsed")) { layoutCollapsedW.parentNode.removeChild(layoutCollapsedW); } else { setTimeout(() => { if (document.querySelector(".layout-menu-horizontal")) { layoutCollapsedW.parentNode.removeChild( layoutCollapsedW, ); } }, 100); const layoutCollapsedOpt = layoutCollapsedW.querySelector( ".template-customizer-layouts-options", ); this.settings.availableLayouts.forEach((layoutOpt) => { const layoutsEl = createOptionElement( layoutOpt.name, layoutOpt.title, "layoutsRadios", cl.contains("dark-style"), ); layoutCollapsedOpt.appendChild(layoutsEl); }); layoutCollapsedOpt .querySelector( `input[value="${this.settings.layoutCollapsed ? "collapsed" : "expanded"}"]`, ) .setAttribute("checked", "checked"); const layoutCb = (e) => { window.Helpers.setCollapsed( e.target.value === "collapsed", true, ); this._setSetting( "LayoutCollapsed", e.target.value === "collapsed", ); }; layoutCollapsedOpt.addEventListener("change", layoutCb); this._listeners.push([layoutCollapsedOpt, "change", layoutCb]); } // Layout Navbar Options const navbarOption = this.container.querySelector( ".template-customizer-layoutNavbarOptions", ); if (!this._hasControls("layoutNavbarOptions")) { navbarOption.parentNode.removeChild(navbarOption); } else { setTimeout(() => { if (templateName.includes("horizontal")) { navbarOption.parentNode.removeChild(navbarOption); } }, 100); const navbarTypeOpt = navbarOption.querySelector( ".template-customizer-navbar-options", ); this.settings.availableNavbarOptions.forEach((navbarOpt) => { const navbarEl = createOptionElement( navbarOpt.name, navbarOpt.title, "navbarOptionRadios", cl.contains("dark-style"), ); navbarTypeOpt.appendChild(navbarEl); }); // check navbar option from settings navbarTypeOpt .querySelector( `input[value="${this.settings.layoutNavbarOptions}"]`, ) .setAttribute("checked", "checked"); const navbarCb = (e) => { this._loading = true; this._loadingState(true, true); this.setLayoutNavbarOption(e.target.value, true, () => { this._loading = false; this._loadingState(false, true); }); }; navbarTypeOpt.addEventListener("change", navbarCb); this._listeners.push([navbarTypeOpt, "change", navbarCb]); } } setTimeout(() => { const layoutCustom = this.container.querySelector( ".template-customizer-layout", ); if (document.querySelector(".menu-vertical")) { if ( !this._hasControls( "rtl contentLayout layoutCollapsed layoutNavbarOptions", true, ) ) { if (layoutCustom) { layoutCustom.parentNode.removeChild(layoutCustom); } } } else if (document.querySelector(".menu-horizontal")) { if (!this._hasControls("rtl contentLayout headerType", true)) { if (layoutCustom) { layoutCustom.parentNode.removeChild(layoutCustom); } } } }, 100); // Set language this.setLang(this.settings.lang, false, true); // Append container if (_container === document) { if (_container.body) { _container.body.appendChild(this.container); } else { window.addEventListener("DOMContentLoaded", () => _container.body.appendChild(this.container), ); } } else { _container.appendChild(this.container); } } _initDirection() { if (this._hasControls("rtl")) { document.documentElement.setAttribute( "dir", this._checkCookie("direction") ? this._getCookie("direction") === "true" ? "rtl" : "ltr" : this.settings.rtl ? "rtl" : "ltr", ); } } // Init template styles _initStyle() { if (!this._hasControls("style")) return; const { style } = this.settings; this._insertStylesheet( "template-customizer-core-css", this.pathResolver( this.settings.cssPath + this.settings.cssFilenamePattern.replace( "%name%", `core${style !== "light" ? `-${style}` : ""}`, ), ), ); // ? Uncomment if needed /* this._insertStylesheet( 'template-customizer-bootstrap-css', this.pathResolver( this.settings.cssPath + this.settings.cssFilenamePattern.replace('%name%', `bootstrap${style !== 'light' ? `-${style}` : ''}`) ) ) this._insertStylesheet( 'template-customizer-bsextended-css', this.pathResolver( this.settings.cssPath + this.settings.cssFilenamePattern.replace( '%name%', `bootstrap-extended${style !== 'light' ? `-${style}` : ''}` ) ) ) this._insertStylesheet( 'template-customizer-components-css', this.pathResolver( this.settings.cssPath + this.settings.cssFilenamePattern.replace('%name%', `components${style !== 'light' ? `-${style}` : ''}`) ) ) this._insertStylesheet( 'template-customizer-colors-css', this.pathResolver( this.settings.cssPath + this.settings.cssFilenamePattern.replace('%name%', `colors${style !== 'light' ? `-${style}` : ''}`) ) ) */ const classesToRemove = style === "light" ? ["dark-style"] : ["light-style"]; classesToRemove.forEach((cls) => { document.documentElement.classList.remove(cls); }); document.documentElement.classList.add(`${style}-style`); } // Init theme style _initTheme() { if (this._hasControls("themes")) { this._insertStylesheet( "template-customizer-theme-css", this.pathResolver( this.settings.themesPath + this.settings.cssFilenamePattern.replace( "%name%", this.settings.theme.name + (this.settings.style !== "light" ? `-${this.settings.style}` : ""), ), ), ); } else { // If theme control is not enabled, get the current theme from localstorage else display default theme const theme = this._getSetting("Theme"); this._insertStylesheet( "template-customizer-theme-css", this.pathResolver( this.settings.themesPath + this.settings.cssFilenamePattern.replace( "%name%", theme ? theme : this.settings.defaultTheme.name + (this.settings.style !== "light" ? `-${this.settings.style}` : ""), ), ), ); } } _loadStylesheet(href, className) { const link = document.createElement("link"); link.rel = "stylesheet"; link.type = "text/css"; link.href = href; link.className = className; document.head.appendChild(link); } _insertStylesheet(className, href) { const curLink = document.querySelector(`.${className}`); if ( typeof document.documentMode === "number" && document.documentMode < 11 ) { if (!curLink) return; if (href === curLink.getAttribute("href")) return; const link = document.createElement("link"); link.setAttribute("rel", "stylesheet"); link.setAttribute("type", "text/css"); link.className = className; link.setAttribute("href", href); curLink.parentNode.insertBefore(link, curLink.nextSibling); } else { this._loadStylesheet(href, className); } if (curLink) { curLink.parentNode.removeChild(curLink); } } _loadStylesheets(stylesheets, cb) { const paths = Object.keys(stylesheets); const count = paths.length; let loaded = 0; function loadStylesheet(path, curLink, _cb = () => {}) { const link = document.createElement("link"); link.setAttribute("href", path); link.setAttribute("rel", "stylesheet"); link.setAttribute("type", "text/css"); link.className = curLink.className; const sheet = "sheet" in link ? "sheet" : "styleSheet"; const cssRules = "sheet" in link ? "cssRules" : "rules"; let intervalId; const timeoutId = setTimeout(() => { clearInterval(intervalId); clearTimeout(timeoutId); if (curLink.parentNode.contains(link)) { curLink.parentNode.removeChild(link); } _cb(false, path); }, 15000); intervalId = setInterval(() => { try { if (link[sheet] && link[sheet][cssRules].length) { clearInterval(intervalId); clearTimeout(timeoutId); curLink.parentNode.removeChild(curLink); _cb(true); } } catch (e) { // Catch error } }, 10); curLink.setAttribute("href", link.href); } function stylesheetCallBack() { if ((loaded += 1) >= count) { cb(); } } for (let i = 0; i < paths.length; i++) { loadStylesheet( paths[i], stylesheets[paths[i]], stylesheetCallBack(), ); } } _loadingState(enable, themes) { this.container.classList[enable ? "add" : "remove"]( `template-customizer-loading${themes ? "-theme" : ""}`, ); } _getElementFromString(str) { const wrapper = document.createElement("div"); wrapper.innerHTML = str; return wrapper.firstChild; } // Set settings in LocalStorage with layout & key _getSetting(key) { let result = null; const layoutName = this._getLayoutName(); try { result = localStorage.getItem( `templateCustomizer-${layoutName}--${key}`, ); } catch (e) { // Catch error } return String(result || ""); } _showResetBtnNotification(show = true) { setTimeout(() => { const resetBtnAttr = this.container.querySelector( ".template-customizer-reset-btn .badge", ); if (show) { resetBtnAttr.classList.remove("d-none"); } else { resetBtnAttr.classList.add("d-none"); } }, 200); } // Set settings in LocalStorage with layout & key _setSetting(key, val) { const layoutName = this._getLayoutName(); try { localStorage.setItem( `templateCustomizer-${layoutName}--${key}`, String(val), ); this._showResetBtnNotification(); } catch (e) { // Catch Error } } // Get layout name to set unique _getLayoutName() { return document .getElementsByTagName("HTML")[0] .getAttribute("data-template"); } _removeListeners() { for (let i = 0, l = this._listeners.length; i < l; i++) { this._listeners[i][0].removeEventListener( this._listeners[i][1], this._listeners[i][2], ); } } _cleanup() { this._removeListeners(); this._listeners = []; this._controls = {}; if (this._updateInterval) { clearInterval(this._updateInterval); this._updateInterval = null; } } get _ssr() { return typeof window === "undefined"; } // Check controls availability _hasControls(controls, oneOf = false) { return controls.split(" ").reduce((result, control) => { if (this.settings.controls.indexOf(control) !== -1) { if (oneOf || result !== false) result = true; } else if (!oneOf || result !== true) result = false; return result; }, null); } // Get the default theme _getDefaultTheme(themeId) { let theme; if (typeof themeId === "string") { theme = this._getThemeByName(themeId, false); } else { theme = this.settings.availableThemes[themeId]; } if (!theme) { throw new Error(`Theme ID "${themeId}" not found!`); } return theme; } // Get theme by themeId/themeName _getThemeByName(themeName, returnDefault = false) { const themes = this.settings.availableThemes; for (let i = 0, l = themes.length; i < l; i++) { if (themes[i].name === themeName) return themes[i]; } return returnDefault ? this.settings.defaultTheme : null; } _setCookie(name, value, daysToExpire, path = "/", domain = "") { const cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`; let expires = ""; if (daysToExpire) { const expirationDate = new Date(); expirationDate.setTime( expirationDate.getTime() + daysToExpire * 24 * 60 * 60 * 1000, ); expires = `; expires=${expirationDate.toUTCString()}`; } const pathString = `; path=${path}`; const domainString = domain ? `; domain=${domain}` : ""; document.cookie = `${cookie}${expires}${pathString}${domainString}`; } _getCookie(name) { const cookies = document.cookie.split("; "); for (let i = 0; i < cookies.length; i++) { const [cookieName, cookieValue] = cookies[i].split("="); if (decodeURIComponent(cookieName) === name) { return decodeURIComponent(cookieValue); } } return null; } _checkCookie(name) { return this._getCookie(name) !== null; } _deleteCookie(name) { document.cookie = name + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; } } // Styles TemplateCustomizer.STYLES = [ { name: "light", title: "Light", }, { name: "dark", title: "Dark", }, { name: "system", title: "System", }, ]; // Themes TemplateCustomizer.THEMES = [ { name: "theme-default", title: "Default", }, { name: "theme-bordered", title: "Bordered", }, { name: "theme-semi-dark", title: "Semi Dark", }, ]; // Layouts TemplateCustomizer.LAYOUTS = [ { name: "expanded", title: "Expanded", }, { name: "collapsed", title: "Collapsed", }, ]; // Navbar Options TemplateCustomizer.NAVBAR_OPTIONS = [ { name: "sticky", title: "Sticky", }, { name: "static", title: "Static", }, { name: "hidden", title: "Hidden", }, ]; // Header Types TemplateCustomizer.HEADER_TYPES = [ { name: "fixed", title: "Fixed", }, { name: "static", title: "Static", }, ]; // Content Types TemplateCustomizer.CONTENT = [ { name: "compact", title: "Compact", }, { name: "wide", title: "Wide", }, ]; // Directions TemplateCustomizer.DIRECTIONS = [ { name: "ltr", title: "Left to Right (En)", }, { name: "rtl", title: "Right to Left (Ar)", }, ]; // Theme setting language TemplateCustomizer.LANGUAGES = { en: { panel_header: "Template Customizer", panel_sub_header: "Customize and preview in real time", theming_header: "Theming", style_label: "Style (Mode)", theme_label: "Themes", layout_header: "Layout", layout_label: "Menu (Navigation)", layout_header_label: "Header Types", content_label: "Content", layout_navbar_label: "Navbar Type", direction_label: "Direction", }, fr: { panel_header: "Modèle De Personnalisation", panel_sub_header: "Personnalisez et prévisualisez en temps réel", theming_header: "Thématisation", style_label: "Style (Mode)", theme_label: "Thèmes", layout_header: "Disposition", layout_label: "Menu (Navigation)", layout_header_label: "Types d'en-tête", content_label: "Contenu", layout_navbar_label: "Type de barre de navigation", direction_label: "Direction", }, ar: { panel_header: "أداة تخصيص القالب", panel_sub_header: "تخصيص ومعاينة في الوقت الحقيقي", theming_header: "السمات", style_label: "النمط (الوضع)", theme_label: "المواضيع", layout_header: "تَخطِيط", layout_label: "القائمة (الملاحة)", layout_header_label: "أنواع الرأس", content_label: "محتوى", layout_navbar_label: "نوع شريط التنقل", direction_label: "اتجاه", }, de: { panel_header: "Vorlagen-Anpasser", panel_sub_header: "Anpassen und Vorschau in Echtzeit", theming_header: "Themen", style_label: "Stil (Modus)", theme_label: "Themen", layout_header: "Layout", layout_label: "Menü (Navigation)", layout_header_label: "Header-Typen", content_label: "Inhalt", layout_navbar_label: "Art der Navigationsleiste", direction_label: "Richtung", }, }; window.TemplateCustomizer = TemplateCustomizer;