"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const PropertySymbol = __importStar(require("../../../PropertySymbol.cjs")); const CSSStyleDeclarationPropertyManager_js_1 = __importDefault(require("../property-manager/CSSStyleDeclarationPropertyManager.cjs")); const NodeTypeEnum_js_1 = __importDefault(require("../../../nodes/node/NodeTypeEnum.cjs")); const CSSRuleTypeEnum_js_1 = __importDefault(require("../../CSSRuleTypeEnum.cjs")); const CSSStyleDeclarationElementDefaultCSS_js_1 = __importDefault(require("./config/CSSStyleDeclarationElementDefaultCSS.cjs")); const CSSStyleDeclarationElementInheritedProperties_js_1 = __importDefault(require("./config/CSSStyleDeclarationElementInheritedProperties.cjs")); const CSSStyleDeclarationElementMeasurementProperties_js_1 = __importDefault(require("./config/CSSStyleDeclarationElementMeasurementProperties.cjs")); const CSSStyleDeclarationCSSParser_js_1 = __importDefault(require("../css-parser/CSSStyleDeclarationCSSParser.cjs")); const QuerySelector_js_1 = __importDefault(require("../../../query-selector/QuerySelector.cjs")); const CSSMeasurementConverter_js_1 = __importDefault(require("../measurement-converter/CSSMeasurementConverter.cjs")); const MediaQueryList_js_1 = __importDefault(require("../../../match-media/MediaQueryList.cjs")); const WindowBrowserSettingsReader_js_1 = __importDefault(require("../../../window/WindowBrowserSettingsReader.cjs")); const CSS_VARIABLE_REGEXP = /var\( *(--[^), ]+)\)|var\( *(--[^), ]+), *([^), ]+)\)/g; const CSS_MEASUREMENT_REGEXP = /[0-9.]+(px|rem|em|vw|vh|%|vmin|vmax|cm|mm|in|pt|pc|Q)/g; /** * CSS Style Declaration utility */ class CSSStyleDeclarationElementStyle { /** * Constructor. * * @param element Element. * @param [computed] Computed. */ constructor(element, computed = false) { this.cache = { propertyManager: null, cssText: null, documentCacheID: null }; this.element = element; this.computed = computed; } /** * Returns element style properties. * * @returns Element style properties. */ getElementStyle() { if (this.computed) { return this.getComputedElementStyle(); } const cssText = this.element[PropertySymbol.attributes]['style']?.[PropertySymbol.value]; if (cssText) { if (this.cache.propertyManager && this.cache.cssText === cssText) { return this.cache.propertyManager; } this.cache.cssText = cssText; this.cache.propertyManager = new CSSStyleDeclarationPropertyManager_js_1.default({ cssText }); return this.cache.propertyManager; } return new CSSStyleDeclarationPropertyManager_js_1.default(); } /** * Returns style sheets. * * @param element Element. * @returns Style sheets. */ getComputedElementStyle() { const documentElements = []; const parentElements = []; let styleAndElement = { element: this.element, cssTexts: [] }; let shadowRootElements = []; if (!this.element[PropertySymbol.isConnected]) { return new CSSStyleDeclarationPropertyManager_js_1.default(); } if (this.cache.propertyManager && this.cache.documentCacheID === this.element[PropertySymbol.ownerDocument][PropertySymbol.cacheID]) { return this.cache.propertyManager; } this.cache.documentCacheID = this.element[PropertySymbol.ownerDocument][PropertySymbol.cacheID]; // Walks through all parent elements and stores them in an array with element and matching CSS text. while (styleAndElement.element) { if (styleAndElement.element[PropertySymbol.nodeType] === NodeTypeEnum_js_1.default.elementNode) { const rootNode = styleAndElement.element.getRootNode(); if (rootNode[PropertySymbol.nodeType] === NodeTypeEnum_js_1.default.documentNode) { documentElements.unshift(styleAndElement); } else { shadowRootElements.unshift(styleAndElement); } parentElements.unshift(styleAndElement); } if (styleAndElement.element === this.element[PropertySymbol.ownerDocument]) { const styleSheets = (this.element[PropertySymbol.ownerDocument].querySelectorAll('style,link[rel="stylesheet"]')); for (const styleSheet of styleSheets) { const sheet = styleSheet.sheet; if (sheet) { this.parseCSSRules({ elements: documentElements, cssRules: sheet.cssRules }); } } for (const styleSheet of this.element[PropertySymbol.ownerDocument].adoptedStyleSheets) { this.parseCSSRules({ elements: documentElements, cssRules: styleSheet.cssRules }); } styleAndElement = { element: null, cssTexts: [] }; } else if (styleAndElement.element[PropertySymbol.nodeType] === NodeTypeEnum_js_1.default.documentFragmentNode && styleAndElement.element.host) { const shadowRoot = styleAndElement.element; const styleSheets = (shadowRoot.querySelectorAll('style,link[rel="stylesheet"]')); styleAndElement = { element: shadowRoot.host, cssTexts: [] }; for (const styleSheet of styleSheets) { const sheet = styleSheet.sheet; if (sheet) { this.parseCSSRules({ elements: shadowRootElements, cssRules: sheet.cssRules, hostElement: styleAndElement }); } } for (const styleSheet of shadowRoot.adoptedStyleSheets) { this.parseCSSRules({ elements: shadowRootElements, cssRules: styleSheet.cssRules, hostElement: styleAndElement }); } shadowRootElements = []; } else { styleAndElement = { element: styleAndElement.element[PropertySymbol.parentNode], cssTexts: [] }; } } // Concatenates all parent element CSS to one string. const targetElement = parentElements[parentElements.length - 1]; const propertyManager = new CSSStyleDeclarationPropertyManager_js_1.default(); const cssVariables = {}; let rootFontSize = 16; let parentFontSize = 16; for (const parentElement of parentElements) { parentElement.cssTexts.sort((a, b) => a.priorityWeight - b.priorityWeight); let elementCSSText = ''; if (CSSStyleDeclarationElementDefaultCSS_js_1.default[parentElement.element[PropertySymbol.tagName]]) { if (typeof CSSStyleDeclarationElementDefaultCSS_js_1.default[parentElement.element[PropertySymbol.tagName]] === 'string') { elementCSSText += CSSStyleDeclarationElementDefaultCSS_js_1.default[parentElement.element[PropertySymbol.tagName]]; } else { for (const key of Object.keys(CSSStyleDeclarationElementDefaultCSS_js_1.default[parentElement.element[PropertySymbol.tagName]])) { if (key === 'default' || !!parentElement.element[key]) { elementCSSText += CSSStyleDeclarationElementDefaultCSS_js_1.default[parentElement.element[PropertySymbol.tagName]][key]; } } } elementCSSText += CSSStyleDeclarationElementDefaultCSS_js_1.default[parentElement.element[PropertySymbol.tagName]]; } for (const cssText of parentElement.cssTexts) { elementCSSText += cssText.cssText; } const elementStyleAttribute = parentElement.element[PropertySymbol.attributes]['style']; if (elementStyleAttribute) { elementCSSText += elementStyleAttribute[PropertySymbol.value]; } CSSStyleDeclarationCSSParser_js_1.default.parse(elementCSSText, (name, value, important) => { const isCSSVariable = name.startsWith('--'); if (isCSSVariable || CSSStyleDeclarationElementInheritedProperties_js_1.default[name] || parentElement === targetElement) { const cssValue = this.parseCSSVariablesInValue(value, cssVariables); if (cssValue && (!propertyManager.get(name)?.important || important)) { propertyManager.set(name, cssValue, important); if (isCSSVariable) { cssVariables[name] = cssValue; } else if (name === 'font' || name === 'font-size') { const fontSize = propertyManager.properties['font-size']; if (fontSize !== null) { const parsedValue = this.parseMeasurementsInValue({ value: fontSize.value, rootFontSize, parentFontSize, parentSize: parentFontSize }); if (parentElement.element[PropertySymbol.tagName] === 'HTML') { rootFontSize = parsedValue; } else if (parentElement !== targetElement) { parentFontSize = parsedValue; } } } } } }); } for (const name of CSSStyleDeclarationElementMeasurementProperties_js_1.default) { const property = propertyManager.properties[name]; if (property) { property.value = this.parseMeasurementsInValue({ value: property.value, rootFontSize, parentFontSize, // TODO: Only "font-size" is supported when using percentage values. Add support for other properties. parentSize: name === 'font-size' ? parentFontSize : null }); } } this.cache.propertyManager = propertyManager; return propertyManager; } /** * Applies CSS text to elements. * * @param options Options. * @param options.elements Elements. * @param options.cssRules CSS rules. * @param [options.hostElement] Host element. */ parseCSSRules(options) { if (!options.elements.length) { return; } const ownerWindow = this.element[PropertySymbol.ownerDocument][PropertySymbol.ownerWindow]; for (const rule of options.cssRules) { if (rule.type === CSSRuleTypeEnum_js_1.default.styleRule) { const selectorText = rule.selectorText; if (selectorText) { if (selectorText.startsWith(':host')) { if (options.hostElement) { options.hostElement.cssTexts.push({ cssText: rule[PropertySymbol.cssText], priorityWeight: 0 }); } } else { for (const element of options.elements) { const matchResult = QuerySelector_js_1.default.match(element.element, selectorText); if (matchResult) { element.cssTexts.push({ cssText: rule[PropertySymbol.cssText], priorityWeight: matchResult.priorityWeight }); } } } } } else if (rule.type === CSSRuleTypeEnum_js_1.default.mediaRule && // TODO: We need to send in a predfined root font size as it will otherwise be calculated using Window.getComputedStyle(), which will cause a never ending loop. Is there another solution? new MediaQueryList_js_1.default({ ownerWindow, media: rule.conditionText, rootFontSize: this.element[PropertySymbol.tagName] === 'HTML' ? 16 : null }).matches) { this.parseCSSRules({ elements: options.elements, cssRules: rule.cssRules, hostElement: options.hostElement }); } } } /** * Parses CSS variables in a value. * * @param value Value. * @param cssVariables CSS variables. * @returns CSS value. */ parseCSSVariablesInValue(value, cssVariables) { const regexp = new RegExp(CSS_VARIABLE_REGEXP); let newValue = value; let match; while ((match = regexp.exec(value)) !== null) { // Fallback value - E.g. var(--my-var, #FFFFFF) if (match[2] !== undefined) { newValue = newValue.replace(match[0], cssVariables[match[2]] || match[3]); } else { newValue = newValue.replace(match[0], cssVariables[match[1]] || ''); } } return newValue; } /** * Parses measurements in a value. * * @param options Options. * @param options.value Value. * @param options.rootFontSize Root font size. * @param options.parentFontSize Parent font size. * @param [options.parentSize] Parent width. * @returns CSS value. */ parseMeasurementsInValue(options) { if (WindowBrowserSettingsReader_js_1.default.getSettings(this.element[PropertySymbol.ownerDocument][PropertySymbol.ownerWindow]).disableComputedStyleRendering) { return options.value; } const regexp = new RegExp(CSS_MEASUREMENT_REGEXP); let newValue = options.value; let match; while ((match = regexp.exec(options.value)) !== null) { if (match[1] !== 'px') { const valueInPixels = CSSMeasurementConverter_js_1.default.toPixels({ ownerWindow: this.element[PropertySymbol.ownerDocument][PropertySymbol.ownerWindow], value: match[0], rootFontSize: options.rootFontSize, parentFontSize: options.parentFontSize, parentSize: options.parentSize }); if (valueInPixels !== null) { newValue = newValue.replace(match[0], valueInPixels + 'px'); } } } return newValue; } } exports.default = CSSStyleDeclarationElementStyle; //# sourceMappingURL=CSSStyleDeclarationElementStyle.cjs.map