2020-05-14 04:23:41 +08:00
|
|
|
import I18n from "I18n";
|
2018-11-27 05:49:57 +08:00
|
|
|
import attributeHook from "discourse-common/lib/attribute-hook";
|
2017-07-27 00:13:49 +08:00
|
|
|
import { h } from "virtual-dom";
|
2020-11-24 10:41:54 +08:00
|
|
|
import { isDevelopment } from "discourse-common/config/environment";
|
2021-03-17 21:11:40 +08:00
|
|
|
import escape from "discourse-common/lib/escape";
|
2018-11-27 05:49:57 +08:00
|
|
|
|
|
|
|
const SVG_NAMESPACE = "http://www.w3.org/2000/svg";
|
2017-07-27 00:13:49 +08:00
|
|
|
let _renderers = [];
|
|
|
|
|
2020-06-02 04:33:43 +08:00
|
|
|
let warnMissingIcons = true;
|
2020-08-18 04:33:57 +08:00
|
|
|
let _iconList;
|
2020-06-02 04:33:43 +08:00
|
|
|
|
2017-09-02 00:14:16 +08:00
|
|
|
const REPLACEMENTS = {
|
2019-12-20 03:39:29 +08:00
|
|
|
"d-tracking": "bell",
|
|
|
|
"d-muted": "discourse-bell-slash",
|
|
|
|
"d-regular": "far-bell",
|
|
|
|
"d-watching": "discourse-bell-exclamation",
|
|
|
|
"d-watching-first": "discourse-bell-one",
|
2017-09-07 23:18:59 +08:00
|
|
|
"d-drop-expanded": "caret-down",
|
|
|
|
"d-drop-collapsed": "caret-right",
|
2018-11-27 05:49:57 +08:00
|
|
|
"d-unliked": "far-heart",
|
2017-10-04 23:07:59 +08:00
|
|
|
"d-liked": "heart",
|
2017-09-14 23:14:43 +08:00
|
|
|
"notification.mentioned": "at",
|
2020-09-17 23:23:19 +08:00
|
|
|
"notification.group_mentioned": "users",
|
2017-09-14 23:14:43 +08:00
|
|
|
"notification.quoted": "quote-right",
|
|
|
|
"notification.replied": "reply",
|
|
|
|
"notification.posted": "reply",
|
2018-11-27 05:49:57 +08:00
|
|
|
"notification.edited": "pencil-alt",
|
2020-03-12 08:16:00 +08:00
|
|
|
"notification.bookmark_reminder": "discourse-bookmark-clock",
|
2017-09-14 23:14:43 +08:00
|
|
|
"notification.liked": "heart",
|
|
|
|
"notification.liked_2": "heart",
|
|
|
|
"notification.liked_many": "heart",
|
2019-01-16 10:40:16 +08:00
|
|
|
"notification.liked_consolidated": "heart",
|
2018-11-27 05:49:57 +08:00
|
|
|
"notification.private_message": "far-envelope",
|
|
|
|
"notification.invited_to_private_message": "far-envelope",
|
|
|
|
"notification.invited_to_topic": "hand-point-right",
|
2017-09-14 23:14:43 +08:00
|
|
|
"notification.invitee_accepted": "user",
|
2019-12-20 22:50:05 +08:00
|
|
|
"notification.moved_post": "sign-out-alt",
|
2017-09-14 23:14:43 +08:00
|
|
|
"notification.linked": "link",
|
|
|
|
"notification.granted_badge": "certificate",
|
2019-01-24 23:07:24 +08:00
|
|
|
"notification.topic_reminder": "far-clock",
|
2019-12-20 03:39:29 +08:00
|
|
|
"notification.watching_first_post": "discourse-bell-one",
|
2019-05-29 22:29:01 +08:00
|
|
|
"notification.group_message_summary": "users",
|
2019-08-06 18:29:46 +08:00
|
|
|
"notification.post_approved": "check",
|
2019-11-28 06:32:35 +08:00
|
|
|
"notification.membership_request_accepted": "user-plus",
|
2020-07-27 09:39:50 +08:00
|
|
|
"notification.membership_request_consolidated": "users",
|
2020-08-07 07:51:16 +08:00
|
|
|
"notification.reaction": "bell",
|
|
|
|
"notification.votes_released": "plus",
|
2017-09-02 00:14:16 +08:00
|
|
|
};
|
|
|
|
|
2017-09-16 01:54:47 +08:00
|
|
|
export function replaceIcon(source, destination) {
|
|
|
|
REPLACEMENTS[source] = destination;
|
|
|
|
}
|
2017-09-14 23:14:43 +08:00
|
|
|
|
2020-06-02 04:33:43 +08:00
|
|
|
export function disableMissingIconWarning() {
|
|
|
|
warnMissingIcons = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function enableMissingIconWarning() {
|
|
|
|
warnMissingIcons = false;
|
|
|
|
}
|
|
|
|
|
2017-07-27 00:13:49 +08:00
|
|
|
export function renderIcon(renderType, id, params) {
|
|
|
|
for (let i = 0; i < _renderers.length; i++) {
|
|
|
|
let renderer = _renderers[i];
|
|
|
|
let rendererForType = renderer[renderType];
|
|
|
|
|
|
|
|
if (rendererForType) {
|
2017-11-21 18:53:09 +08:00
|
|
|
const icon = { id, replacementId: REPLACEMENTS[id] };
|
|
|
|
let result = rendererForType(icon, params || {});
|
2017-07-27 00:13:49 +08:00
|
|
|
if (result) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function iconHTML(id, params) {
|
|
|
|
return renderIcon("string", id, params);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function iconNode(id, params) {
|
|
|
|
return renderIcon("node", id, params);
|
|
|
|
}
|
|
|
|
|
2018-11-27 05:49:57 +08:00
|
|
|
export function convertIconClass(icon) {
|
|
|
|
return icon
|
|
|
|
.replace("far fa-", "far-")
|
|
|
|
.replace("fab fa-", "fab-")
|
|
|
|
.replace("fas fa-", "")
|
|
|
|
.replace("fa-", "")
|
|
|
|
.trim();
|
|
|
|
}
|
|
|
|
|
2017-07-27 00:13:49 +08:00
|
|
|
export function registerIconRenderer(renderer) {
|
|
|
|
_renderers.unshift(renderer);
|
|
|
|
}
|
|
|
|
|
2018-11-27 05:49:57 +08:00
|
|
|
function iconClasses(icon, params) {
|
|
|
|
// "notification." is invalid syntax for classes, use replacement instead
|
|
|
|
const dClass =
|
|
|
|
icon.replacementId && icon.id.indexOf("notification.") > -1
|
|
|
|
? icon.replacementId
|
|
|
|
: icon.id;
|
2018-11-08 02:05:43 +08:00
|
|
|
|
2018-11-27 05:49:57 +08:00
|
|
|
let classNames = `fa d-icon d-icon-${dClass} svg-icon`;
|
|
|
|
|
|
|
|
if (params && params["class"]) {
|
|
|
|
classNames += " " + params["class"];
|
2017-07-27 00:13:49 +08:00
|
|
|
}
|
2018-11-27 05:49:57 +08:00
|
|
|
|
2017-07-27 00:13:49 +08:00
|
|
|
return classNames;
|
|
|
|
}
|
|
|
|
|
2020-08-18 04:33:57 +08:00
|
|
|
export function setIconList(iconList) {
|
|
|
|
_iconList = iconList;
|
|
|
|
}
|
|
|
|
|
2020-11-21 00:34:55 +08:00
|
|
|
export function isExistingIconId(id) {
|
2020-11-21 03:00:51 +08:00
|
|
|
return _iconList && _iconList.indexOf(id) >= 0;
|
2020-11-21 00:34:55 +08:00
|
|
|
}
|
|
|
|
|
2018-11-27 05:49:57 +08:00
|
|
|
function warnIfMissing(id) {
|
2020-11-24 10:41:54 +08:00
|
|
|
if (warnMissingIcons && isDevelopment() && !isExistingIconId(id)) {
|
2020-08-18 04:33:57 +08:00
|
|
|
console.warn(`The icon "${id}" is missing from the SVG subset.`); // eslint-disable-line no-console
|
2018-11-27 05:49:57 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function handleIconId(icon) {
|
|
|
|
let id = icon.replacementId || icon.id || "";
|
|
|
|
|
|
|
|
// TODO: clean up "thumbtack unpinned" at source instead of here
|
|
|
|
id = id.replace(" unpinned", "");
|
|
|
|
|
|
|
|
warnIfMissing(id);
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
2017-07-27 00:13:49 +08:00
|
|
|
// default resolver is font awesome
|
|
|
|
registerIconRenderer({
|
|
|
|
name: "font-awesome",
|
|
|
|
|
2017-11-21 18:53:09 +08:00
|
|
|
string(icon, params) {
|
2021-03-17 21:11:40 +08:00
|
|
|
const id = escape(handleIconId(icon));
|
|
|
|
let html = `<svg class='${escape(iconClasses(icon, params))} svg-string'`;
|
2018-11-27 05:49:57 +08:00
|
|
|
|
2017-07-27 00:13:49 +08:00
|
|
|
if (params.label) {
|
|
|
|
html += " aria-hidden='true'";
|
|
|
|
}
|
2018-11-27 05:49:57 +08:00
|
|
|
html += ` xmlns="${SVG_NAMESPACE}"><use xlink:href="#${id}" /></svg>`;
|
2017-07-27 00:13:49 +08:00
|
|
|
if (params.label) {
|
2021-03-17 21:11:40 +08:00
|
|
|
html += `<span class='sr-only'>${escape(params.label)}</span>`;
|
2017-07-27 00:13:49 +08:00
|
|
|
}
|
2018-11-27 05:49:57 +08:00
|
|
|
if (params.title) {
|
2021-03-17 21:11:40 +08:00
|
|
|
html = `<span class="svg-icon-title" title='${escape(
|
|
|
|
I18n.t(params.title)
|
|
|
|
)}'>${html}</span>`;
|
2018-11-27 05:49:57 +08:00
|
|
|
}
|
2020-02-03 21:22:14 +08:00
|
|
|
if (params.translatedtitle) {
|
2021-03-17 21:11:40 +08:00
|
|
|
html = `<span class="svg-icon-title" title='${escape(
|
|
|
|
params.translatedtitle
|
2020-02-03 21:22:14 +08:00
|
|
|
)}'>${html}</span>`;
|
|
|
|
}
|
2017-07-27 00:13:49 +08:00
|
|
|
return html;
|
|
|
|
},
|
|
|
|
|
2017-11-21 18:53:09 +08:00
|
|
|
node(icon, params) {
|
2018-11-27 05:49:57 +08:00
|
|
|
const id = handleIconId(icon);
|
|
|
|
const classes = iconClasses(icon, params) + " svg-node";
|
2017-07-28 07:22:19 +08:00
|
|
|
|
2018-11-27 05:49:57 +08:00
|
|
|
const svg = h(
|
|
|
|
"svg",
|
|
|
|
{
|
|
|
|
attributes: { class: classes, "aria-hidden": true },
|
|
|
|
namespace: SVG_NAMESPACE,
|
|
|
|
},
|
|
|
|
[
|
|
|
|
h("use", {
|
2021-03-17 21:11:40 +08:00
|
|
|
"xlink:href": attributeHook(
|
|
|
|
"http://www.w3.org/1999/xlink",
|
|
|
|
`#${escape(id)}`
|
|
|
|
),
|
2018-11-27 05:49:57 +08:00
|
|
|
namespace: SVG_NAMESPACE,
|
|
|
|
}),
|
|
|
|
]
|
|
|
|
);
|
2017-07-27 00:13:49 +08:00
|
|
|
|
|
|
|
if (params.title) {
|
2018-11-27 05:49:57 +08:00
|
|
|
return h(
|
|
|
|
"span",
|
|
|
|
{
|
|
|
|
title: params.title,
|
|
|
|
attributes: { class: "svg-icon-title" },
|
|
|
|
},
|
|
|
|
[svg]
|
|
|
|
);
|
2017-07-27 00:13:49 +08:00
|
|
|
} else {
|
2018-11-27 05:49:57 +08:00
|
|
|
return svg;
|
2017-07-27 00:13:49 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
});
|