Overhaul the message share providers and buttons
authorAlexander Ebert <ebert@woltlab.com>
Sat, 13 Aug 2022 19:32:22 +0000 (21:32 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Sat, 13 Aug 2022 19:32:22 +0000 (21:32 +0200)
12 files changed:
com.woltlab.wcf/templates/headIncludeJavaScript.tpl
com.woltlab.wcf/templates/shareButtons.tpl
ts/WoltLabSuite/Core/BootstrapFrontend.ts
ts/WoltLabSuite/Core/Ui/Message/Share.ts
ts/WoltLabSuite/Core/Ui/Message/Share/Dialog.ts
ts/WoltLabSuite/Core/Ui/Message/Share/Providers.ts
wcfsetup/install/files/js/WoltLabSuite/Core/BootstrapFrontend.js
wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Message/Share.js
wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Message/Share/Dialog.js
wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Message/Share/Providers.js
wcfsetup/install/files/lib/system/template/plugin/IconFunctionTemplatePlugin.class.php
wcfsetup/install/files/style/ui/shareButtons.scss

index fa3e3a88dcba65d2941b0ddfc2ab70799de7c5d3..ece17e724320cdd557cc57d1dd3c3a6e7979afe1 100644 (file)
@@ -144,13 +144,6 @@ window.addEventListener('pageshow', function(event) {
                        'wcf.global.form.password.button.hide': '{jslang}wcf.global.form.password.button.hide{/jslang}',
                        'wcf.global.form.password.button.show': '{jslang}wcf.global.form.password.button.show{/jslang}',
                        'wcf.message.share': '{jslang}wcf.message.share{/jslang}',
-                       'wcf.message.share.facebook': '{jslang}wcf.message.share.facebook{/jslang}',
-                       'wcf.message.share.twitter': '{jslang}wcf.message.share.twitter{/jslang}',
-                       'wcf.message.share.reddit': '{jslang}wcf.message.share.reddit{/jslang}',
-                       'wcf.message.share.whatsApp': '{jslang}wcf.message.share.whatsApp{/jslang}',
-                       'wcf.message.share.linkedIn': '{jslang}wcf.message.share.linkedIn{/jslang}',
-                       'wcf.message.share.pinterest': '{jslang}wcf.message.share.pinterest{/jslang}',
-                       'wcf.message.share.xing': '{jslang}wcf.message.share.xing{/jslang}',
                        'wcf.message.share.permalink': '{jslang}wcf.message.share.permalink{/jslang}',
                        'wcf.message.share.permalink.bbcode': '{jslang}wcf.message.share.permalink.bbcode{/jslang}',
                        'wcf.message.share.permalink.html': '{jslang}wcf.message.share.permalink.html{/jslang}',
@@ -190,7 +183,16 @@ window.addEventListener('pageshow', function(event) {
                        enableUserPopover: {if $__wcf->getSession()->getPermission('user.profile.canViewUserProfile')}true{else}false{/if},
                        executeCronjobs: {if $executeCronjobs}true{else}false{/if},
                        {if ENABLE_SHARE_BUTTONS}
-                           shareButtonProviders: [{implode from="\n"|explode:SHARE_BUTTONS_PROVIDERS item=shareButtonProvider}'{$shareButtonProvider}'{/implode}],
+                               {assign var='__shareProviders' value="\n"|explode:SHARE_BUTTONS_PROVIDERS}
+                           shareButtonProviders: [
+                                       {if 'Facebook'|in_array:$__shareProviders}["Facebook", "{jslang}wcf.message.share.facebook{/jslang}", {icon size=24 name='facebook' type='brand' encodeJson=true}],{/if} 
+                                       {if 'Twitter'|in_array:$__shareProviders}["Twitter", "{jslang}wcf.message.share.twitter{/jslang}", {icon size=24 name='twitter' type='brand' encodeJson=true}],{/if} 
+                                       {if 'Reddit'|in_array:$__shareProviders}["Reddit", "{jslang}wcf.message.share.reddit{/jslang}", {icon size=24 name='reddit' type='brand' encodeJson=true}],{/if} 
+                                       {if 'WhatsApp'|in_array:$__shareProviders}["WhatsApp", "{jslang}wcf.message.share.whatsApp{/jslang}", {icon size=24 name='whatsapp' type='brand' encodeJson=true}],{/if} 
+                                       {if 'LinkedIn'|in_array:$__shareProviders}["LinkedIn", "{jslang}wcf.message.share.linkedIn{/jslang}", {icon size=24 name='linkedin-in' type='brand' encodeJson=true}],{/if} 
+                                       {if 'Pinterest'|in_array:$__shareProviders}["Pinterest", "{jslang}wcf.message.share.pinterest{/jslang}", {icon size=24 name='pinterest' type='brand' encodeJson=true}],{/if} 
+                                       {if 'XING'|in_array:$__shareProviders}["XING", "{jslang}wcf.message.share.xing{/jslang}", {icon size=24 name='xing' type='brand' encodeJson=true}],{/if} 
+                               ],
                        {/if}
                        styleChanger: {if $__wcf->getStyleHandler()->showStyleChanger()}true{else}false{/if}
                });
index a7b5293e198d44029318fbc2e23602684cd7c67b..5744f25d0999792832b3764029e85f69d4698625 100644 (file)
@@ -4,58 +4,58 @@
        <ul class="inlineList">
                {if 'Facebook'|in_array:$__share_buttons_providers}
                        <li>
-                               <a href="#" role="button" class="button jsShareFacebook" title="{lang}wcf.message.share.facebook{/lang}" aria-label="{lang}wcf.message.share.facebook{/lang}">
+                               <button class="button messageShareProvider" title="{lang}wcf.message.share.facebook{/lang}" aria-label="{lang}wcf.message.share.facebook{/lang}" data-identifier="Facebook">
                                        {icon size=24 name='facebook' type='brand'}
                                        <span>{lang}wcf.message.share.facebook{/lang}</span>
-                               </a>
+                               </button>
                        </li>
                {/if}
                {if 'Twitter'|in_array:$__share_buttons_providers}
                        <li>
-                               <a href="#" role="button" class="button jsShareTwitter" title="{lang}wcf.message.share.twitter{/lang}" aria-label="{lang}wcf.message.share.twitter{/lang}">
+                               <button class="button messageShareProvider" title="{lang}wcf.message.share.twitter{/lang}" aria-label="{lang}wcf.message.share.twitter{/lang}" data-identifier="Twitter">
                                        {icon size=24 name='twitter' type='brand'}
                                        <span>{lang}wcf.message.share.twitter{/lang}</span>
-                               </a>
+                               </button>
                        </li>
                {/if}
                {if 'Reddit'|in_array:$__share_buttons_providers}
                        <li>
-                               <a href="#" role="button" class="button jsShareReddit" title="{lang}wcf.message.share.reddit{/lang}" aria-label="{lang}wcf.message.share.reddit{/lang}">
+                               <button class="button messageShareProvider" title="{lang}wcf.message.share.reddit{/lang}" aria-label="{lang}wcf.message.share.reddit{/lang}" data-identifier="Reddit">
                                        {icon size=24 name='reddit' type='brand'}
                                        <span>{lang}wcf.message.share.reddit{/lang}</span>
-                               </a>
+                               </button>
                        </li>
                {/if}
                {if 'WhatsApp'|in_array:$__share_buttons_providers}
                        <li>
-                               <a href="#" role="button" class="button jsShareWhatsApp" title="{lang}wcf.message.share.whatsApp{/lang}" aria-label="{lang}wcf.message.share.whatsApp{/lang}">
-                                       <span class="icon icon24 fa-whatsapp jsTooltip"></span>
+                               <button class="button messageShareProvider" title="{lang}wcf.message.share.whatsApp{/lang}" aria-label="{lang}wcf.message.share.whatsApp{/lang}" data-identifier="WhatsApp">
+                                       {icon size=24 name='whatsapp' type='brand'}
                                        <span>{lang}wcf.message.share.whatsApp{/lang}</span>
-                               </a>
+                               </button>
                        </li>
                {/if}
                {if 'LinkedIn'|in_array:$__share_buttons_providers}
                        <li>
-                               <a href="#" role="button" class="button jsShareLinkedIn" title="{lang}wcf.message.share.linkedIn{/lang}" aria-label="{lang}wcf.message.share.linkedIn{/lang}">
-                                       <span class="icon icon24 fa-linkedin jsTooltip"></span>
+                               <button href="#" role="button" class="button messageShareProvider" title="{lang}wcf.message.share.linkedIn{/lang}" aria-label="{lang}wcf.message.share.linkedIn{/lang}" data-identifier="LinkedIn">
+                                       {icon size=24 name='linkedin-in' type='brand'}
                                        <span>{lang}wcf.message.share.linkedIn{/lang}</span>
-                               </a>
+                               </button>
                        </li>
                {/if}
                {if 'Pinterest'|in_array:$__share_buttons_providers}
                        <li>
-                               <a href="#" role="button" class="button jsSharePinterest" title="{lang}wcf.message.share.pinterest{/lang}" aria-label="{lang}wcf.message.share.pinterest{/lang}">
-                                       <span class="icon icon24 fa-pinterest-p jsTooltip"></span>
+                               <button class="button messageShareProvider" title="{lang}wcf.message.share.pinterest{/lang}" aria-label="{lang}wcf.message.share.pinterest{/lang}" data-identifier="Pinterest">
+                                       {icon size=24 name='pinterest' type='brand'}
                                        <span>{lang}wcf.message.share.pinterest{/lang}</span>
-                               </a>
+                               </button>
                        </li>
                {/if}
                {if 'XING'|in_array:$__share_buttons_providers}
                        <li>
-                               <a href="#" role="button" class="button jsShareXing" title="{lang}wcf.message.share.xing{/lang}" aria-label="{lang}wcf.message.share.xing{/lang}">
-                                       <span class="icon icon24 fa-xing jsTooltip"></span>
+                               <button class="button messageShareProvider" title="{lang}wcf.message.share.xing{/lang}" aria-label="{lang}wcf.message.share.xing{/lang}" data-identifier="XING">
+                                       {icon size=24 name='xing' type='brand'}
                                        <span>{lang}wcf.message.share.xing{/lang}</span>
-                               </a>
+                               </button>
                        </li>
                {/if}
                {event name='buttons'}
index c626dfbf76f4be8450ab3a1ce3a9065a32622537..679618f0d2ab3a98e1a216e549a4273a2e2e4a0b 100644 (file)
@@ -15,7 +15,7 @@ import * as UiPageHeaderMenu from "./Ui/Page/Header/Menu";
 import * as UiMessageUserConsent from "./Ui/Message/UserConsent";
 import * as Ajax from "./Ajax";
 import * as UiMessageShareDialog from "./Ui/Message/Share/Dialog";
-import * as UiMessageShareProviders from "./Ui/Message/Share/Providers";
+import { ShareProvider, addShareProviders } from "./Ui/Message/Share/Providers";
 import * as UiFeedDialog from "./Ui/Feed/Dialog";
 import User from "./User";
 import UiPageMenuMainFrontend from "./Ui/Page/Menu/Main/Frontend";
@@ -27,7 +27,7 @@ interface BootstrapOptions {
   };
   enableUserPopover: boolean;
   executeCronjobs: boolean;
-  shareButtonProviders?: string[];
+  shareButtonProviders?: ShareProvider[];
   styleChanger: boolean;
 }
 
@@ -98,7 +98,9 @@ export function setup(options: BootstrapOptions): void {
 
   UiMessageUserConsent.init();
 
-  UiMessageShareProviders.enableShareProviders(options.shareButtonProviders || []);
+  if (options.shareButtonProviders) {
+    addShareProviders(options.shareButtonProviders);
+  }
   UiMessageShareDialog.setup();
 
   if (User.userId) {
index 532536687bd8f81df94d7f138c77b14392f622fd..c7908d55072cb6f312acb33e8fef6072bb945c86 100644 (file)
@@ -57,35 +57,35 @@ export function init(): void {
 
     const providers: Providers = {
       facebook: {
-        link: container.querySelector(".jsShareFacebook"),
+        link: container.querySelector('.messageShareProvider[data-identifier="Facebook"]'),
         share(event: MouseEvent): void {
           event.preventDefault();
           share("facebook", "https://www.facebook.com/sharer.php?u={pageURL}&t={text}", true, pageUrl);
         },
       },
       reddit: {
-        link: container.querySelector(".jsShareReddit"),
+        link: container.querySelector('.messageShareProvider[data-identifier="Reddit"]'),
         share(event: MouseEvent): void {
           event.preventDefault();
           share("reddit", "https://ssl.reddit.com/submit?url={pageURL}", false, pageUrl);
         },
       },
       twitter: {
-        link: container.querySelector(".jsShareTwitter"),
+        link: container.querySelector('.messageShareProvider[data-identifier="Twitter"]'),
         share(event: MouseEvent): void {
           event.preventDefault();
           share("twitter", "https://twitter.com/share?url={pageURL}&text={text}", false, pageUrl);
         },
       },
       linkedIn: {
-        link: container.querySelector(".jsShareLinkedIn"),
+        link: container.querySelector('.messageShareProvider[data-identifier="LinkedIn"]'),
         share(event: MouseEvent): void {
           event.preventDefault();
           share("linkedIn", "https://www.linkedin.com/cws/share?url={pageURL}", false, pageUrl);
         },
       },
       pinterest: {
-        link: container.querySelector(".jsSharePinterest"),
+        link: container.querySelector('.messageShareProvider[data-identifier="Pinterest"]'),
         share(event: MouseEvent): void {
           event.preventDefault();
           share(
@@ -97,14 +97,14 @@ export function init(): void {
         },
       },
       xing: {
-        link: container.querySelector(".jsShareXing"),
+        link: container.querySelector('.messageShareProvider[data-identifier="XING"]'),
         share(event: MouseEvent): void {
           event.preventDefault();
           share("xing", "https://www.xing.com/social_plugins/share?url={pageURL}", false, pageUrl);
         },
       },
       whatsApp: {
-        link: container.querySelector(".jsShareWhatsApp"),
+        link: container.querySelector('.messageShareProvider[data-identifier="WhatsApp"]'),
         share(event: MouseEvent): void {
           event.preventDefault();
           window.location.href = "https://api.whatsapp.com/send?text=" + _pageDescription + "%20" + _pageUrl;
index ff5ad29f57c3ee65365b454430a8d0e91713291f..7613f877b06f1abd687bdc4cb5de8e64479ccc82 100644 (file)
@@ -16,7 +16,7 @@ import * as UiNotification from "../../Notification";
 import * as StringUtil from "../../../StringUtil";
 import DomChangeListener from "../../../Dom/Change/Listener";
 import * as UiMessageShare from "../Share";
-import * as UiMessageShareProviders from "./Providers";
+import { getShareProviders } from "./Providers";
 
 const shareButtons = new WeakSet<HTMLElement>();
 
@@ -74,9 +74,11 @@ function getDialogElement(label: string, value: string): string {
       <dd>
         <div class="inputAddon">
           <input type="text" class="long" readonly value="${StringUtil.escapeHTML(value)}">
-          <a href="#" class="inputSuffix button jsTooltip shareDialogCopyButton" title="${Language.get(
+          <button class="inputSuffix button jsTooltip shareDialogCopyButton" title="${Language.get(
             "wcf.message.share.copy",
-          )}"><span class="icon icon16 fa-files-o pointer"></span></a>
+          )}">
+            <fa-icon size="16" name="copy"></fa-icon>
+          </a>
         </div>
       </dd>
     </dl>
@@ -84,16 +86,16 @@ function getDialogElement(label: string, value: string): string {
 }
 
 function getProviderButtons(): string {
-  const providerButtons = Array.from(UiMessageShareProviders.getEnabledProviders())
+  const providerButtons = Array.from(getShareProviders())
     .map((provider) => {
-      const label = Language.get(provider.label);
+      const [identifier, label, icon] = provider;
 
       return `
       <li>
-        <a href="#" role="button" class="button small ${provider.cssClass}" title="${label}" aria-label="${label}">
-          <span class="icon icon24 ${provider.iconClassName}"></span>
+        <button class="button small messageShareProvider" title="${label}" aria-label="${label}" data-identifier="${identifier}">
+          ${icon}
           <span>${label}</span>
-        </a>
+        </button>
       </li>
     `;
     })
@@ -152,9 +154,9 @@ function openDialog(event: MouseEvent): void {
           <dd>
               <button class="button shareDialogNativeButton" data-url="${StringUtil.escapeHTML(
                 target.href,
-              )}" data-title="${StringUtil.escapeHTML(target.dataset.linkTitle || "")}">${Language.get(
-        "wcf.message.share.nativeShare",
-      )}</button>
+              )}" data-title="${StringUtil.escapeHTML(target.dataset.linkTitle || "")}">
+                ${Language.get("wcf.message.share.nativeShare")}
+              </button>
           </dd>
         </dl>
       `;
index 0a4a1ae1e779c320399d7528299080fa0b394833..2f56a66a8c37a06f605cd400397440afa07ff46c 100644 (file)
@@ -7,92 +7,21 @@
  * @module  WoltLabSuite/Core/Ui/Message/Share/Providers
  */
 
-export interface ShareProvider {
-  cssClass: string;
-  iconClassName: string;
-  label: string;
-}
-
-const enabledProviders = new Set<ShareProvider>();
-const providers = new Map<string, ShareProvider>([
-  [
-    "Facebook",
-    {
-      cssClass: "jsShareFacebook",
-      iconClassName: "fa-facebook-official",
-      label: "wcf.message.share.facebook",
-    },
-  ],
-  [
-    "Twitter",
-    {
-      cssClass: "jsShareTwitter",
-      iconClassName: "fa-twitter",
-      label: "wcf.message.share.twitter",
-    },
-  ],
-  [
-    "Reddit",
-    {
-      cssClass: "jsShareReddit",
-      iconClassName: "fa-reddit",
-      label: "wcf.message.share.reddit",
-    },
-  ],
-  [
-    "WhatsApp",
-    {
-      cssClass: "jsShareWhatsApp",
-      iconClassName: "fa-whatsapp",
-      label: "wcf.message.share.whatsApp",
-    },
-  ],
-  [
-    "LinkedIn",
-    {
-      cssClass: "jsShareLinkedIn",
-      iconClassName: "fa-linkedin",
-      label: "wcf.message.share.linkedIn",
-    },
-  ],
-  [
-    "Pinterest",
-    {
-      cssClass: "jsSharePinterest",
-      iconClassName: "fa-pinterest-p",
-      label: "wcf.message.share.pinterest",
-    },
-  ],
-  [
-    "XING",
-    {
-      cssClass: "jsShareXing",
-      iconClassName: "fa-xing",
-      label: "wcf.message.share.xing",
-    },
-  ],
-]);
+type Identifier = string;
+type Label = string;
+type Icon = string;
+export type ShareProvider = [Identifier, Label, Icon];
 
-export function addShareProvider(providerName: string, provider: ShareProvider): void {
-  if (providers.has(providerName)) {
-    throw new Error(`A share provider with name "${providerName}" already exists.`);
-  }
+const providers = new Set<ShareProvider>();
 
-  providers.set(providerName, provider);
+export function addShareProvider(shareProvider: ShareProvider): void {
+  providers.add(shareProvider);
 }
 
-export function enableShareProviders(providerNames: string[]): void {
-  providerNames.forEach((providerName) => {
-    if (providers.has(providerName)) {
-      enabledProviders.add(providers.get(providerName)!);
-    }
-  });
+export function addShareProviders(shareProviders: ShareProvider[]): void {
+  shareProviders.forEach((shareProvider) => addShareProvider(shareProvider));
 }
 
-export function getProviders(): ReadonlyMap<string, ShareProvider> {
+export function getShareProviders(): ReadonlySet<ShareProvider> {
   return providers;
 }
-
-export function getEnabledProviders(): ReadonlySet<ShareProvider> {
-  return enabledProviders;
-}
index c41b5d6ecd9519d13431db9b5558228ba9fdea29..06cbd517aa26bd2a38e5ef0b3c3f26250fdbc4cb 100644 (file)
@@ -6,7 +6,7 @@
  * @license  GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @module  WoltLabSuite/Core/BootstrapFrontend
  */
-define(["require", "exports", "tslib", "./BackgroundQueue", "./Bootstrap", "./Controller/Popover", "./Ui/User/Ignore", "./Ui/Page/Header/Menu", "./Ui/Message/UserConsent", "./Ajax", "./Ui/Message/Share/Dialog", "./Ui/Message/Share/Providers", "./Ui/Feed/Dialog", "./User", "./Ui/Page/Menu/Main/Frontend"], function (require, exports, tslib_1, BackgroundQueue, Bootstrap, ControllerPopover, UiUserIgnore, UiPageHeaderMenu, UiMessageUserConsent, Ajax, UiMessageShareDialog, UiMessageShareProviders, UiFeedDialog, User_1, Frontend_1) {
+define(["require", "exports", "tslib", "./BackgroundQueue", "./Bootstrap", "./Controller/Popover", "./Ui/User/Ignore", "./Ui/Page/Header/Menu", "./Ui/Message/UserConsent", "./Ajax", "./Ui/Message/Share/Dialog", "./Ui/Message/Share/Providers", "./Ui/Feed/Dialog", "./User", "./Ui/Page/Menu/Main/Frontend"], function (require, exports, tslib_1, BackgroundQueue, Bootstrap, ControllerPopover, UiUserIgnore, UiPageHeaderMenu, UiMessageUserConsent, Ajax, UiMessageShareDialog, Providers_1, UiFeedDialog, User_1, Frontend_1) {
     "use strict";
     Object.defineProperty(exports, "__esModule", { value: true });
     exports.setup = void 0;
@@ -18,7 +18,6 @@ define(["require", "exports", "tslib", "./BackgroundQueue", "./Bootstrap", "./Co
     UiMessageUserConsent = tslib_1.__importStar(UiMessageUserConsent);
     Ajax = tslib_1.__importStar(Ajax);
     UiMessageShareDialog = tslib_1.__importStar(UiMessageShareDialog);
-    UiMessageShareProviders = tslib_1.__importStar(UiMessageShareProviders);
     UiFeedDialog = tslib_1.__importStar(UiFeedDialog);
     User_1 = tslib_1.__importDefault(User_1);
     Frontend_1 = tslib_1.__importDefault(Frontend_1);
@@ -77,7 +76,9 @@ define(["require", "exports", "tslib", "./BackgroundQueue", "./Bootstrap", "./Co
             UiUserIgnore.init();
         }
         UiMessageUserConsent.init();
-        UiMessageShareProviders.enableShareProviders(options.shareButtonProviders || []);
+        if (options.shareButtonProviders) {
+            (0, Providers_1.addShareProviders)(options.shareButtonProviders);
+        }
         UiMessageShareDialog.setup();
         if (User_1.default.userId) {
             UiFeedDialog.setup();
index ebab5b4b6ddf96f20b3af76f5d9a1979dbf7d7cf..a04accabdd8f1b00b9f2f289e43037d85cf97a97 100644 (file)
@@ -38,49 +38,49 @@ define(["require", "exports", "tslib", "../../Event/Handler", "../../StringUtil"
             }
             const providers = {
                 facebook: {
-                    link: container.querySelector(".jsShareFacebook"),
+                    link: container.querySelector('.messageShareProvider[data-identifier="Facebook"]'),
                     share(event) {
                         event.preventDefault();
                         share("facebook", "https://www.facebook.com/sharer.php?u={pageURL}&t={text}", true, pageUrl);
                     },
                 },
                 reddit: {
-                    link: container.querySelector(".jsShareReddit"),
+                    link: container.querySelector('.messageShareProvider[data-identifier="Reddit"]'),
                     share(event) {
                         event.preventDefault();
                         share("reddit", "https://ssl.reddit.com/submit?url={pageURL}", false, pageUrl);
                     },
                 },
                 twitter: {
-                    link: container.querySelector(".jsShareTwitter"),
+                    link: container.querySelector('.messageShareProvider[data-identifier="Twitter"]'),
                     share(event) {
                         event.preventDefault();
                         share("twitter", "https://twitter.com/share?url={pageURL}&text={text}", false, pageUrl);
                     },
                 },
                 linkedIn: {
-                    link: container.querySelector(".jsShareLinkedIn"),
+                    link: container.querySelector('.messageShareProvider[data-identifier="LinkedIn"]'),
                     share(event) {
                         event.preventDefault();
                         share("linkedIn", "https://www.linkedin.com/cws/share?url={pageURL}", false, pageUrl);
                     },
                 },
                 pinterest: {
-                    link: container.querySelector(".jsSharePinterest"),
+                    link: container.querySelector('.messageShareProvider[data-identifier="Pinterest"]'),
                     share(event) {
                         event.preventDefault();
                         share("pinterest", "https://www.pinterest.com/pin/create/link/?url={pageURL}&description={text}", false, pageUrl);
                     },
                 },
                 xing: {
-                    link: container.querySelector(".jsShareXing"),
+                    link: container.querySelector('.messageShareProvider[data-identifier="XING"]'),
                     share(event) {
                         event.preventDefault();
                         share("xing", "https://www.xing.com/social_plugins/share?url={pageURL}", false, pageUrl);
                     },
                 },
                 whatsApp: {
-                    link: container.querySelector(".jsShareWhatsApp"),
+                    link: container.querySelector('.messageShareProvider[data-identifier="WhatsApp"]'),
                     share(event) {
                         event.preventDefault();
                         window.location.href = "https://api.whatsapp.com/send?text=" + _pageDescription + "%20" + _pageUrl;
index 0a4480febe97a21bf839cb4a916bbcddcb897dfe..8b9f74d5d9c3b36a0019237045ea00a8400d8653 100644 (file)
@@ -6,7 +6,7 @@
  * @license  GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @module  WoltLabSuite/Core/Ui/Message/Share/Dialog
  */
-define(["require", "exports", "tslib", "../../Dialog", "../../../Dom/Util", "../../../Dom/Traverse", "../../../Language", "../../../Clipboard", "../../Notification", "../../../StringUtil", "../../../Dom/Change/Listener", "../Share", "./Providers"], function (require, exports, tslib_1, Dialog_1, Util_1, DomTraverse, Language, Clipboard, UiNotification, StringUtil, Listener_1, UiMessageShare, UiMessageShareProviders) {
+define(["require", "exports", "tslib", "../../Dialog", "../../../Dom/Util", "../../../Dom/Traverse", "../../../Language", "../../../Clipboard", "../../Notification", "../../../StringUtil", "../../../Dom/Change/Listener", "../Share", "./Providers"], function (require, exports, tslib_1, Dialog_1, Util_1, DomTraverse, Language, Clipboard, UiNotification, StringUtil, Listener_1, UiMessageShare, Providers_1) {
     "use strict";
     Object.defineProperty(exports, "__esModule", { value: true });
     exports.setup = void 0;
@@ -19,7 +19,6 @@ define(["require", "exports", "tslib", "../../Dialog", "../../../Dom/Util", "../
     StringUtil = tslib_1.__importStar(StringUtil);
     Listener_1 = tslib_1.__importDefault(Listener_1);
     UiMessageShare = tslib_1.__importStar(UiMessageShare);
-    UiMessageShareProviders = tslib_1.__importStar(UiMessageShareProviders);
     const shareButtons = new WeakSet();
     const offerNativeSharing = window.navigator.share !== undefined;
     /**
@@ -59,22 +58,24 @@ define(["require", "exports", "tslib", "../../Dialog", "../../../Dom/Util", "../
       <dd>
         <div class="inputAddon">
           <input type="text" class="long" readonly value="${StringUtil.escapeHTML(value)}">
-          <a href="#" class="inputSuffix button jsTooltip shareDialogCopyButton" title="${Language.get("wcf.message.share.copy")}"><span class="icon icon16 fa-files-o pointer"></span></a>
+          <button class="inputSuffix button jsTooltip shareDialogCopyButton" title="${Language.get("wcf.message.share.copy")}">
+            <fa-icon size="16" name="copy"></fa-icon>
+          </a>
         </div>
       </dd>
     </dl>
   `;
     }
     function getProviderButtons() {
-        const providerButtons = Array.from(UiMessageShareProviders.getEnabledProviders())
+        const providerButtons = Array.from((0, Providers_1.getShareProviders)())
             .map((provider) => {
-            const label = Language.get(provider.label);
+            const [identifier, label, icon] = provider;
             return `
       <li>
-        <a href="#" role="button" class="button small ${provider.cssClass}" title="${label}" aria-label="${label}">
-          <span class="icon icon24 ${provider.iconClassName}"></span>
+        <button class="button small messageShareProvider" title="${label}" aria-label="${label}" data-identifier="${identifier}">
+          ${icon}
           <span>${label}</span>
-        </a>
+        </button>
       </li>
     `;
         })
@@ -122,7 +123,9 @@ define(["require", "exports", "tslib", "../../Dialog", "../../../Dom/Util", "../
         <dl>
           <dt></dt>
           <dd>
-              <button class="button shareDialogNativeButton" data-url="${StringUtil.escapeHTML(target.href)}" data-title="${StringUtil.escapeHTML(target.dataset.linkTitle || "")}">${Language.get("wcf.message.share.nativeShare")}</button>
+              <button class="button shareDialogNativeButton" data-url="${StringUtil.escapeHTML(target.href)}" data-title="${StringUtil.escapeHTML(target.dataset.linkTitle || "")}">
+                ${Language.get("wcf.message.share.nativeShare")}
+              </button>
           </dd>
         </dl>
       `;
index bad89cf6ee1c67e131c6eba5cec5f15c4ff4db2b..028f664590644218323c3d7d663af6317ec321db 100644 (file)
@@ -9,87 +9,18 @@
 define(["require", "exports"], function (require, exports) {
     "use strict";
     Object.defineProperty(exports, "__esModule", { value: true });
-    exports.getEnabledProviders = exports.getProviders = exports.enableShareProviders = exports.addShareProvider = void 0;
-    const enabledProviders = new Set();
-    const providers = new Map([
-        [
-            "Facebook",
-            {
-                cssClass: "jsShareFacebook",
-                iconClassName: "fa-facebook-official",
-                label: "wcf.message.share.facebook",
-            },
-        ],
-        [
-            "Twitter",
-            {
-                cssClass: "jsShareTwitter",
-                iconClassName: "fa-twitter",
-                label: "wcf.message.share.twitter",
-            },
-        ],
-        [
-            "Reddit",
-            {
-                cssClass: "jsShareReddit",
-                iconClassName: "fa-reddit",
-                label: "wcf.message.share.reddit",
-            },
-        ],
-        [
-            "WhatsApp",
-            {
-                cssClass: "jsShareWhatsApp",
-                iconClassName: "fa-whatsapp",
-                label: "wcf.message.share.whatsApp",
-            },
-        ],
-        [
-            "LinkedIn",
-            {
-                cssClass: "jsShareLinkedIn",
-                iconClassName: "fa-linkedin",
-                label: "wcf.message.share.linkedIn",
-            },
-        ],
-        [
-            "Pinterest",
-            {
-                cssClass: "jsSharePinterest",
-                iconClassName: "fa-pinterest-p",
-                label: "wcf.message.share.pinterest",
-            },
-        ],
-        [
-            "XING",
-            {
-                cssClass: "jsShareXing",
-                iconClassName: "fa-xing",
-                label: "wcf.message.share.xing",
-            },
-        ],
-    ]);
-    function addShareProvider(providerName, provider) {
-        if (providers.has(providerName)) {
-            throw new Error(`A share provider with name "${providerName}" already exists.`);
-        }
-        providers.set(providerName, provider);
+    exports.getShareProviders = exports.addShareProviders = exports.addShareProvider = void 0;
+    const providers = new Set();
+    function addShareProvider(shareProvider) {
+        providers.add(shareProvider);
     }
     exports.addShareProvider = addShareProvider;
-    function enableShareProviders(providerNames) {
-        providerNames.forEach((providerName) => {
-            if (providers.has(providerName)) {
-                enabledProviders.add(providers.get(providerName));
-            }
-        });
+    function addShareProviders(shareProviders) {
+        shareProviders.forEach((shareProvider) => addShareProvider(shareProvider));
     }
-    exports.enableShareProviders = enableShareProviders;
-    function getProviders() {
+    exports.addShareProviders = addShareProviders;
+    function getShareProviders() {
         return providers;
     }
-    exports.getProviders = getProviders;
-    function getEnabledProviders() {
-        return enabledProviders;
-    }
-    exports.getEnabledProviders = getEnabledProviders;
+    exports.getShareProviders = getShareProviders;
 });
index 783a86eddb9c833b1a746e3d8c36e8fb246d68f9..ac23755e95bdce8cf169999ae3e4dee41eca2018 100644 (file)
@@ -3,6 +3,7 @@
 namespace wcf\system\template\plugin;
 
 use wcf\system\template\TemplateEngine;
+use wcf\util\JSON;
 
 /**
  * Template compiler plugin that embeds icons into the page. The
@@ -31,6 +32,7 @@ final class IconFunctionTemplatePlugin implements IFunctionTemplatePlugin
         $size = \intval($tagArgs['size'] ?? 0);
         $name = $tagArgs['name'] ?? '';
         $type = $tagArgs['type'] ?? '';
+        $encodeJson = $tagArgs['encodeJson'] ?? '';
 
         if (!\in_array($size, self::SIZES)) {
             throw new \InvalidArgumentException("An unsupported size '{$size}' was requested.");
@@ -44,6 +46,16 @@ final class IconFunctionTemplatePlugin implements IFunctionTemplatePlugin
             throw new \InvalidArgumentException("An unsupported type '{$type}' was specified.");
         }
 
+        $icon = $this->getIcon($type, $name, $size);
+        if ($encodeJson) {
+            return JSON::encode($icon);
+        }
+
+        return $icon;
+    }
+
+    private function getIcon(string $type, string $name, int $size): string
+    {
         if ($type === 'brand') {
             $svgFile = \WCF_DIR . "icon/font-awesome/v6/brands/{$name}.svg";
             if (!\file_exists($svgFile)) {
index d41ec3dbe81013942d77a1083034359ba5339053..f71bf12e3751412b424ceb8d88bd08bec0039166 100644 (file)
@@ -34,104 +34,78 @@ $shareXingBackground: rgba(0, 101, 103, 1);
                }
        }
 
-       .jsShareFacebook {
-               background-color: $shareFacebookBackground;
-               color: rgba(255, 255, 255, 1);
-       }
+       .messageShareProvider {
+               &[data-identifier="Facebook"] {
+                       background-color: $shareFacebookBackground;
+                       color: rgba(255, 255, 255, 1);
+               }
 
-       .jsShareTwitter {
-               background-color: $shareTwitterBackground;
-               color: rgba(255, 255, 255, 1);
+               &[data-identifier="Twitter"] {
+                       background-color: $shareTwitterBackground;
+                       color: rgba(255, 255, 255, 1);
+               }
+
+               &[data-identifier="Reddit"] {
+                       background-color: $shareRedditBackground;
+                       color: rgba(255, 255, 255, 1);
+               }
+
+               &[data-identifier="WhatsApp"] {
+                       background-color: $shareWhatsAppBackground;
+                       color: rgba(255, 255, 255, 1);
+               }
+
+               &[data-identifier="LinkedIn"] {
+                       background-color: $shareLinkedInBackground;
+                       color: rgba(255, 255, 255, 1);
+               }
+
+               &[data-identifier="Pinterest"] {
+                       background-color: $sharePinterestBackground;
+                       color: rgba(255, 255, 255, 1);
+               }
+
+               &[data-identifier="XING"] {
+                       background-color: $shareXingBackground;
+                       color: rgba(255, 255, 255, 1);
+               }
        }
+}
 
-       .jsShareGoogle {
-               background-color: $shareGoogleBackground;
+/* hover states are only applied to non-touch devices to avoid "leftover" hover states after taps */
+html:not(.touch) .messageShareButtons .messageShareProvider {
+       &[data-identifier="Facebook"]:hover {
+               background-color: darken($shareFacebookBackground, 10%);
                color: rgba(255, 255, 255, 1);
        }
 
-       .jsShareReddit {
-               background-color: $shareRedditBackground;
+       &[data-identifier="Twitter"]:hover {
+               background-color: darken($shareTwitterBackground, 10%);
                color: rgba(255, 255, 255, 1);
        }
 
-       .jsShareWhatsApp {
-               background-color: $shareWhatsAppBackground;
+       &[data-identifier="Reddit"]:hover {
+               background-color: darken($shareRedditBackground, 10%);
                color: rgba(255, 255, 255, 1);
        }
 
-       .jsShareLinkedIn {
-               background-color: $shareLinkedInBackground;
+       &[data-identifier="WhatsApp"]:hover {
+               background-color: darken($shareWhatsAppBackground, 10%);
                color: rgba(255, 255, 255, 1);
        }
 
-       .jsSharePinterest {
-               background-color: $sharePinterestBackground;
+       &[data-identifier="LinkedIn"]:hover {
+               background-color: darken($shareLinkedInBackground, 10%);
                color: rgba(255, 255, 255, 1);
        }
 
-       .jsShareXing {
-               background-color: $shareXingBackground;
+       &[data-identifier="Pinterest"]:hover {
+               background-color: darken($sharePinterestBackground, 10%);
                color: rgba(255, 255, 255, 1);
        }
-}
-
-/* hover states are only applied to non-touch devices to avoid "leftover" hover states after taps */
-html:not(.touch) {
-       .messageShareButtons {
-               .jsShareFacebook {
-                       &:hover {
-                               background-color: darken($shareFacebookBackground, 10%);
-                               color: rgba(255, 255, 255, 1);
-                       }
-               }
 
-               .jsShareTwitter {
-                       &:hover {
-                               background-color: darken($shareTwitterBackground, 10%);
-                               color: rgba(255, 255, 255, 1);
-                       }
-               }
-
-               .jsShareGoogle {
-                       &:hover {
-                               background-color: darken($shareGoogleBackground, 10%);
-                               color: rgba(255, 255, 255, 1);
-                       }
-               }
-
-               .jsShareReddit {
-                       &:hover {
-                               background-color: darken($shareRedditBackground, 10%);
-                               color: rgba(255, 255, 255, 1);
-                       }
-               }
-
-               .jsShareWhatsApp {
-                       &:hover {
-                               background-color: darken($shareWhatsAppBackground, 10%);
-                               color: rgba(255, 255, 255, 1);
-                       }
-               }
-
-               .jsShareLinkedIn {
-                       &:hover {
-                               background-color: darken($shareLinkedInBackground, 10%);
-                               color: rgba(255, 255, 255, 1);
-                       }
-               }
-
-               .jsSharePinterest {
-                       &:hover {
-                               background-color: darken($sharePinterestBackground, 10%);
-                               color: rgba(255, 255, 255, 1);
-                       }
-               }
-
-               .jsShareXing {
-                       &:hover {
-                               background-color: darken($shareXingBackground, 10%);
-                               color: rgba(255, 255, 255, 1);
-                       }
-               }
+       &[data-identifier="XING"]:hover {
+               background-color: darken($shareXingBackground, 10%);
+               color: rgba(255, 255, 255, 1);
        }
 }