1401 lines
45 KiB
JavaScript
1401 lines
45 KiB
JavaScript
|
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(`<div class="col-4 px-2">
|
||
|
<div class="form-check custom-option custom-option-icon">
|
||
|
<label class="form-check-label custom-option-content p-0" for="${inputName}${nameVal}">
|
||
|
<span class="custom-option-body mb-0">
|
||
|
<img src="${baseUrl}vendor/vuexy-admin/img/customizer/${image}${
|
||
|
isDarkStyle ? '-dark' : ''
|
||
|
}.svg" alt="${title}" class="img-fluid scaleX-n1-rtl" />
|
||
|
</span>
|
||
|
<input
|
||
|
name="${inputName}"
|
||
|
class="form-check-input d-none"
|
||
|
type="radio"
|
||
|
value="${nameVal}"
|
||
|
id="${inputName}${nameVal}" />
|
||
|
</label>
|
||
|
</div>
|
||
|
<label class="form-check-label small text-nowrap text-body mt-1" for="${inputName}${nameVal}">${title}</label>
|
||
|
</div>`)
|
||
|
}
|
||
|
|
||
|
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'
|
||
|
},
|
||
|
es: {
|
||
|
panel_header: 'Personalizador de Plantilla',
|
||
|
panel_sub_header: 'Personaliza y previsualiza en tiempo real',
|
||
|
theming_header: 'Tematización',
|
||
|
style_label: 'Estilo (Modo)',
|
||
|
theme_label: 'Temas',
|
||
|
layout_header: 'Diseño',
|
||
|
layout_label: 'Menú (Navegación)',
|
||
|
layout_header_label: 'Tipos de Encabezado',
|
||
|
content_label: 'Contenido',
|
||
|
layout_navbar_label: 'Tipo de Barra de Navegación',
|
||
|
direction_label: 'Dirección'
|
||
|
},
|
||
|
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
|