Make solid an opt-in flag, disallow writing to `name` and `solid`
authorAlexander Ebert <ebert@woltlab.com>
Tue, 16 Aug 2022 14:10:06 +0000 (16:10 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Tue, 16 Aug 2022 14:14:39 +0000 (16:14 +0200)
Force the usage of `setIcon()` to set the desired icon.

global.d.ts
ts/WoltLabSuite/WebComponent/fa-icon.ts
wcfsetup/install/files/js/WoltLabSuite/WebComponent/fa-icon.js

index 251c2d10e3ccc9919605ddcb25d3921dfa8a4622..f6975377a8ec9047a91a37892328f5d2a74b4b36 100644 (file)
@@ -54,16 +54,15 @@ declare global {
   type ArbitraryObject = Record<string, unknown>;
 
   interface FaBrand extends HTMLElement {
-    name: string;
     size: IconSize;
   }
 
   interface FaIcon extends HTMLElement {
-    name: string;
-    solid: boolean;
+    readonly name: string;
+    readonly solid: boolean;
     size: IconSize;
 
-    setIcon: (name: string, isSolid: boolean) => void;
+    setIcon: (name: string, forceSolid?: boolean) => void;
   }
 
   interface HTMLElementTagNameMap {
index fb52d65ccf4df0090aa156593d02d63ffe439e18..6d85d78d489556f65f48694b22f88e19a958b5a1 100644 (file)
       }
     }
 
-    setIcon(name: string, isSolid: boolean): void {
+    setIcon(name: string, forceSolid = false): void {
       if (!this.isValidIconName(name)) {
         throw new TypeError(`The icon '${name}' is unknown or unsupported.`);
       }
 
-      if (!this.isValidIconStyle(name, isSolid)) {
-        throw new Error(`The icon '${name}' only supports the 'solid' style.`);
+      if (!forceSolid && !this.hasNonSolidStyle(name)) {
+        forceSolid = true;
       }
 
-      this.solid = isSolid;
-      this.name = name;
+      if (forceSolid) {
+        this.setAttribute("solid", "");
+      } else {
+        this.removeAttribute("solid");
+      }
+
+      this.setAttribute("name", name);
 
       this.updateIcon();
     }
@@ -68,8 +73,8 @@
       return name !== null && window.getFontAwesome6IconMetadata(name) !== undefined;
     }
 
-    private isValidIconStyle(name: string, isSolid: boolean): boolean {
-      if (!isSolid && isFontAwesome6Free()) {
+    private hasNonSolidStyle(name: string): boolean {
+      if (isFontAwesome6Free()) {
         const [, hasRegularVariant] = window.getFontAwesome6IconMetadata(name)!;
         if (!hasRegularVariant) {
           // Font Awesome 6 Free only includes solid icons with the
       return this.hasAttribute("solid");
     }
 
-    set solid(solid: boolean) {
-      if (solid) {
-        this.setAttribute("solid", "");
-      } else {
-        this.removeAttribute("solid");
-      }
-    }
-
     get name(): string {
       return this.getAttribute("name") || "";
     }
 
-    set name(name: string) {
-      if (!this.isValidIconName(name)) {
-        throw new Error(`Refused to set the unknown icon name '${name}'.`);
-      }
-
-      this.setAttribute("name", name);
-      this.updateIcon();
-    }
-
     get size(): IconSize {
       const size = this.getAttribute("size");
       if (size === null) {
index 2514e10fd8e33be80383d249324311cd78c40888..bcab3946bbec2f57fa25d190f5e609c913563865 100644 (file)
                 throw new TypeError(`The icon '${this.name}' is unknown or unsupported.`);
             }
         }
-        setIcon(name, isSolid) {
+        setIcon(name, forceSolid = false) {
             if (!this.isValidIconName(name)) {
                 throw new TypeError(`The icon '${name}' is unknown or unsupported.`);
             }
-            if (!this.isValidIconStyle(name, isSolid)) {
-                throw new Error(`The icon '${name}' only supports the 'solid' style.`);
+            if (!forceSolid && !this.hasNonSolidStyle(name)) {
+                forceSolid = true;
             }
-            this.solid = isSolid;
-            this.name = name;
+            if (forceSolid) {
+                this.setAttribute("solid", "");
+            }
+            else {
+                this.removeAttribute("solid");
+            }
+            this.setAttribute("name", name);
             this.updateIcon();
         }
         isValidIconName(name) {
             return name !== null && window.getFontAwesome6IconMetadata(name) !== undefined;
         }
-        isValidIconStyle(name, isSolid) {
-            if (!isSolid && isFontAwesome6Free()) {
+        hasNonSolidStyle(name) {
+            if (isFontAwesome6Free()) {
                 const [, hasRegularVariant] = window.getFontAwesome6IconMetadata(name);
                 if (!hasRegularVariant) {
                     // Font Awesome 6 Free only includes solid icons with the
         get solid() {
             return this.hasAttribute("solid");
         }
-        set solid(solid) {
-            if (solid) {
-                this.setAttribute("solid", "");
-            }
-            else {
-                this.removeAttribute("solid");
-            }
-        }
         get name() {
             return this.getAttribute("name") || "";
         }
-        set name(name) {
-            if (!this.isValidIconName(name)) {
-                throw new Error(`Refused to set the unknown icon name '${name}'.`);
-            }
-            this.setAttribute("name", name);
-            this.updateIcon();
-        }
         get size() {
             const size = this.getAttribute("size");
             if (size === null) {