FEATURE: Plugins can overwrite and add support for new icons

This commit is contained in:
Robin Ward 2017-07-26 12:13:49 -04:00
parent 2d41c5ed3c
commit e87125b63c
38 changed files with 136 additions and 71 deletions

View File

@ -1,4 +1,4 @@
import { iconHTML } from 'discourse-common/helpers/fa-icon'; import { iconHTML } from 'discourse-common/lib/icon-library';
import { bufferedRender } from 'discourse-common/lib/buffered-render'; import { bufferedRender } from 'discourse-common/lib/buffered-render';
export default Ember.Component.extend(bufferedRender({ export default Ember.Component.extend(bufferedRender({

View File

@ -1,5 +1,5 @@
import computed from 'ember-addons/ember-computed-decorators'; import computed from 'ember-addons/ember-computed-decorators';
import { iconHTML } from 'discourse-common/helpers/fa-icon'; import { iconHTML } from 'discourse-common/lib/icon-library';
import { bufferedRender } from 'discourse-common/lib/buffered-render'; import { bufferedRender } from 'discourse-common/lib/buffered-render';
export default Ember.Component.extend(bufferedRender({ export default Ember.Component.extend(bufferedRender({

View File

@ -1,23 +1,8 @@
import { registerUnbound } from 'discourse-common/lib/helpers'; import { registerUnbound } from 'discourse-common/lib/helpers';
import { renderIcon } from 'discourse-common/lib/icon-library';
export function iconClasses(icon, params) { export function iconHTML(id, params) {
let classes = "fa fa-" + icon; return renderIcon('string', id, params);
if (params.modifier) { classes += " fa-" + params.modifier; }
if (params['class']) { classes += ' ' + params['class']; }
return classes;
}
export function iconHTML(icon, params) {
params = params || {};
var html = "<i class='" + iconClasses(icon, params) + "'";
if (params.title) { html += ` title='${I18n.t(params.title)}'`; }
if (params.label) { html += " aria-hidden='true'"; }
html += "></i>";
if (params.label) {
html += "<span class='sr-only'>" + I18n.t(params.label) + "</span>";
}
return html;
} }
registerUnbound('fa-icon', function(icon, params) { registerUnbound('fa-icon', function(icon, params) {

View File

@ -0,0 +1,68 @@
import { h } from 'virtual-dom';
let _renderers = [];
export function renderIcon(renderType, id, params) {
for (let i=0; i<_renderers.length; i++) {
let renderer = _renderers[i];
let rendererForType = renderer[renderType];
if (rendererForType) {
let result = rendererForType(id, params || {});
if (result) {
return result;
}
}
}
}
export function iconHTML(id, params) {
return renderIcon('string', id, params);
}
export function iconNode(id, params) {
return renderIcon('node', id, params);
}
export function registerIconRenderer(renderer) {
_renderers.unshift(renderer);
}
// Support for font awesome icons
function faClasses(id, params) {
let classNames = `fa fa-${id}`;
if (params) {
if (params.modifier) { classNames += " fa-" + params.modifier; }
if (params['class']) { classNames += ' ' + params['class']; }
}
return classNames;
}
// default resolver is font awesome
registerIconRenderer({
name: 'font-awesome',
string(id, params) {
let html = `<i class='${faClasses(id, params)}'`;
if (params.title) { html += ` title='${I18n.t(params.title)}'`; }
if (params.label) { html += " aria-hidden='true'"; }
html += "></i>";
if (params.label) {
html += "<span class='sr-only'>" + I18n.t(params.label) + "</span>";
}
return html;
},
node(id, params) {
const properties = {
className: faClasses(id, params),
attributes: { "aria-hidden": true }
};
if (params.title) { properties.attributes.title = params.title; }
if (params.label) {
return h('i', properties, h('span.sr-only', I18n.t(params.label)));
} else {
return h('i', properties);
}
}
});

View File

@ -1,4 +1,4 @@
import { iconHTML } from 'discourse-common/helpers/fa-icon'; import { iconHTML } from 'discourse-common/lib/icon-library';
import DropdownButton from 'discourse/components/dropdown-button'; import DropdownButton from 'discourse/components/dropdown-button';
import computed from "ember-addons/ember-computed-decorators"; import computed from "ember-addons/ember-computed-decorators";

View File

@ -1,4 +1,4 @@
import { iconHTML } from 'discourse-common/helpers/fa-icon'; import { iconHTML } from 'discourse-common/lib/icon-library';
import { bufferedRender } from 'discourse-common/lib/buffered-render'; import { bufferedRender } from 'discourse-common/lib/buffered-render';
export default Ember.Component.extend(bufferedRender({ export default Ember.Component.extend(bufferedRender({

View File

@ -1,5 +1,5 @@
import { on } from 'ember-addons/ember-computed-decorators'; import { on } from 'ember-addons/ember-computed-decorators';
import { iconHTML } from 'discourse-common/helpers/fa-icon'; import { iconHTML } from 'discourse-common/lib/icon-library';
import LogsNotice from 'discourse/services/logs-notice'; import LogsNotice from 'discourse/services/logs-notice';
import { bufferedRender } from 'discourse-common/lib/buffered-render'; import { bufferedRender } from 'discourse-common/lib/buffered-render';

View File

@ -1,4 +1,4 @@
import { iconHTML } from 'discourse-common/helpers/fa-icon'; import { iconHTML } from 'discourse-common/lib/icon-library';
import { bufferedRender } from 'discourse-common/lib/buffered-render'; import { bufferedRender } from 'discourse-common/lib/buffered-render';
export default Ember.Component.extend(bufferedRender({ export default Ember.Component.extend(bufferedRender({

View File

@ -1,5 +1,5 @@
import { bufferedRender } from 'discourse-common/lib/buffered-render'; import { bufferedRender } from 'discourse-common/lib/buffered-render';
import { iconHTML } from 'discourse-common/helpers/fa-icon'; import { iconHTML } from 'discourse-common/lib/icon-library';
export default Ember.Component.extend(bufferedRender({ export default Ember.Component.extend(bufferedRender({
classNameBindings: [':tip', 'good', 'bad'], classNameBindings: [':tip', 'good', 'bad'],

View File

@ -1,6 +1,6 @@
import DropdownButton from 'discourse/components/dropdown-button'; import DropdownButton from 'discourse/components/dropdown-button';
import { allLevels, buttonDetails } from 'discourse/lib/notification-levels'; import { allLevels, buttonDetails } from 'discourse/lib/notification-levels';
import { iconHTML } from 'discourse-common/helpers/fa-icon'; import { iconHTML } from 'discourse-common/lib/icon-library';
import computed from 'ember-addons/ember-computed-decorators'; import computed from 'ember-addons/ember-computed-decorators';
export default DropdownButton.extend({ export default DropdownButton.extend({

View File

@ -1,4 +1,4 @@
import { iconHTML } from 'discourse-common/helpers/fa-icon'; import { iconHTML } from 'discourse-common/lib/icon-library';
import { default as computed, observes } from 'ember-addons/ember-computed-decorators'; import { default as computed, observes } from 'ember-addons/ember-computed-decorators';
import { bufferedRender } from 'discourse-common/lib/buffered-render'; import { bufferedRender } from 'discourse-common/lib/buffered-render';

View File

@ -1,4 +1,4 @@
import { iconHTML } from 'discourse-common/helpers/fa-icon'; import { iconHTML } from 'discourse-common/lib/icon-library';
import DropdownButton from 'discourse/components/dropdown-button'; import DropdownButton from 'discourse/components/dropdown-button';
import computed from "ember-addons/ember-computed-decorators"; import computed from "ember-addons/ember-computed-decorators";

View File

@ -1,4 +1,4 @@
import { iconHTML } from 'discourse-common/helpers/fa-icon'; import { iconHTML } from 'discourse-common/lib/icon-library';
import Combobox from 'discourse-common/components/combo-box'; import Combobox from 'discourse-common/components/combo-box';
import { observes } from 'ember-addons/ember-computed-decorators'; import { observes } from 'ember-addons/ember-computed-decorators';

View File

@ -1,4 +1,4 @@
import { iconHTML } from 'discourse-common/helpers/fa-icon'; import { iconHTML } from 'discourse-common/lib/icon-library';
import { bufferedRender } from 'discourse-common/lib/buffered-render'; import { bufferedRender } from 'discourse-common/lib/buffered-render';
import { escapeExpression } from 'discourse/lib/utilities'; import { escapeExpression } from 'discourse/lib/utilities';

View File

@ -4,7 +4,7 @@ import { default as computed, observes } from 'ember-addons/ember-computed-decor
import Category from 'discourse/models/category'; import Category from 'discourse/models/category';
import { escapeExpression } from 'discourse/lib/utilities'; import { escapeExpression } from 'discourse/lib/utilities';
import { setTransient } from 'discourse/lib/page-tracker'; import { setTransient } from 'discourse/lib/page-tracker';
import { iconHTML } from 'discourse-common/helpers/fa-icon'; import { iconHTML } from 'discourse-common/lib/icon-library';
const SortOrders = [ const SortOrders = [
{name: I18n.t('search.relevance'), id: 0}, {name: I18n.t('search.relevance'), id: 0},

View File

@ -1,5 +1,5 @@
import { registerUnbound } from 'discourse-common/lib/helpers'; import { registerUnbound } from 'discourse-common/lib/helpers';
import { iconHTML } from 'discourse-common/helpers/fa-icon'; import { iconHTML } from 'discourse-common/lib/icon-library';
var get = Em.get, var get = Em.get,
escapeExpression = Handlebars.Utils.escapeExpression; escapeExpression = Handlebars.Utils.escapeExpression;

View File

@ -1,20 +1,5 @@
import { h } from 'virtual-dom'; import { renderIcon } from 'discourse-common/lib/icon-library';
import { iconClasses } from 'discourse-common/helpers/fa-icon';
export function iconNode(icon, params) { export function iconNode(id, params) {
params = params || {}; return renderIcon('node', id, params);
const properties = {
className: iconClasses(icon, params),
attributes: { "aria-hidden": true }
};
if (params.title) { properties.attributes.title = params.title; }
if (params.label) {
return h('i', properties, h('span.sr-only', I18n.t(params.label)));
} else {
return h('i', properties);
}
} }

View File

@ -1,4 +1,4 @@
import { iconHTML } from 'discourse-common/helpers/fa-icon'; import { iconHTML } from 'discourse-common/lib/icon-library';
import { htmlHelper } from 'discourse-common/lib/helpers'; import { htmlHelper } from 'discourse-common/lib/helpers';
import { escapeExpression } from 'discourse/lib/utilities'; import { escapeExpression } from 'discourse/lib/utilities';

View File

@ -1,4 +1,4 @@
import { iconNode } from 'discourse/helpers/fa-icon-node'; import { iconNode } from 'discourse-common/lib/icon-library';
import { addDecorator } from 'discourse/widgets/post-cooked'; import { addDecorator } from 'discourse/widgets/post-cooked';
import ComposerEditor from 'discourse/components/composer-editor'; import ComposerEditor from 'discourse/components/composer-editor';
import { addButton } from 'discourse/widgets/post-menu'; import { addButton } from 'discourse/widgets/post-menu';
@ -19,6 +19,7 @@ import { addUserMenuGlyph } from 'discourse/widgets/user-menu';
import { addPostClassesCallback } from 'discourse/widgets/post'; import { addPostClassesCallback } from 'discourse/widgets/post';
import { addPostTransformCallback } from 'discourse/widgets/post-stream'; import { addPostTransformCallback } from 'discourse/widgets/post-stream';
import { attachAdditionalPanel } from 'discourse/widgets/header'; import { attachAdditionalPanel } from 'discourse/widgets/header';
import { registerIconRenderer } from 'discourse-common/lib/icon-library';
// If you add any methods to the API ensure you bump up this number // If you add any methods to the API ensure you bump up this number
@ -58,6 +59,32 @@ class PluginApi {
return klass; return klass;
} }
/**
* If you want to use custom icons in your discourse application,
* you can register a renderer that will return an icon in the
* format required.
*
* For example, the follwing resolver will render a smile in the place
* of every icon on Discourse.
*
* api.registerIconRenderer({
* name: 'smile-icons',
*
* // for the place in code that render a string
* string() {
* return "<i class='fa fa-smile-o'></i>";
* },
*
* // for the places in code that render virtual dom elements
* node() {
* return h('i', { className: 'fa fa-smile-o' });
* }
* });
**/
registerIconRenderer(fn) {
registerIconRenderer(fn);
}
/** /**
* Used for decorating the `cooked` content of a post after it is rendered using * Used for decorating the `cooked` content of a post after it is rendered using
* jQuery. * jQuery.

View File

@ -1,6 +1,6 @@
import { createWidget } from 'discourse/widgets/widget'; import { createWidget } from 'discourse/widgets/widget';
import { avatarFor } from 'discourse/widgets/post'; import { avatarFor } from 'discourse/widgets/post';
import { iconNode } from 'discourse/helpers/fa-icon-node'; import { iconNode } from 'discourse-common/lib/icon-library';
import { h } from 'virtual-dom'; import { h } from 'virtual-dom';
import { dateNode } from 'discourse/helpers/node'; import { dateNode } from 'discourse/helpers/node';
import { userPath } from 'discourse/lib/url'; import { userPath } from 'discourse/lib/url';

View File

@ -1,5 +1,5 @@
import { createWidget } from 'discourse/widgets/widget'; import { createWidget } from 'discourse/widgets/widget';
import { iconNode } from 'discourse/helpers/fa-icon-node'; import { iconNode } from 'discourse-common/lib/icon-library';
const ButtonClass = { const ButtonClass = {

View File

@ -2,7 +2,7 @@ import PostCooked from 'discourse/widgets/post-cooked';
import DecoratorHelper from 'discourse/widgets/decorator-helper'; import DecoratorHelper from 'discourse/widgets/decorator-helper';
import { createWidget } from 'discourse/widgets/widget'; import { createWidget } from 'discourse/widgets/widget';
import { h } from 'virtual-dom'; import { h } from 'virtual-dom';
import { iconNode } from 'discourse/helpers/fa-icon-node'; import { iconNode } from 'discourse-common/lib/icon-library';
import DiscourseURL from 'discourse/lib/url'; import DiscourseURL from 'discourse/lib/url';
createWidget('post-link-arrow', { createWidget('post-link-arrow', {

View File

@ -1,6 +1,6 @@
import { applyDecorators, createWidget } from 'discourse/widgets/widget'; import { applyDecorators, createWidget } from 'discourse/widgets/widget';
import { h } from 'virtual-dom'; import { h } from 'virtual-dom';
import { iconNode } from 'discourse/helpers/fa-icon-node'; import { iconNode } from 'discourse-common/lib/icon-library';
import DiscourseURL from 'discourse/lib/url'; import DiscourseURL from 'discourse/lib/url';
import RawHtml from 'discourse/widgets/raw-html'; import RawHtml from 'discourse/widgets/raw-html';
import renderTags from 'discourse/lib/render-tags'; import renderTags from 'discourse/lib/render-tags';

View File

@ -1,5 +1,5 @@
import { createWidget } from 'discourse/widgets/widget'; import { createWidget } from 'discourse/widgets/widget';
import { iconNode } from 'discourse/helpers/fa-icon-node'; import { iconNode } from 'discourse-common/lib/icon-library';
import { avatarImg } from 'discourse/widgets/post'; import { avatarImg } from 'discourse/widgets/post';
import DiscourseURL from 'discourse/lib/url'; import DiscourseURL from 'discourse/lib/url';
import { wantsNewWindow } from 'discourse/lib/intercept-click'; import { wantsNewWindow } from 'discourse/lib/intercept-click';

View File

@ -1,6 +1,6 @@
import { createWidget } from 'discourse/widgets/widget'; import { createWidget } from 'discourse/widgets/widget';
import { h } from 'virtual-dom'; import { h } from 'virtual-dom';
import { iconNode } from 'discourse/helpers/fa-icon-node'; import { iconNode } from 'discourse-common/lib/icon-library';
import { wantsNewWindow } from 'discourse/lib/intercept-click'; import { wantsNewWindow } from 'discourse/lib/intercept-click';
import DiscourseURL from 'discourse/lib/url'; import DiscourseURL from 'discourse/lib/url';

View File

@ -1,6 +1,6 @@
import { wantsNewWindow } from 'discourse/lib/intercept-click'; import { wantsNewWindow } from 'discourse/lib/intercept-click';
import { createWidget } from 'discourse/widgets/widget'; import { createWidget } from 'discourse/widgets/widget';
import { iconNode } from 'discourse/helpers/fa-icon-node'; import { iconNode } from 'discourse-common/lib/icon-library';
import { h } from 'virtual-dom'; import { h } from 'virtual-dom';
import DiscourseURL from 'discourse/lib/url'; import DiscourseURL from 'discourse/lib/url';

View File

@ -1,4 +1,4 @@
import { iconNode } from 'discourse/helpers/fa-icon-node'; import { iconNode } from 'discourse-common/lib/icon-library';
import { createWidget } from 'discourse/widgets/widget'; import { createWidget } from 'discourse/widgets/widget';
import { h } from 'virtual-dom'; import { h } from 'virtual-dom';

View File

@ -1,5 +1,5 @@
import { createWidget } from 'discourse/widgets/widget'; import { createWidget } from 'discourse/widgets/widget';
import { iconNode } from 'discourse/helpers/fa-icon-node'; import { iconNode } from 'discourse-common/lib/icon-library';
import { longDate } from 'discourse/lib/formatter'; import { longDate } from 'discourse/lib/formatter';
import { h } from 'virtual-dom'; import { h } from 'virtual-dom';

View File

@ -1,4 +1,4 @@
import { iconNode } from 'discourse/helpers/fa-icon-node'; import { iconNode } from 'discourse-common/lib/icon-library';
import { createWidget } from 'discourse/widgets/widget'; import { createWidget } from 'discourse/widgets/widget';
import { h } from 'virtual-dom'; import { h } from 'virtual-dom';
import { replaceEmoji } from 'discourse/widgets/emoji'; import { replaceEmoji } from 'discourse/widgets/emoji';

View File

@ -1,6 +1,6 @@
import { createWidget } from 'discourse/widgets/widget'; import { createWidget } from 'discourse/widgets/widget';
import RawHtml from 'discourse/widgets/raw-html'; import RawHtml from 'discourse/widgets/raw-html';
import { iconNode } from 'discourse/helpers/fa-icon-node'; import { iconNode } from 'discourse-common/lib/icon-library';
import { h } from 'virtual-dom'; import { h } from 'virtual-dom';
import { actionDescriptionHtml } from 'discourse/components/small-action'; import { actionDescriptionHtml } from 'discourse/components/small-action';
import { avatarFor } from 'discourse/widgets/post'; import { avatarFor } from 'discourse/widgets/post';

View File

@ -1,7 +1,7 @@
import PostCooked from 'discourse/widgets/post-cooked'; import PostCooked from 'discourse/widgets/post-cooked';
import DecoratorHelper from 'discourse/widgets/decorator-helper'; import DecoratorHelper from 'discourse/widgets/decorator-helper';
import { createWidget, applyDecorators } from 'discourse/widgets/widget'; import { createWidget, applyDecorators } from 'discourse/widgets/widget';
import { iconNode } from 'discourse/helpers/fa-icon-node'; import { iconNode } from 'discourse-common/lib/icon-library';
import { transformBasicPost } from 'discourse/lib/transform-post'; import { transformBasicPost } from 'discourse/lib/transform-post';
import { h } from 'virtual-dom'; import { h } from 'virtual-dom';
import DiscourseURL from 'discourse/lib/url'; import DiscourseURL from 'discourse/lib/url';

View File

@ -1,4 +1,4 @@
import { iconNode } from 'discourse/helpers/fa-icon-node'; import { iconNode } from 'discourse-common/lib/icon-library';
import { createWidget } from 'discourse/widgets/widget'; import { createWidget } from 'discourse/widgets/widget';
import { h } from 'virtual-dom'; import { h } from 'virtual-dom';

View File

@ -1,4 +1,4 @@
import { iconNode } from 'discourse/helpers/fa-icon-node'; import { iconNode } from 'discourse-common/lib/icon-library';
import { createWidget } from 'discourse/widgets/widget'; import { createWidget } from 'discourse/widgets/widget';
import { h } from 'virtual-dom'; import { h } from 'virtual-dom';
import { avatarFor } from 'discourse/widgets/post'; import { avatarFor } from 'discourse/widgets/post';

View File

@ -3,7 +3,7 @@ import { dateNode } from 'discourse/helpers/node';
import RawHtml from 'discourse/widgets/raw-html'; import RawHtml from 'discourse/widgets/raw-html';
import { createWidget } from 'discourse/widgets/widget'; import { createWidget } from 'discourse/widgets/widget';
import { h } from 'virtual-dom'; import { h } from 'virtual-dom';
import { iconNode } from 'discourse/helpers/fa-icon-node'; import { iconNode } from 'discourse-common/lib/icon-library';
import highlightText from 'discourse/lib/highlight-text'; import highlightText from 'discourse/lib/highlight-text';
class Highlighted extends RawHtml { class Highlighted extends RawHtml {

View File

@ -1,6 +1,6 @@
import { createWidget } from 'discourse/widgets/widget'; import { createWidget } from 'discourse/widgets/widget';
import { h } from 'virtual-dom'; import { h } from 'virtual-dom';
import { iconNode } from 'discourse/helpers/fa-icon-node'; import { iconNode } from 'discourse-common/lib/icon-library';
function description(attrs) { function description(attrs) {
const daysSince = attrs.daysSince; const daysSince = attrs.daysSince;

View File

@ -1,5 +1,5 @@
import { createWidget } from 'discourse/widgets/widget'; import { createWidget } from 'discourse/widgets/widget';
import { iconNode } from 'discourse/helpers/fa-icon-node'; import { iconNode } from 'discourse-common/lib/icon-library';
import { h } from 'virtual-dom'; import { h } from 'virtual-dom';
import { escapeExpression } from 'discourse/lib/utilities'; import { escapeExpression } from 'discourse/lib/utilities';

View File

@ -1,7 +1,7 @@
import { createWidget } from 'discourse/widgets/widget'; import { createWidget } from 'discourse/widgets/widget';
import { h } from 'virtual-dom'; import { h } from 'virtual-dom';
import { relativeAge } from 'discourse/lib/formatter'; import { relativeAge } from 'discourse/lib/formatter';
import { iconNode } from 'discourse/helpers/fa-icon-node'; import { iconNode } from 'discourse-common/lib/icon-library';
import RawHtml from 'discourse/widgets/raw-html'; import RawHtml from 'discourse/widgets/raw-html';
const SCROLLAREA_HEIGHT = 300; const SCROLLAREA_HEIGHT = 300;

View File

@ -1,6 +1,6 @@
import { createWidget } from 'discourse/widgets/widget'; import { createWidget } from 'discourse/widgets/widget';
import { h } from 'virtual-dom'; import { h } from 'virtual-dom';
import { iconNode } from 'discourse/helpers/fa-icon-node'; import { iconNode } from 'discourse-common/lib/icon-library';
import RawHtml from 'discourse/widgets/raw-html'; import RawHtml from 'discourse/widgets/raw-html';
import { ajax } from 'discourse/lib/ajax'; import { ajax } from 'discourse/lib/ajax';
import evenRound from "discourse/plugins/poll/lib/even-round"; import evenRound from "discourse/plugins/poll/lib/even-round";