(function() {
/**
* @namespace theme
* @memberof Help4
*/
Help4.theme = {};
/** Sets the CSS variables for a certain theme. */
Help4.theme.Theme = class {
static CSS_ID = 'help4-theme-core';
static VAR_ID = 'help4-theme-vars';
static BASE_ID = '_BASE';
/**
* @param {DocumentFragment} shadowRoot
* @param {string} name - theme name
* @param {Object} [dynamicValues = {}]
*/
static async set(shadowRoot, name, dynamicValues = {}) {
const themeCore = await _waitStylesheet(shadowRoot, this.CSS_ID);
const apply = list => {
const {VAR_ID} = this;
let themeVars = shadowRoot.getElementById(VAR_ID);
if (!themeVars) {
themeVars = document.createElement('style');
themeVars.id = VAR_ID;
const {nextElementSibling} = themeCore;
nextElementSibling
? shadowRoot.insertBefore(themeVars, nextElementSibling)
: shadowRoot.appendChild(themeVars);
}
const html = [];
for (const [name, rules] of Object.entries(list)) {
html.push(`:host, theme-${name} {\n${rules}\n}\n`);
}
themeVars.innerHTML = html.join('');
};
const {BASE_ID} = this;
const {theme} = Help4;
const added = [];
const list = {};
const add = name => {
const vars = theme[name];
if (vars) {
const {[BASE_ID]: base} = vars;
base && !Help4.includes(added, base) && add(base);
if (!Help4.includes(added, name)) {
const rules = Object.entries(vars)
.filter(([key]) => key !== BASE_ID)
.map(([key, value]) => {
if (dynamicValues[key]) value = dynamicValues[key];
return `${key}: ${value};`;
})
.join('\n');
added.push(name);
list[name] = rules;
}
}
};
add('default');
add(name);
apply(list);
}
/**
* @param {Object} values
* @param {string} theme
*/
static clamp(values, theme) {
if (!values) return null;
const colorClamp = [
'panelHeadlineFg',
'iconFg',
'accentFg',
'accentBg',
'uiFg',
'uiBg',
'buttonFg',
'buttonBg',
'hoverFg',
'hoverBg',
'hoverListFg',
'hoverListBg',
'HSIconFg',
'HSIconBg',
'HSIconImpFg',
'HSIconImpBg',
'WNFg',
'WNBg',
'LABg',
'LAAssetFg',
'LAAssetBg',
'LAHeadFg',
'LAHeadBg',
'LAHeadlineFg',
'bubHeadFg',
'bubHeadBg',
'bubHeadBgCol'
];
// clamp rgb values to rgb(...)
for (const [key, value] of Object.entries(values)) {
if (colorClamp.indexOf(key) >= 0 && value.includes(',') && !value.startsWith('rgb(')) {
values[key] = `rgb(${value})`;
}
}
// remove whitespaces
for (const [key, value] of Object.entries(values)) {
if (typeof value === 'number') values[key] = value.toString(); // XRAY-5699
values[key] = value.replace(/\s/mg, '');
}
const {bubHeadBgCol, HSIconFg, HSIconBg, HSIconImpFg, HSIconImpBg, buttonFg, buttonBg} = values;
// legacy XRAY-2702 unify params
if (bubHeadBgCol) {
values.bubHeadBg = bubHeadBgCol;
delete values.bubHeadBgCol;
}
// for legacy if HSIconFg or HSIconBg is set but no color information
// about important hotspots, we use the same colors for important hotspots too
if ((HSIconFg || HSIconBg) && (!HSIconImpFg && !HSIconImpBg)) {
values.HSIconImpFg = HSIconFg;
values.HSIconImpBg = HSIconBg;
}
if (!buttonFg && !buttonBg) {
values.buttonFg = 'var(--help4-cmp-act-fg-col)';
values.buttonBg = 'var(--help4-cmp-act-bg-col)';
}
// get custom theme base
const {themeBase = theme || 'horizon'} = values;
delete values.themeBase; // avoid wrong processing in next loop
// add prefix to keys for correct CSS var names
const prefix = '--help4-cmp-';
return Object.entries(values)
.reduce((a, [key, value]) => {
a[`${prefix}${key}`] = value;
return a;
}, {themeBase}); // re-add theme base here
}
/**
* @param {DocumentFragment} shadowRoot
* @param {string} name
* @param {Object} list
* @throws {Error}
*/
static setCustomVariables(shadowRoot, name, list) {
const {VAR_ID} = this;
const id = `${VAR_ID}-${name}`;
const rules = Object.entries(list)
.map(([name, value]) => `${name}: ${value};`)
.join('\n');
let style = shadowRoot.getElementById(id)
if (!style) {
style = document.createElement('style');
style.id = id;
shadowRoot.appendChild(style);
}
style.innerHTML = `:host, ${name} {\n${rules}\n}`;
}
/**
* @param {DocumentFragment} shadowRoot
* @param {string} name
*/
static removeCustomVariables(shadowRoot, name) {
const {VAR_ID} = this;
const style = shadowRoot.getElementById(`${VAR_ID}-${name}`);
style && style.parentNode.removeChild(style);
}
}
/**
* @memberof Help4.theme.Theme
* @private
* @param {DocumentFragment} shadowRoot
* @param {string} cssId
* @returns {Promise<HTMLElement>}
*/
async function _waitStylesheet(shadowRoot, cssId) {
return new Help4.Promise(resolve => {
const wait = () => {
const cssFile = shadowRoot.getElementById(cssId);
cssFile
? resolve(cssFile)
: setTimeout(wait, 100);
}
wait();
});
}
})();