gruene-seele/resources/assets/vendor/js/theme-settings.js
2021-01-08 17:48:20 +01:00

1257 lines
42 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import style from './_theme-settings/_theme-settings.scss'
import markup from './_theme-settings/_theme-settings.html'
import themeItemMarkup from './_theme-settings/_theme-settings-theme-item.html'
import bgItemMarkup from './_theme-settings/_theme-settings-bg-item.html'
const DEFAULT_THEME = 1
const CSS_FILENAME_PATTERN = '%name%.css'
const CONTROLS = [
'rtl',
'style',
'layoutPosition',
'layoutNavbarFixed',
'layoutFooterFixed',
'layoutReversed',
'navbarBg',
'sidenavBg',
'footerBg',
'themes'
]
const STYLES = [
'light',
'material',
'dark'
]
const DEFAULT_NAVBAR_BG = 'navbar-theme'
const DEFAULT_SIDENAV_BG = 'sidenav-theme'
const DEFAULT_FOOTER_BG = 'footer-theme'
class ThemeSettings {
constructor({ cssPath, themesPath, cssFilenamePattern, controls, styles, sidenavBgs, defaultSidenavBg, navbarBgs, defaultNavbarBg, footerBgs, defaultFooterBg, availableThemes, defaultTheme, pathResolver, onSettingsChange, lang }) {
if (this._ssr) return
if (!window.layoutHelpers) throw new Error('window.layoutHelpers required.')
this.settings = {}
this.settings.cssPath = cssPath
this.settings.themesPath = themesPath
this.settings.cssFilenamePattern = cssFilenamePattern || CSS_FILENAME_PATTERN
this.settings.navbarBgs = navbarBgs || ThemeSettings.NAVBAR_BGS
this.settings.defaultNavbarBg = defaultNavbarBg || DEFAULT_NAVBAR_BG
this.settings.sidenavBgs = sidenavBgs || ThemeSettings.SIDENAV_BGS
this.settings.defaultSidenavBg = defaultSidenavBg || DEFAULT_SIDENAV_BG
this.settings.footerBgs = footerBgs || ThemeSettings.FOOTER_BGS
this.settings.defaultFooterBg = defaultFooterBg || DEFAULT_FOOTER_BG
this.settings.availableThemes = availableThemes || ThemeSettings.AVAILABLE_THEMES
this.settings.defaultTheme = this._getDefaultTheme(typeof defaultTheme !== 'undefined' ? defaultTheme : DEFAULT_THEME)
this.settings.controls = controls || CONTROLS
this.settings.styles = styles || STYLES
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.setLayoutPosition(this.settings.layoutPosition, false)
this.setLayoutNavbarFixed(this.settings.layoutNavbarFixed, false)
this.setLayoutFooterFixed(this.settings.layoutFooterFixed, false)
this.setLayoutReversed(this.settings.layoutReversed, false)
this._setup()
this._waitForNavs()
}
setRtl(rtl) {
if (!this._hasControls('rtl')) return
this._setSetting('Rtl', String(rtl))
window.location.reload()
}
setStyle(style) {
if (!this._hasControls('style')) return
this._setSetting('Style', ['material', 'dark'].indexOf(style) === -1 ? 'light' : style)
window.location.reload()
}
isLightStyle() {
return document.documentElement.classList.contains('light-style')
}
isMaterialStyle() {
return document.documentElement.classList.contains('material-style')
}
isDarkStyle() {
return document.documentElement.classList.contains('dark-style')
}
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)
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('.theme-settings-theme-css') },
cb || (() => {})
)
if (updateStorage) this.settings.onSettingsChange.call(this, this.settings)
}
setLayoutPosition(pos, updateStorage = true) {
if (!this._hasControls('layoutPosition')) return
if (pos !== 'static' && pos !== 'static-offcanvas' && pos !== 'fixed' && pos !== 'fixed-offcanvas') return
this.settings.layoutPosition = pos
if (updateStorage) this._setSetting('LayoutPosition', pos)
window.layoutHelpers.setPosition(
pos === 'fixed' || pos === 'fixed-offcanvas',
pos === 'static-offcanvas' || pos === 'fixed-offcanvas'
)
if (updateStorage) this.settings.onSettingsChange.call(this, this.settings)
}
setLayoutNavbarFixed(fixed, updateStorage = true) {
if (!this._hasControls('layoutNavbarFixed')) return
this.settings.layoutNavbarFixed = fixed
if (updateStorage) this._setSetting('FixedNavbar', fixed)
window.layoutHelpers.setNavbarFixed(fixed)
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.layoutHelpers.setFooterFixed(fixed)
if (updateStorage) this.settings.onSettingsChange.call(this, this.settings)
}
setLayoutReversed(reversed, updateStorage = true) {
if (!this._hasControls('layoutReversed')) return
this.settings.layoutReversed = reversed
if (updateStorage) this._setSetting('LayoutReversed', reversed)
window.layoutHelpers.setReversed(reversed)
if (updateStorage) this.settings.onSettingsChange.call(this, this.settings)
}
setNavbarBg(bg, updateStorage = true, _container = document) {
if (!this._hasControls('navbarBg')) return
if (this.settings.navbarBgs.indexOf(bg) === -1) return
this.settings.navbarBg = bg
if (updateStorage) this._setSetting('NavbarBg', bg)
const navbar = _container.querySelector('.layout-navbar.navbar, .layout-navbar .navbar')
if (!navbar) return
navbar.className = navbar.className.replace(/^bg\-[^ ]+| bg\-[^ ]+/ig, '')
navbar.classList.remove('navbar-light')
navbar.classList.remove('navbar-dark')
const classes = bg.split(' ')
navbar.classList.add(`bg-${classes[0]}`)
for (let i = 1, l = classes.length; i < l; i++) navbar.classList.add(classes[i])
if (updateStorage) this.settings.onSettingsChange.call(this, this.settings)
}
setSidenavBg(bg, updateStorage = true, _container = document) {
if (!this._hasControls('sidenavBg')) return
if (this.settings.sidenavBgs.indexOf(bg) === -1) return
this.settings.sidenavBg = bg
if (updateStorage) this._setSetting('SidenavBg', bg)
const sidenav = _container.querySelector('.layout-sidenav.sidenav, .layout-sidenav .sidenav, .layout-sidenav-horizontal.sidenav, .layout-sidenav-horizontal .sidenav')
if (!sidenav) return
sidenav.className = sidenav.className.replace(/^bg\-[^ ]+| bg\-[^ ]+/ig, '')
sidenav.classList.remove('sidenav-light')
sidenav.classList.remove('sidenav-dark')
let classes = bg.split(' ')
if (sidenav.classList.contains('sidenav-horizontal')) {
classes = classes.join(' ').replace(' sidenav-dark', '').replace(' sidenav-light', '').split(' ')
classes[0] = classes[0].replace(/-darke?r?$/, '')
}
sidenav.classList.add(`bg-${classes[0]}`)
for (let i = 1, l = classes.length; i < l; i++) sidenav.classList.add(classes[i])
if (updateStorage) this.settings.onSettingsChange.call(this, this.settings)
}
setFooterBg(bg, updateStorage = true, _container = document) {
if (!this._hasControls('footerBg')) return
if (this.settings.footerBgs.indexOf(bg) === -1) return
this.settings.footerBg = bg
if (updateStorage) this._setSetting('FooterBg', bg)
const footer = _container.querySelector('.layout-footer.footer, .layout-footer .footer')
if (!footer) return
footer.className = footer.className.replace(/^bg\-[^ ]+| bg\-[^ ]+/ig, '')
footer.classList.remove('footer-light')
footer.classList.remove('footer-dark')
const classes = bg.split(' ')
footer.classList.add(`bg-${classes[0]}`)
for (let i = 1, l = classes.length; i < l; i++) footer.classList.add(classes[i])
if (updateStorage) this.settings.onSettingsChange.call(this, this.settings)
}
setLang(lang, force = false) {
if (lang === this.settings.lang && !force) return
if (!ThemeSettings.LANGUAGES[lang]) throw new Error(`Language "${lang}" not found!`)
const t = ThemeSettings.LANGUAGES[lang]
;[
'panel_header', 'rtl_switcher', 'style_switcher_light', 'style_switcher_material',
'style_switcher_dark', 'layout_header', 'layout_static',
'layout_offcanvas', 'layout_fixed', 'layout_fixed_offcanvas', 'layout_navbar_swicher',
'layout_footer_swicher', 'layout_reversed_swicher', 'navbar_bg_header', 'sidenav_bg_header',
'footer_bg_header', 'theme_header'
].forEach(key => {
const el = this.container.querySelector(`.theme-settings-t-${key}`)
el && (el.textContent = t[key])
})
const tt = t.themes || {}
const themes = this.container.querySelectorAll('.theme-settings-theme-item') || []
for (let i = 0, l = themes.length; i < l; i++) {
const themeName = themes[i].querySelector('input[type="radio"]').value
themes[i].querySelector('.theme-settings-theme-name').textContent = tt[themeName] || this._getThemeByName(themeName).title
}
this.settings.lang = lang
}
update() {
if (this._ssr) return
const hasNavbar = !!document.querySelector('.layout-navbar')
const hasSidenav = !!document.querySelector('.layout-sidenav')
const hasHorizontalSidenav = !!document.querySelector('.layout-sidenav-horizontal.sidenav, .layout-sidenav-horizontal .sidenav')
const isLayout1 = !!document.querySelector('.layout-wrapper.layout-1')
const hasFooter = !!document.querySelector('.layout-footer')
if (this._controls.layoutReversed) {
if (!hasSidenav) {
this._controls.layoutReversed.setAttribute('disabled', 'disabled')
this._controls.layoutReversedW.classList.add('disabled')
} else {
this._controls.layoutReversed.removeAttribute('disabled')
this._controls.layoutReversedW.classList.remove('disabled')
}
}
if (this._controls.layoutNavbarFixed) {
if (!hasNavbar) {
this._controls.layoutNavbarFixed.setAttribute('disabled', 'disabled')
this._controls.layoutNavbarFixedW.classList.add('disabled')
} else {
this._controls.layoutNavbarFixed.removeAttribute('disabled')
this._controls.layoutNavbarFixedW.classList.remove('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.layoutPosition) {
if (!hasSidenav) {
this._controls.layoutPosition.querySelector('[value="static-offcanvas"]').setAttribute('disabled', 'disabled')
this._controls.layoutPosition.querySelector('[value="fixed-offcanvas"]').setAttribute('disabled', 'disabled')
} else {
this._controls.layoutPosition.querySelector('[value="static-offcanvas"]').removeAttribute('disabled')
this._controls.layoutPosition.querySelector('[value="fixed-offcanvas"]').removeAttribute('disabled')
}
if ((!hasNavbar && !hasSidenav) || (!hasSidenav && !isLayout1)) {
this._controls.layoutPosition.setAttribute('disabled', 'disabled')
} else {
this._controls.layoutPosition.removeAttribute('disabled')
}
}
if (this._controls.navbarBgWInner) {
if (!hasNavbar) {
this._controls.navbarBgWInner.setAttribute('disabled', 'disabled')
} else {
this._controls.navbarBgWInner.removeAttribute('disabled')
}
}
if (this._controls.sidenavBgWInner) {
const items = Array.prototype.slice.call(document.querySelectorAll('.theme-settings-sidenavBg-inner .theme-settings-bg-item'))
if (!hasSidenav && !hasHorizontalSidenav) {
items.forEach(item => {
item.classList.add('disabled')
item.querySelector('input').setAttribute('disabled', 'disabled')
})
} else {
items.forEach(item => {
item.classList.remove('disabled')
item.querySelector('input').removeAttribute('disabled')
})
if (hasHorizontalSidenav) items.forEach(item => {
if (!/-darke?r?/.test(item.className) || /bg-dark/.test(item.className)) return
item.classList.add('disabled')
item.querySelector('input').setAttribute('disabled', 'disabled')
})
}
}
if (this._controls.footerBgWInner) {
if (!hasFooter) {
this._controls.footerBgWInner.setAttribute('disabled', 'disabled')
} else {
this._controls.footerBgWInner.removeAttribute('disabled')
}
}
}
updateNavbarBg(_container = document) {
this.setNavbarBg(this.settings.navbarBg, false, _container)
}
updateSidenavBg(_container = document) {
this.setSidenavBg(this.settings.sidenavBg, false, _container)
}
updateFooterBg(_container = document) {
this.setFooterBg(this.settings.footerBg, false, _container)
}
clearLocalStorage() {
if (this._ssr) return
this._setSetting('Theme', '')
this._setSetting('Rtl', '')
this._setSetting('Style', '')
this._setSetting('LayoutReversed', '')
this._setSetting('FixedNavbar', '')
this._setSetting('FixedFooter', '')
this._setSetting('LayoutPosition', '')
this._setSetting('NavbarBg', '')
this._setSetting('SidenavBg', '')
this._setSetting('FooterBg', '')
}
destroy() {
if (this._ssr) return
this._cleanup()
this.settings = null
this.container.parentNode.removeChild(this.container)
this.container = null
}
_loadSettings() {
const cl = document.documentElement.classList
const rtl = this._getSetting('Rtl')
const style = this._getSetting('Style')
const reversed = this._getSetting('LayoutReversed')
const fixedNavbar = this._getSetting('FixedNavbar')
const fixedFooter = this._getSetting('FixedFooter')
const navbarBg = this._getSetting('NavbarBg')
const sidenavBg = this._getSetting('SidenavBg')
const footerBg = this._getSetting('FooterBg')
const lPosition = this._getSetting('LayoutPosition')
let position
if (lPosition !== '' && ['static', 'static-offcanvas', 'fixed', 'fixed-offcanvas'].indexOf(lPosition) !== -1) {
position = lPosition
} else if (cl.contains('layout-offcanvas')) {
position = 'static-offcanvas'
} else if (cl.contains('layout-fixed')) {
position = 'fixed'
} else if (cl.contains('layout-fixed-offcanvas')) {
position = 'fixed-offcanvas'
} else {
position = 'static'
}
// Set settings
this.settings.rtl = rtl !== '' ? rtl === 'true' : document.documentElement.getAttribute('dir') === 'rtl'
this.settings.style = this.settings.styles.indexOf(style) !== -1 ? style : (
cl.contains('material-style') ? 'material' : (
cl.contains('dark-style') ? 'dark' : 'light'
)
)
if (this.settings.styles.indexOf(this.settings.style) === -1) {
this.settings.style = this.settings.styles[0]
}
this.settings.layoutPosition = position
this.settings.layoutReversed = reversed !== '' ? reversed === 'true' : cl.contains('layout-reversed')
this.settings.layoutNavbarFixed = fixedNavbar !== '' ? fixedNavbar === 'true' : cl.contains('layout-navbar-fixed')
this.settings.layoutFooterFixed = fixedFooter !== '' ? fixedFooter === 'true' : cl.contains('layout-footer-fixed')
this.settings.navbarBg = this.settings.navbarBgs.indexOf(navbarBg) !== -1 ? navbarBg : this.settings.defaultNavbarBg
this.settings.sidenavBg = this.settings.sidenavBgs.indexOf(sidenavBg) !== -1 ? sidenavBg : this.settings.defaultSidenavBg
this.settings.footerBg = this.settings.footerBgs.indexOf(footerBg) !== -1 ? footerBg : this.settings.defaultFooterBg
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('material-style') ? 'material' : (
cl.contains('dark-style') ? 'dark' : 'light'
)
}
if (!this._hasControls('layoutPosition')) this.settings.layoutPosition = null
if (!this._hasControls('layoutReversed')) this.settings.layoutReversed = null
if (!this._hasControls('layoutNavbarFixed')) this.settings.layoutNavbarFixed = null
if (!this._hasControls('layoutFooterFixed')) this.settings.layoutFooterFixed = null
if (!this._hasControls('navbarBg')) this.settings.navbarBg = null
if (!this._hasControls('sidenavBg')) this.settings.sidenavBg = null
if (!this._hasControls('footerBg')) this.settings.footerBg = null
if (!this._hasControls('themes')) this.settings.theme = null
}
_setup(_container = document) {
this._cleanup()
this.container = this._getElementFromString(markup)
// Open btn
//
const openBtn = this.container.querySelector('.theme-settings-open-btn')
const openBtnCb = () => {
this.container.classList.add('theme-settings-open')
this.update()
if (this._updateInterval) clearInterval(this._updateInterval)
this._updateInterval = setInterval(() => {
this.update()
}, 1000)
}
openBtn.addEventListener('click', openBtnCb)
this._listeners.push([ openBtn, 'click', openBtnCb ])
// Close btn
//
const closeBtn = this.container.querySelector('.theme-settings-close-btn')
const closeBtnCb = () => {
this.container.classList.remove('theme-settings-open')
if (this._updateInterval) {
clearInterval(this._updateInterval)
this._updateInterval = null
}
}
closeBtn.addEventListener('click', closeBtnCb)
this._listeners.push([ closeBtn, 'click', closeBtnCb ])
// RTL
//
const rtlW = this.container.querySelector('.theme-settings-rtl')
if (!this._hasControls('rtl')) {
rtlW.parentNode.removeChild(rtlW)
} else {
const rtl = rtlW.querySelector('input')
if (this.settings.rtl) rtl.setAttribute('checked', 'checked')
const rtlCb = e => {
this._loadingState(true)
this.setRtl(e.target.checked)
}
rtl.addEventListener('change', rtlCb)
this._listeners.push([ rtl, 'change', rtlCb ])
}
// Style
//
const styleW = this.container.querySelector('.theme-settings-style')
if (!this._hasControls('style')) {
styleW.parentNode.removeChild(styleW)
} else {
const style = styleW.querySelector('select')
this.settings.styles.forEach(styleItem => {
const styleEl = this._getElementFromString(
`<option value="${styleItem}" class="theme-settings-t-style_switcher_${styleItem}" ${this.settings.style === styleItem ? 'selected="selected"' : ''}></option>`
)
style.appendChild(styleEl)
})
const styleCb = e => {
this._loadingState(true)
this.setStyle(e.target.value)
}
style.addEventListener('change', styleCb)
this._listeners.push([ style, 'change', styleCb ])
}
// Layout wrapper
//
const layoutW = this.container.querySelector('.theme-settings-layout')
if (!this._hasControls('layoutPosition layoutNavbarFixed layoutFooterFixed layoutReversed', true)) {
layoutW.parentNode.removeChild(layoutW)
} else {
// Position
//
const layoutPositionW = this.container.querySelector('.theme-settings-layoutPosition')
if (!this._hasControls('layoutPosition')) {
layoutPositionW.parentNode.removeChild(layoutPositionW)
} else {
this._controls.layoutPosition = layoutPositionW.querySelector('select')
this._controls.layoutPosition.value = this.settings.layoutPosition
const layoutPositionCb = e => this.setLayoutPosition(e.target.value)
this._controls.layoutPosition.addEventListener('change', layoutPositionCb)
this._listeners.push([ this._controls.layoutPosition, 'change', layoutPositionCb ])
}
// Navbar
//
this._controls.layoutNavbarFixedW = this.container.querySelector('.theme-settings-layoutNavbarFixed')
if (!this._hasControls('layoutNavbarFixed')) {
this._controls.layoutNavbarFixedW.parentNode.removeChild(this._controls.layoutNavbarFixedW)
} else {
this._controls.layoutNavbarFixed = this._controls.layoutNavbarFixedW.querySelector('input')
if (this.settings.layoutNavbarFixed) this._controls.layoutNavbarFixed.setAttribute('checked', 'checked')
const layoutNavbarFixedCb = e => this.setLayoutNavbarFixed(e.target.checked)
this._controls.layoutNavbarFixed.addEventListener('change', layoutNavbarFixedCb)
this._listeners.push([ this._controls.layoutNavbarFixed, 'change', layoutNavbarFixedCb ])
}
// Footer
//
this._controls.layoutFooterFixedW = this.container.querySelector('.theme-settings-layoutFooterFixed')
if (!this._hasControls('layoutFooterFixed')) {
this._controls.layoutFooterFixedW.parentNode.removeChild(this._controls.layoutFooterFixedW)
} else {
this._controls.layoutFooterFixed = this._controls.layoutFooterFixedW.querySelector('input')
if (this.settings.layoutFooterFixed) this._controls.layoutFooterFixed.setAttribute('checked', 'checked')
const layoutFooterFixedCb = e => this.setLayoutFooterFixed(e.target.checked)
this._controls.layoutFooterFixed.addEventListener('change', layoutFooterFixedCb)
this._listeners.push([ this._controls.layoutFooterFixed, 'change', layoutFooterFixedCb ])
}
// Reversed
//
this._controls.layoutReversedW = this.container.querySelector('.theme-settings-layoutReversed')
if (!this._hasControls('layoutReversed')) {
this._controls.layoutReversedW.parentNode.removeChild(this._controls.layoutReversedW)
} else {
this._controls.layoutReversed = this._controls.layoutReversedW.querySelector('input')
if (this.settings.layoutReversed) this._controls.layoutReversed.setAttribute('checked', 'checked')
const layoutReversedCb = e => this.setLayoutReversed(e.target.checked)
this._controls.layoutReversed.addEventListener('change', layoutReversedCb)
this._listeners.push([ this._controls.layoutReversed, 'change', layoutReversedCb ])
}
}
// Navbar Bg
//
const navbarBgW = this.container.querySelector('.theme-settings-navbarBg')
if (!this._hasControls('navbarBg')) {
navbarBgW.parentNode.removeChild(navbarBgW)
} else {
this._controls.navbarBgWInner = navbarBgW.querySelector('.theme-settings-navbarBg-inner')
this.settings.navbarBgs.forEach(bg => {
const bgItem = this._getElementFromString(bgItemMarkup)
const control = bgItem.querySelector('input')
bgItem.classList.add(`bg-${bg.split(' ')[0]}`)
control.name = 'theme-settings-navbarBg-input'
control.value = bg
if (this.settings.navbarBg === bg) {
control.setAttribute('checked', 'checked')
bgItem.classList.add('active')
}
const cb = e => {
const items = this._controls.navbarBgWInner.querySelectorAll('.theme-settings-bg-item')
for (let i = 0, l = items.length; i < l; i++) items[i].classList.remove('active')
e.target.parentNode.classList.add('active')
this.setNavbarBg(e.target.value)
}
control.addEventListener('change', cb)
this._listeners.push([ control, 'change', cb ])
this._controls.navbarBgWInner.appendChild(bgItem)
})
}
// Sidenav Bg
//
const sidenavBgW = this.container.querySelector('.theme-settings-sidenavBg')
if (!this._hasControls('sidenavBg')) {
sidenavBgW.parentNode.removeChild(sidenavBgW)
} else {
this._controls.sidenavBgWInner = sidenavBgW.querySelector('.theme-settings-sidenavBg-inner')
this.settings.sidenavBgs.forEach(bg => {
const bgItem = this._getElementFromString(bgItemMarkup)
const control = bgItem.querySelector('input')
bgItem.classList.add(`bg-${bg.split(' ')[0]}`)
control.name = 'theme-settings-sidenavBg-input'
control.value = bg
if (this.settings.sidenavBg === bg) {
control.setAttribute('checked', 'checked')
bgItem.classList.add('active')
}
const cb = e => {
const items = this._controls.sidenavBgWInner.querySelectorAll('.theme-settings-bg-item')
for (let i = 0, l = items.length; i < l; i++) items[i].classList.remove('active')
e.target.parentNode.classList.add('active')
this.setSidenavBg(e.target.value)
}
control.addEventListener('change', cb)
this._listeners.push([ control, 'change', cb ])
this._controls.sidenavBgWInner.appendChild(bgItem)
})
}
// Footer Bg
//
const footerBgW = this.container.querySelector('.theme-settings-footerBg')
if (!this._hasControls('footerBg')) {
footerBgW.parentNode.removeChild(footerBgW)
} else {
this._controls.footerBgWInner = footerBgW.querySelector('.theme-settings-footerBg-inner')
this.settings.footerBgs.forEach(bg => {
const bgItem = this._getElementFromString(bgItemMarkup)
const control = bgItem.querySelector('input')
bgItem.classList.add(`bg-${bg.split(' ')[0]}`)
control.name = 'theme-settings-footerBg-input'
control.value = bg
if (this.settings.footerBg === bg) {
control.setAttribute('checked', 'checked')
bgItem.classList.add('active')
}
const cb = e => {
const items = this._controls.footerBgWInner.querySelectorAll('.theme-settings-bg-item')
for (let i = 0, l = items.length; i < l; i++) items[i].classList.remove('active')
e.target.parentNode.classList.add('active')
this.setFooterBg(e.target.value)
}
control.addEventListener('change', cb)
this._listeners.push([ control, 'change', cb ])
this._controls.footerBgWInner.appendChild(bgItem)
})
}
// Themes
//
const themesW = this.container.querySelector('.theme-settings-themes')
if (!this._hasControls('themes')) {
themesW.parentNode.removeChild(themesW)
} else {
const themesWInner = this.container.querySelector('.theme-settings-themes-inner')
// SETUP THEMES
this.settings.availableThemes.forEach(theme => {
const themeItem = this._getElementFromString(themeItemMarkup)
const control = themeItem.querySelector('input')
const colors = this.isDarkStyle() ? theme.colorsDark : theme.colors
control.value = theme.name
if (this.settings.theme.name === theme.name) {
control.setAttribute('checked', 'checked')
}
themeItem.querySelector('.theme-settings-theme-colors').innerHTML = `
<span style="background: ${colors.primary}"></span>
<span style="background: ${colors.navbar}"></span>
<span style="background: ${colors.sidenav}"></span>
`
const cb = e => {
if (this._loading) return
this._loading = true
this._loadingState(true, true)
this.setTheme(e.target.value, true, () => {
this._loading = false
this._loadingState(false, true)
})
}
control.addEventListener('change', cb)
this._listeners.push([ control, 'change', cb ])
themesWInner.appendChild(themeItem)
})
}
// Set language
this.setLang(this.settings.lang, 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.settings.rtl ? 'rtl' : 'ltr')
}
_initStyle() {
if (!this._hasControls('style')) return
const style = this.settings.style
this._insertStylesheet('theme-settings-bootstrap-css', this.pathResolver(
this.settings.cssPath + this.settings.cssFilenamePattern.replace('%name%', 'bootstrap' + (style !== 'light' ? `-${style}` : ''))
))
this._insertStylesheet('theme-settings-appwork-css', this.pathResolver(
this.settings.cssPath + this.settings.cssFilenamePattern.replace('%name%', 'appwork' + (style !== 'light' ? `-${style}` : ''))
))
this._insertStylesheet('theme-settings-colors-css', this.pathResolver(
this.settings.cssPath + this.settings.cssFilenamePattern.replace('%name%', 'colors' + (style !== 'light' ? `-${style}` : ''))
))
const classesToRemove = style === 'light'
? ['material-style', 'dark-style']
: (
style === 'material'
? ['light-style', 'dark-style']
: ['light-style', 'material-style']
)
classesToRemove.forEach(cls => {
document.documentElement.classList.remove(cls)
})
document.documentElement.classList.add(`${style}-style`)
if (style === 'material' && window.attachMaterialRipple) {
if (document.body) {
window.attachMaterialRipple()
} else {
window.addEventListener('DOMContentLoaded', () => window.attachMaterialRipple())
}
}
}
_initTheme() {
if (this._hasControls('themes')) {
this._insertStylesheet('theme-settings-theme-css', this.pathResolver(
this.settings.themesPath + this.settings.cssFilenamePattern.replace('%name%', this.settings.theme.name + (this.settings.style !== 'light' ? `-${this.settings.style}` : ''))
))
}
}
_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 {
document.write(`<link rel="stylesheet" type="text/css" href="${href}" class="${className}">`)
}
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 timeoutId, intervalId
timeoutId = setTimeout(function() {
clearInterval(intervalId)
clearTimeout(timeoutId)
curLink.parentNode.removeChild(link)
_cb(false, path)
}, 15000 )
intervalId = setInterval(function() {
try {
if (link[sheet] && link[sheet][cssRules].length) {
clearInterval(intervalId)
clearTimeout(timeoutId)
curLink.parentNode.removeChild(curLink)
_cb(true)
}
} catch(e) {
console.error(e)
} finally {}
}, 10)
curLink.parentNode.insertBefore(link, curLink.nextSibling)
}
for (let i = 0; i < paths.length; i++) {
loadStylesheet(paths[i], stylesheets[paths[i]], function(success, errPath) {
if (!success) {
if (console && typeof console.error === 'function') { console.error('Error occured while loading stylesheets!') }
alert('Error occured while loading stylesheets!')
console.log(errPath)
}
if (++loaded >= count) {
cb()
}
})
}
}
_loadingState(enable, themes) {
this.container.classList[enable ? 'add' : 'remove'](`theme-settings-loading${themes ? '-theme' : ''}`)
}
_waitForNavs() {
this._addObserver(
'.layout-navbar.navbar, .layout-navbar .navbar',
node => {
return node && node.classList && node.classList.contains('layout-navbar') && (
node.classList.contains('navbar') || node.querySelector('.navbar')
)
},
() => this.setNavbarBg(this.settings.navbarBg, false)
)
this._addObserver(
'.layout-sidenav.sidenav, .layout-sidenav .sidenav, .layout-sidenav-horizontal.sidenav, .layout-sidenav-horizontal .sidenav',
node => {
return node && node.classList && (
(node.classList.contains('layout-sidenav') || node.classList.contains('layout-sidenav-horizontal')) && (
node.classList.contains('sidenav') || node.querySelector('.sidenav')
)
)
},
() => this.setSidenavBg(this.settings.sidenavBg, false)
)
this._addObserver(
'.layout-footer.footer, .layout-footer .footer',
node => {
return node && node.classList && node.classList.contains('layout-footer') && (
node.classList.contains('footer') || node.querySelector('.footer')
)
},
() => this.setFooterBg(this.settings.footerBg, false)
)
if (!document.body && ((this._observers && this._observers.length) || (this._intervals && this._intervals.length))) {
const loadCb = () => {
this._clearObservers()
this.setNavbarBg(this.settings.navbarBg, false)
this.setSidenavBg(this.settings.sidenavBg, false)
this.setFooterBg(this.settings.footerBg, false)
window.removeEventListener('load', loadCb)
}
window.addEventListener('load', loadCb)
}
}
_addObserver(selector, condition, cb) {
if (!this._observers) this._observers = []
if (!this._intervals) this._intervals = []
let _observer
let _interval
if (document.querySelector(selector)) {
cb.call(this)
} else if (!document.body) {
if (typeof MutationObserver !== 'undefined') {
_observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
if (!mutation.addedNodes) return
for (let i = 0; i < mutation.addedNodes.length; i++) {
let node = mutation.addedNodes[i]
if (condition.call(this, node)) {
_observer.disconnect()
this._observers.splice(this._observers.indexOf(_observer), 1)
_observer = null
cb.call(this)
break
}
}
})
})
this._observers.push(_observer)
_observer.observe(document.documentElement, {
childList: true, subtree: true, attributes: false, characterData: false
})
} else {
_interval = setInterval(() => {
if (document.querySelector(selector)) {
clearInterval(_interval)
this._intervals.splice(this._intervals.indexOf(_interval), 1)
_interval = null
cb.call(this)
}
}, 10)
this._intervals.push(_interval)
}
}
}
_clearObservers() {
if (this._observers && this._observers.length) {
for (let i = 0, l = this._observers.length; i < l; i++) {
this._observers[i].disconnect()
}
}
if (this._intervals && this._intervals.length) {
for (let j = 0, k = this._intervals.length; j < k; j++) {
clearInterval(this._intervals[j])
}
}
this._observers = null
this._intervals = null
}
_getElementFromString(str) {
const wrapper = document.createElement('div')
wrapper.innerHTML = str
return wrapper.firstChild
}
_getSetting(key) {
let result = null
try { result = localStorage.getItem(`themeSettings${key}`) } catch (e) {}
return String(result || '')
}
_setSetting(key, val) {
try { localStorage.setItem(`themeSettings${key}`, String(val)) } catch (e) {}
}
_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 = {}
this._clearObservers()
if (this._updateInterval) {
clearInterval(this._updateInterval)
this._updateInterval = null
}
}
get _ssr() {
return typeof window === 'undefined'
}
_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)
}
_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
}
_getThemeByName(themeName, returnDefault = false) {
const themes = this.settings.availableThemes
for (var i = 0, l = themes.length; i < l; i++) {
if (themes[i].name === themeName) return themes[i]
}
return returnDefault ? this.settings.defaultTheme : null
}
}
ThemeSettings.AVAILABLE_THEMES = [
{ name: 'theme-air', title: 'Air', colors: { primary: '#3c97fe', navbar: '#f8f8f8', sidenav: '#f8f8f8' }, colorsDark: { primary: '#3c97fe', navbar: '#25282e', sidenav: '#25282e' } },
{ name: 'theme-corporate', title: 'Corporate', colors: { primary: '#26B4FF', navbar: '#fff', sidenav: '#2e323a' }, colorsDark: { primary: '#26B4FF', navbar: '#1c1f24', sidenav: '#2f3238' } },
{ name: 'theme-cotton', title: 'Сotton', colors: { primary: '#e84c64', navbar: '#ffffff', sidenav: '#ffffff' }, colorsDark: { primary: '#e84c64', navbar: '#25282e', sidenav: '#d2d3d4' } },
{ name: 'theme-gradient', title: 'Gradient', colors: { primary: '#775cdc', navbar: '#ffffff', sidenav: 'linear-gradient(to top, #4e54c8, #8c55e4)' }, colorsDark: { primary: '#775cdc', navbar: '#1c1f24', sidenav: 'linear-gradient(to top, #4e54c8, #8c55e4)' } },
{ name: 'theme-paper', title: 'Paper', colors: { primary: '#17b3a3', navbar: '#ffffff', sidenav: '#ffffff' }, colorsDark: { primary: '#17b3a3', navbar: '#32353b', sidenav: '#ffffff' } },
{ name: 'theme-shadow', title: 'Shadow', colors: { primary: '#7b83ff', navbar: '#f8f8f8', sidenav: '#ececf9' }, colorsDark: { primary: '#7b83ff', navbar: '#25282e', sidenav: '#424256' } },
{ name: 'theme-soft', title: 'Soft', colors: { primary: '#1cbb84', navbar: '#39517b', sidenav: '#ffffff' }, colorsDark: { primary: '#1cbb84', navbar: '#39517b', sidenav: '#E9E9EA' } },
{ name: 'theme-sunrise', title: 'Sunrise', colors: { primary: '#fc5a5c', navbar: '#222222', sidenav: '#ffffff' }, colorsDark: { primary: '#fc5a5c', navbar: '#fff', sidenav: '#1c1f24' } },
{ name: 'theme-twitlight', title: 'Twitlight', colors: { primary: '#4c84ff', navbar: '#343c44', sidenav: '#3f4853' }, colorsDark: { primary: '#4c84ff', navbar: '#2b3239', sidenav: '#303942' } },
{ name: 'theme-vibrant', title: 'Vibrant', colors: { primary: '#fc5a5c', navbar: '#f8f8f8', sidenav: '#222222' }, colorsDark: { primary: '#fc5a5c', navbar: '#25282e', sidenav: '#1c1f24' } },
]
ThemeSettings.NAVBAR_BGS = [
'navbar-theme',
'primary',
'primary-dark navbar-dark',
'primary-darker navbar-dark',
'secondary',
'secondary-dark navbar-dark',
'secondary-darker navbar-dark',
'success',
'success-dark navbar-dark',
'success-darker navbar-dark',
'info',
'info-dark navbar-dark',
'info-darker navbar-dark',
'warning',
'warning-dark navbar-light',
'warning-darker navbar-light',
'danger',
'danger-dark navbar-dark',
'danger-darker navbar-dark',
'dark',
'white',
'light',
'lighter'
]
ThemeSettings.SIDENAV_BGS = [
'sidenav-theme',
'primary',
'primary-dark sidenav-dark',
'primary-darker sidenav-dark',
'secondary',
'secondary-dark sidenav-dark',
'secondary-darker sidenav-dark',
'success',
'success-dark sidenav-dark',
'success-darker sidenav-dark',
'info',
'info-dark sidenav-dark',
'info-darker sidenav-dark',
'warning',
'warning-dark sidenav-light',
'warning-darker sidenav-light',
'danger',
'danger-dark sidenav-dark',
'danger-darker sidenav-dark',
'dark',
'white',
'light',
'lighter'
]
ThemeSettings.FOOTER_BGS = [
'footer-theme',
'primary',
'primary-dark footer-dark',
'primary-darker footer-dark',
'secondary',
'secondary-dark footer-dark',
'secondary-darker footer-dark',
'success',
'success-dark footer-dark',
'success-darker footer-dark',
'info',
'info-dark footer-dark',
'info-darker footer-dark',
'warning',
'warning-dark footer-light',
'warning-darker footer-light',
'danger',
'danger-dark footer-dark',
'danger-darker footer-dark',
'dark',
'white',
'light',
'lighter'
]
ThemeSettings.LANGUAGES = {
en: {
panel_header: 'SETTINGS',
rtl_switcher: 'RTL direction',
style_switcher_light: 'Light style',
style_switcher_material: 'Material style',
style_switcher_dark: 'Dark style',
layout_header: 'LAYOUT',
layout_static: 'Static',
layout_offcanvas: 'Offcanvas',
layout_fixed: 'Fixed',
layout_fixed_offcanvas: 'Fixed offcanvas',
layout_navbar_swicher: 'Fixed navbar',
layout_footer_swicher: 'Fixed footer',
layout_reversed_swicher: 'Reversed',
navbar_bg_header: 'NAVBAR BACKGROUND',
sidenav_bg_header: 'SIDENAV BACKGROUND',
footer_bg_header: 'FOOTER BACKGROUND',
theme_header: 'THEME'
}
}
export { ThemeSettings }