mirror of
https://github.com/discourse/discourse.git
synced 2025-03-09 14:34:35 +00:00
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({
|
export default Ember.Component.extend({
|
||||||
classNames: ['d-editor'],
|
classNames: ['d-editor'],
|
||||||
ready: false,
|
ready: false,
|
||||||
@ -25,6 +115,13 @@ export default Ember.Component.extend({
|
|||||||
loadScript('defer/html-sanitizer-bundle').then(() => this.set('ready', true));
|
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')
|
@property('ready', 'value')
|
||||||
preview(ready, value) {
|
preview(ready, value) {
|
||||||
if (!ready) { return; }
|
if (!ready) { return; }
|
||||||
@ -51,7 +148,7 @@ export default Ember.Component.extend({
|
|||||||
showSelector({
|
showSelector({
|
||||||
appendTo: self.$(),
|
appendTo: self.$(),
|
||||||
container,
|
container,
|
||||||
onSelect: title => self._addText(`${title}:`)
|
onSelect: title => self._addText(this._getSelected(), `${title}:`)
|
||||||
});
|
});
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@ -112,8 +209,7 @@ export default Ember.Component.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_applySurround(head, tail, exampleKey) {
|
_applySurround(sel, head, tail, exampleKey) {
|
||||||
const sel = this._getSelected();
|
|
||||||
const pre = sel.pre;
|
const pre = sel.pre;
|
||||||
const post = sel.post;
|
const post = sel.post;
|
||||||
|
|
||||||
@ -162,10 +258,9 @@ export default Ember.Component.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_applyList(head, exampleKey) {
|
_applyList(sel, head, exampleKey) {
|
||||||
const sel = this._getSelected();
|
|
||||||
if (sel.value.indexOf("\n") !== -1) {
|
if (sel.value.indexOf("\n") !== -1) {
|
||||||
this._applySurround(head, '', exampleKey);
|
this._applySurround(sel, head, '', exampleKey);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
const [hval, hlen] = getHead(head);
|
const [hval, hlen] = getHead(head);
|
||||||
@ -185,20 +280,22 @@ export default Ember.Component.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_addText(text, sel) {
|
_addText(sel, text) {
|
||||||
sel = sel || this._getSelected();
|
|
||||||
const insert = `${sel.pre}${text}`;
|
const insert = `${sel.pre}${text}`;
|
||||||
this.set('value', `${insert}${sel.post}`);
|
this.set('value', `${insert}${sel.post}`);
|
||||||
this._selectText(insert.length, 0);
|
this._selectText(insert.length, 0);
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
bold() {
|
toolbarButton(button) {
|
||||||
this._applySurround('**', '**', 'bold_text');
|
|
||||||
},
|
|
||||||
|
|
||||||
italic() {
|
const selected = this._getSelected();
|
||||||
this._applySurround('*', '*', 'italic_text');
|
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() {
|
showLinkModal() {
|
||||||
@ -214,48 +311,19 @@ export default Ember.Component.extend({
|
|||||||
if (m && m.length === 2) {
|
if (m && m.length === 2) {
|
||||||
const description = m[1];
|
const description = m[1];
|
||||||
const remaining = link.replace(m[0], '');
|
const remaining = link.replace(m[0], '');
|
||||||
this._addText(`[${description}](${remaining})`, this._lastSel);
|
this._addText(this._lastSel, `[${description}](${remaining})`);
|
||||||
} else {
|
} else {
|
||||||
this._addText(`[${link}](${link})`, this._lastSel);
|
this._addText(this._lastSel, `[${link}](${link})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.set('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() {
|
emoji() {
|
||||||
showSelector({
|
showSelector({
|
||||||
appendTo: this.$(),
|
appendTo: this.$(),
|
||||||
container: this.container,
|
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 { showSelector } from "discourse/lib/emoji/emoji-toolbar";
|
||||||
|
import { onToolbarCreate } from 'discourse/components/d-editor';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'enable-emoji',
|
name: 'enable-emoji',
|
||||||
@ -6,6 +7,16 @@ export default {
|
|||||||
initialize(container) {
|
initialize(container) {
|
||||||
const siteSettings = container.lookup('site-settings:main');
|
const siteSettings = container.lookup('site-settings:main');
|
||||||
if (siteSettings.enable_emoji) {
|
if (siteSettings.enable_emoji) {
|
||||||
|
|
||||||
|
onToolbarCreate(toolbar => {
|
||||||
|
toolbar.addButton({
|
||||||
|
id: 'emoji',
|
||||||
|
group: 'extras',
|
||||||
|
icon: 'smile-o',
|
||||||
|
action: 'emoji'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
window.PagedownCustom.appendButtons.push({
|
window.PagedownCustom.appendButtons.push({
|
||||||
id: 'wmd-emoji-button',
|
id: 'wmd-emoji-button',
|
||||||
description: I18n.t("composer.emoji"),
|
description: I18n.t("composer.emoji"),
|
||||||
|
@ -8,20 +8,14 @@
|
|||||||
|
|
||||||
<div class='d-editor-container'>
|
<div class='d-editor-container'>
|
||||||
<div class='d-editor-button-bar'>
|
<div class='d-editor-button-bar'>
|
||||||
{{d-button action="bold" icon="bold" class="bold"}}
|
{{#each toolbar.groups as |group|}}
|
||||||
{{d-button action="italic" icon="italic" class="italic"}}
|
{{#each group.buttons as |b|}}
|
||||||
<div class='d-editor-spacer'></div>
|
{{d-button action=b.action actionParam=b icon=b.icon class=b.className title=t.title}}
|
||||||
{{d-button action="showLinkModal" icon="link" class="link"}}
|
{{/each}}
|
||||||
{{d-button action="quote" icon="quote-right" class="quote"}}
|
{{#unless group.lastGroup}}
|
||||||
{{d-button action="code" icon="code" class="code"}}
|
<div class='d-editor-spacer'></div>
|
||||||
<div class='d-editor-spacer'></div>
|
{{/unless}}
|
||||||
{{d-button action="bullet" icon="list-ul" class="bullet"}}
|
{{/each}}
|
||||||
{{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}}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{textarea value=value class="d-editor-input"}}
|
{{textarea value=value class="d-editor-input"}}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import componentTest from 'helpers/component-test';
|
import componentTest from 'helpers/component-test';
|
||||||
|
import { onToolbarCreate } from 'discourse/components/d-editor';
|
||||||
|
|
||||||
moduleForComponent('d-editor', {integration: true});
|
moduleForComponent('d-editor', {integration: true});
|
||||||
|
|
||||||
@ -441,21 +442,34 @@ testCase(`rule with a selection`, function(assert, textarea) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testCase(`emoji`, function(assert) {
|
componentTest('emoji', {
|
||||||
assert.equal($('.emoji-modal').length, 0);
|
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');
|
click('button.emoji');
|
||||||
andThen(() => {
|
andThen(() => {
|
||||||
assert.equal($('.emoji-modal').length, 1);
|
assert.equal($('.emoji-modal').length, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
click('a[data-group-id=0]');
|
click('a[data-group-id=0]');
|
||||||
click('a[title=grinning]');
|
click('a[title=grinning]');
|
||||||
|
|
||||||
andThen(() => {
|
andThen(() => {
|
||||||
assert.ok($('.emoji-modal').length === 0);
|
assert.ok($('.emoji-modal').length === 0);
|
||||||
assert.equal(this.get('value'), 'hello world.:grinning:');
|
assert.equal(this.get('value'), 'hello world.:grinning:');
|
||||||
});
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user