From 7a24d5ae0c777d464e3939573658a5a49da54734 Mon Sep 17 00:00:00 2001 From: Alexander Ebert Date: Wed, 10 Aug 2022 12:53:37 +0200 Subject: [PATCH] Handle changes to the requested size of an icon --- ts/WoltLabSuite/WebComponent/fa-brand.ts | 43 +++++++++++++------ ts/WoltLabSuite/WebComponent/fa-icon.ts | 14 +++++- .../js/WoltLabSuite/WebComponent/fa-brand.js | 34 +++++++++++---- .../js/WoltLabSuite/WebComponent/fa-icon.js | 6 +++ .../IconFunctionTemplatePlugin.class.php | 8 ++-- 5 files changed, 78 insertions(+), 27 deletions(-) diff --git a/ts/WoltLabSuite/WebComponent/fa-brand.ts b/ts/WoltLabSuite/WebComponent/fa-brand.ts index 3ea5ea07e3..9c883e569d 100644 --- a/ts/WoltLabSuite/WebComponent/fa-brand.ts +++ b/ts/WoltLabSuite/WebComponent/fa-brand.ts @@ -1,5 +1,7 @@ (() => { - const HeightMap = new Map([ + type IconSize = number; + type RenderSize = number; + const HeightMap = new Map([ [16, 14], [24, 18], [32, 28], @@ -11,10 +13,13 @@ ]); class FaBrand extends HTMLElement { + private root?: ShadowRoot = undefined; + private svgStyle: HTMLStyleElement = document.createElement("style"); + connectedCallback() { this.validate(); - const root = this.prepareRoot(); + const root = this.getRoot(); const slot = document.createElement("slot"); slot.name = "svg"; @@ -29,24 +34,29 @@ } } - private prepareRoot(): ShadowRoot { - const root = this.attachShadow({ mode: "open" }); + private getRoot(): ShadowRoot { + if (this.root === undefined) { + this.root = this.attachShadow({ mode: "open" }); + + this.updateRenderSize(); + this.root.append(this.svgStyle); + } + + return this.root; + } - const iconHeight = HeightMap.get(this.size)!; - const style = document.createElement("style"); - style.textContent = ` + private updateRenderSize(): void { + const renderSize = HeightMap.get(this.size)!; + this.svgStyle.textContent = ` ::slotted(svg) { fill: currentColor; - height: ${iconHeight}px; + height: ${renderSize}px; shape-rendering: geometricprecision; } `; - root.append(style); - - return root; } - get size(): number { + get size(): IconSize { const size = this.getAttribute("size"); if (size === null) { return 0; @@ -54,6 +64,15 @@ return parseInt(size); } + + set size(size: number) { + if (!HeightMap.has(size)) { + throw new Error(`Refused to set the invalid icon size '${size}'.`); + } + + this.setAttribute("size", size.toString()); + this.updateRenderSize(); + } } window.customElements.define("fa-brand", FaBrand); diff --git a/ts/WoltLabSuite/WebComponent/fa-icon.ts b/ts/WoltLabSuite/WebComponent/fa-icon.ts index 913e5b7f24..2df931ed6d 100644 --- a/ts/WoltLabSuite/WebComponent/fa-icon.ts +++ b/ts/WoltLabSuite/WebComponent/fa-icon.ts @@ -13,7 +13,9 @@ return isFA6Free; } - const HeightMap = new Map([ + type IconSize = number; + type RenderSize = number; + const HeightMap = new Map([ [16, 14], [24, 18], [32, 28], @@ -120,7 +122,7 @@ this.setAttribute("name", name); } - get size(): number { + get size(): IconSize { const size = this.getAttribute("size"); if (size === null) { return 0; @@ -129,6 +131,14 @@ return parseInt(size); } + set size(size: number) { + if (!HeightMap.has(size)) { + throw new Error(`Refused to set the invalid icon size '${size}'.`); + } + + this.setAttribute("size", size.toString()); + } + static get observedAttributes() { return ["name"]; } diff --git a/wcfsetup/install/files/js/WoltLabSuite/WebComponent/fa-brand.js b/wcfsetup/install/files/js/WoltLabSuite/WebComponent/fa-brand.js index 455e957092..d538919009 100644 --- a/wcfsetup/install/files/js/WoltLabSuite/WebComponent/fa-brand.js +++ b/wcfsetup/install/files/js/WoltLabSuite/WebComponent/fa-brand.js @@ -11,9 +11,14 @@ [144, 130], ]); class FaBrand extends HTMLElement { + constructor() { + super(...arguments); + this.root = undefined; + this.svgStyle = document.createElement("style"); + } connectedCallback() { this.validate(); - const root = this.prepareRoot(); + const root = this.getRoot(); const slot = document.createElement("slot"); slot.name = "svg"; root.append(slot); @@ -26,19 +31,23 @@ throw new TypeError("Must provide a valid icon size."); } } - prepareRoot() { - const root = this.attachShadow({ mode: "open" }); - const iconHeight = HeightMap.get(this.size); - const style = document.createElement("style"); - style.textContent = ` + getRoot() { + if (this.root === undefined) { + this.root = this.attachShadow({ mode: "open" }); + this.updateRenderSize(); + this.root.append(this.svgStyle); + } + return this.root; + } + updateRenderSize() { + const renderSize = HeightMap.get(this.size); + this.svgStyle.textContent = ` ::slotted(svg) { fill: currentColor; - height: ${iconHeight}px; + height: ${renderSize}px; shape-rendering: geometricprecision; } `; - root.append(style); - return root; } get size() { const size = this.getAttribute("size"); @@ -47,6 +56,13 @@ } return parseInt(size); } + set size(size) { + if (!HeightMap.has(size)) { + throw new Error(`Refused to set the invalid icon size '${size}'.`); + } + this.setAttribute("size", size.toString()); + this.updateRenderSize(); + } } window.customElements.define("fa-brand", FaBrand); })(); diff --git a/wcfsetup/install/files/js/WoltLabSuite/WebComponent/fa-icon.js b/wcfsetup/install/files/js/WoltLabSuite/WebComponent/fa-icon.js index e6e379f8c8..044de90923 100644 --- a/wcfsetup/install/files/js/WoltLabSuite/WebComponent/fa-icon.js +++ b/wcfsetup/install/files/js/WoltLabSuite/WebComponent/fa-icon.js @@ -109,6 +109,12 @@ } return parseInt(size); } + set size(size) { + if (!HeightMap.has(size)) { + throw new Error(`Refused to set the invalid icon size '${size}'.`); + } + this.setAttribute("size", size.toString()); + } static get observedAttributes() { return ["name"]; } diff --git a/wcfsetup/install/files/lib/system/template/plugin/IconFunctionTemplatePlugin.class.php b/wcfsetup/install/files/lib/system/template/plugin/IconFunctionTemplatePlugin.class.php index a46911c979..783a86eddb 100644 --- a/wcfsetup/install/files/lib/system/template/plugin/IconFunctionTemplatePlugin.class.php +++ b/wcfsetup/install/files/lib/system/template/plugin/IconFunctionTemplatePlugin.class.php @@ -33,21 +33,21 @@ final class IconFunctionTemplatePlugin implements IFunctionTemplatePlugin $type = $tagArgs['type'] ?? ''; if (!\in_array($size, self::SIZES)) { - throw new \InvalidArgumentException("An unsupported size `{$size}` was requested."); + throw new \InvalidArgumentException("An unsupported size '{$size}' was requested."); } if ($name === '') { - throw new \InvalidArgumentException("The `name` attribute must be present and non-empty."); + throw new \InvalidArgumentException("The 'name' attribute must be present and non-empty."); } if ($type !== '' && !\in_array($type, self::TYPES)) { - throw new \InvalidArgumentException("An unsupported type `${type}` was specified."); + throw new \InvalidArgumentException("An unsupported type '{$type}' was specified."); } if ($type === 'brand') { $svgFile = \WCF_DIR . "icon/font-awesome/v6/brands/{$name}.svg"; if (!\file_exists($svgFile)) { - throw new \InvalidArgumentException("Unable to locate the icon for brand `${name}`."); + throw new \InvalidArgumentException("Unable to locate the icon for brand '{$name}'."); } $content = \file_get_contents($svgFile); -- 2.20.1