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