API for adding buttons to the new composer
This commit is contained in:
parent
290708ca53
commit
5cd6308850
|
@ -12,6 +12,96 @@ function getHead(head, prev) {
|
|||
}
|
||||
}
|
||||
|
||||
const _createCallbacks = [];
|
||||
|
||||
function Toolbar() {
|
||||
this.groups = [
|
||||
{group: 'fontStyles', buttons: []},
|
||||
{group: 'insertions', buttons: []},
|
||||
{group: 'extras', buttons: [], lastGroup: true}
|
||||
];
|
||||
|
||||
this.addButton({
|
||||
id: 'bold',
|
||||
group: 'fontStyles',
|
||||
perform: e => e.applySurround('**', '**', 'bold_text')
|
||||
});
|
||||
|
||||
this.addButton({
|
||||
id: 'italic',
|
||||
group: 'fontStyles',
|
||||
perform: e => e.applySurround('*', '*', 'italic_text')
|
||||
});
|
||||
|
||||
this.addButton({group: 'insertions', id: 'link', action: 'showLinkModal'});
|
||||
|
||||
this.addButton({
|
||||
id: 'quote',
|
||||
group: 'insertions',
|
||||
icon: 'quote-right',
|
||||
perform: e => e.applySurround('> ', '', 'code_text')
|
||||
});
|
||||
|
||||
this.addButton({
|
||||
id: 'code',
|
||||
group: 'insertions',
|
||||
perform(e) {
|
||||
if (e.selected.value.indexOf("\n") !== -1) {
|
||||
e.applySurround(' ', '', 'code_text');
|
||||
} else {
|
||||
e.applySurround('`', '`', 'code_text');
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
this.addButton({
|
||||
id: 'bullet',
|
||||
group: 'extras',
|
||||
icon: 'list-ul',
|
||||
perform: e => e.applyList('* ', 'list_item')
|
||||
});
|
||||
|
||||
this.addButton({
|
||||
id: 'list',
|
||||
group: 'extras',
|
||||
icon: 'list-ol',
|
||||
perform: e => e.applyList(i => !i ? "1. " : `${parseInt(i) + 1}. `, 'list_item')
|
||||
});
|
||||
|
||||
this.addButton({
|
||||
id: 'heading',
|
||||
group: 'extras',
|
||||
icon: 'font',
|
||||
perform: e => e.applyList('## ', 'heading_text')
|
||||
});
|
||||
|
||||
this.addButton({
|
||||
id: 'rule',
|
||||
group: 'extras',
|
||||
icon: 'minus',
|
||||
perform: e => e.addText("\n\n----------\n")
|
||||
});
|
||||
};
|
||||
|
||||
Toolbar.prototype.addButton = function(button) {
|
||||
const g = this.groups.findProperty('group', button.group);
|
||||
if (!g) {
|
||||
throw `Couldn't find toolbar group ${button.group}`;
|
||||
}
|
||||
|
||||
g.buttons.push({
|
||||
id: button.id,
|
||||
className: button.className || button.id,
|
||||
icon: button.icon || button.id,
|
||||
action: button.action || 'toolbarButton',
|
||||
perform: button.perform || Ember.k
|
||||
});
|
||||
};
|
||||
|
||||
export function onToolbarCreate(func) {
|
||||
_createCallbacks.push(func);
|
||||
};
|
||||
|
||||
export default Ember.Component.extend({
|
||||
classNames: ['d-editor'],
|
||||
ready: false,
|
||||
|
@ -25,6 +115,13 @@ export default Ember.Component.extend({
|
|||
loadScript('defer/html-sanitizer-bundle').then(() => this.set('ready', true));
|
||||
},
|
||||
|
||||
@property
|
||||
toolbar() {
|
||||
const toolbar = new Toolbar();
|
||||
_createCallbacks.forEach(cb => cb(toolbar));
|
||||
return toolbar;
|
||||
},
|
||||
|
||||
@property('ready', 'value')
|
||||
preview(ready, value) {
|
||||
if (!ready) { return; }
|
||||
|
@ -51,7 +148,7 @@ export default Ember.Component.extend({
|
|||
showSelector({
|
||||
appendTo: self.$(),
|
||||
container,
|
||||
onSelect: title => self._addText(`${title}:`)
|
||||
onSelect: title => self._addText(this._getSelected(), `${title}:`)
|
||||
});
|
||||
return "";
|
||||
}
|
||||
|
@ -112,8 +209,7 @@ export default Ember.Component.extend({
|
|||
});
|
||||
},
|
||||
|
||||
_applySurround(head, tail, exampleKey) {
|
||||
const sel = this._getSelected();
|
||||
_applySurround(sel, head, tail, exampleKey) {
|
||||
const pre = sel.pre;
|
||||
const post = sel.post;
|
||||
|
||||
|
@ -162,10 +258,9 @@ export default Ember.Component.extend({
|
|||
}
|
||||
},
|
||||
|
||||
_applyList(head, exampleKey) {
|
||||
const sel = this._getSelected();
|
||||
_applyList(sel, head, exampleKey) {
|
||||
if (sel.value.indexOf("\n") !== -1) {
|
||||
this._applySurround(head, '', exampleKey);
|
||||
this._applySurround(sel, head, '', exampleKey);
|
||||
} else {
|
||||
|
||||
const [hval, hlen] = getHead(head);
|
||||
|
@ -185,20 +280,22 @@ export default Ember.Component.extend({
|
|||
}
|
||||
},
|
||||
|
||||
_addText(text, sel) {
|
||||
sel = sel || this._getSelected();
|
||||
_addText(sel, text) {
|
||||
const insert = `${sel.pre}${text}`;
|
||||
this.set('value', `${insert}${sel.post}`);
|
||||
this._selectText(insert.length, 0);
|
||||
},
|
||||
|
||||
actions: {
|
||||
bold() {
|
||||
this._applySurround('**', '**', 'bold_text');
|
||||
},
|
||||
toolbarButton(button) {
|
||||
|
||||
italic() {
|
||||
this._applySurround('*', '*', 'italic_text');
|
||||
const selected = this._getSelected();
|
||||
button.perform({
|
||||
selected,
|
||||
applySurround: (head, tail, exampleKey) => this._applySurround(selected, head, tail, exampleKey),
|
||||
applyList: (head, exampleKey) => this._applyList(selected, head, exampleKey),
|
||||
addText: text => this._addText(selected, text)
|
||||
});
|
||||
},
|
||||
|
||||
showLinkModal() {
|
||||
|
@ -214,48 +311,19 @@ export default Ember.Component.extend({
|
|||
if (m && m.length === 2) {
|
||||
const description = m[1];
|
||||
const remaining = link.replace(m[0], '');
|
||||
this._addText(`[${description}](${remaining})`, this._lastSel);
|
||||
this._addText(this._lastSel, `[${description}](${remaining})`);
|
||||
} else {
|
||||
this._addText(`[${link}](${link})`, this._lastSel);
|
||||
this._addText(this._lastSel, `[${link}](${link})`);
|
||||
}
|
||||
|
||||
this.set('link', '');
|
||||
},
|
||||
|
||||
code() {
|
||||
const sel = this._getSelected();
|
||||
if (sel.value.indexOf("\n") !== -1) {
|
||||
this._applySurround(' ', '', 'code_text');
|
||||
} else {
|
||||
this._applySurround('`', '`', 'code_text');
|
||||
}
|
||||
},
|
||||
|
||||
quote() {
|
||||
this._applySurround('> ', "", 'code_text');
|
||||
},
|
||||
|
||||
bullet() {
|
||||
this._applyList('* ', 'list_item');
|
||||
},
|
||||
|
||||
list() {
|
||||
this._applyList(i => !i ? "1. " : `${parseInt(i) + 1}. `, 'list_item');
|
||||
},
|
||||
|
||||
heading() {
|
||||
this._applyList('## ', 'heading_text');
|
||||
},
|
||||
|
||||
rule() {
|
||||
this._addText("\n\n----------\n");
|
||||
},
|
||||
|
||||
emoji() {
|
||||
showSelector({
|
||||
appendTo: this.$(),
|
||||
container: this.container,
|
||||
onSelect: title => this._addText(`:${title}:`)
|
||||
onSelect: title => this._addText(this._getSelected(), `:${title}:`)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { showSelector } from "discourse/lib/emoji/emoji-toolbar";
|
||||
import { onToolbarCreate } from 'discourse/components/d-editor';
|
||||
|
||||
export default {
|
||||
name: 'enable-emoji',
|
||||
|
@ -6,6 +7,16 @@ export default {
|
|||
initialize(container) {
|
||||
const siteSettings = container.lookup('site-settings:main');
|
||||
if (siteSettings.enable_emoji) {
|
||||
|
||||
onToolbarCreate(toolbar => {
|
||||
toolbar.addButton({
|
||||
id: 'emoji',
|
||||
group: 'extras',
|
||||
icon: 'smile-o',
|
||||
action: 'emoji'
|
||||
});
|
||||
});
|
||||
|
||||
window.PagedownCustom.appendButtons.push({
|
||||
id: 'wmd-emoji-button',
|
||||
description: I18n.t("composer.emoji"),
|
||||
|
|
|
@ -8,20 +8,14 @@
|
|||
|
||||
<div class='d-editor-container'>
|
||||
<div class='d-editor-button-bar'>
|
||||
{{d-button action="bold" icon="bold" class="bold"}}
|
||||
{{d-button action="italic" icon="italic" class="italic"}}
|
||||
<div class='d-editor-spacer'></div>
|
||||
{{d-button action="showLinkModal" icon="link" class="link"}}
|
||||
{{d-button action="quote" icon="quote-right" class="quote"}}
|
||||
{{d-button action="code" icon="code" class="code"}}
|
||||
<div class='d-editor-spacer'></div>
|
||||
{{d-button action="bullet" icon="list-ul" class="bullet"}}
|
||||
{{d-button action="list" icon="list-ol" class="list"}}
|
||||
{{d-button action="heading" icon="font" class="heading"}}
|
||||
{{d-button action="rule" icon="minus" class="rule"}}
|
||||
{{#if siteSettings.enable_emoji}}
|
||||
{{d-button action="emoji" icon="smile-o" class="emoji"}}
|
||||
{{/if}}
|
||||
{{#each toolbar.groups as |group|}}
|
||||
{{#each group.buttons as |b|}}
|
||||
{{d-button action=b.action actionParam=b icon=b.icon class=b.className title=t.title}}
|
||||
{{/each}}
|
||||
{{#unless group.lastGroup}}
|
||||
<div class='d-editor-spacer'></div>
|
||||
{{/unless}}
|
||||
{{/each}}
|
||||
</div>
|
||||
|
||||
{{textarea value=value class="d-editor-input"}}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import componentTest from 'helpers/component-test';
|
||||
import { onToolbarCreate } from 'discourse/components/d-editor';
|
||||
|
||||
moduleForComponent('d-editor', {integration: true});
|
||||
|
||||
|
@ -441,21 +442,34 @@ testCase(`rule with a selection`, function(assert, textarea) {
|
|||
});
|
||||
});
|
||||
|
||||
testCase(`emoji`, function(assert) {
|
||||
assert.equal($('.emoji-modal').length, 0);
|
||||
componentTest('emoji', {
|
||||
template: '{{d-editor value=value}}',
|
||||
setup() {
|
||||
// Test adding a custom button
|
||||
onToolbarCreate(toolbar => {
|
||||
toolbar.addButton({
|
||||
id: 'emoji',
|
||||
group: 'extras',
|
||||
icon: 'smile-o',
|
||||
action: 'emoji'
|
||||
});
|
||||
});
|
||||
this.set('value', 'hello world.');
|
||||
},
|
||||
test(assert) {
|
||||
assert.equal($('.emoji-modal').length, 0);
|
||||
|
||||
click('button.emoji');
|
||||
andThen(() => {
|
||||
assert.equal($('.emoji-modal').length, 1);
|
||||
});
|
||||
click('button.emoji');
|
||||
andThen(() => {
|
||||
assert.equal($('.emoji-modal').length, 1);
|
||||
});
|
||||
|
||||
click('a[data-group-id=0]');
|
||||
click('a[title=grinning]');
|
||||
click('a[data-group-id=0]');
|
||||
click('a[title=grinning]');
|
||||
|
||||
andThen(() => {
|
||||
assert.ok($('.emoji-modal').length === 0);
|
||||
assert.equal(this.get('value'), 'hello world.:grinning:');
|
||||
});
|
||||
andThen(() => {
|
||||
assert.ok($('.emoji-modal').length === 0);
|
||||
assert.equal(this.get('value'), 'hello world.:grinning:');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue