Browse Source

Update RichTextEditor APIs

pull/415/head
Artur Arseniev 9 years ago
parent
commit
5d20e06300
  1. 110
      src/rich_text_editor/index.js
  2. 49
      src/rich_text_editor/model/RichTextEditor.js

110
src/rich_text_editor/index.js

@ -2,7 +2,6 @@
* * [add](#add) * * [add](#add)
* * [get](#get) * * [get](#get)
* * [getAll](#getall) * * [getAll](#getall)
* * [remove](#remove)
* * [getToolbarEl](#gettoolbarel) * * [getToolbarEl](#gettoolbarel)
* *
* This module allows to customize the toolbar of the Rich Text Editor and use commands from the HTML Editing APIs. * This module allows to customize the toolbar of the Rich Text Editor and use commands from the HTML Editing APIs.
@ -28,7 +27,7 @@ import {on, off} from 'utils/mixins'
module.exports = () => { module.exports = () => {
let config = {}; let config = {};
const defaults = require('./config/config'); const defaults = require('./config/config');
let toolbar, actions, lastEl; let toolbar, actions, lastEl, globalRte;
return { return {
@ -65,6 +64,7 @@ module.exports = () => {
actions = config.actions || []; actions = config.actions || [];
toolbar = document.createElement('div'); toolbar = document.createElement('div');
toolbar.className = `${ppfx}rte-toolbar`; toolbar.className = `${ppfx}rte-toolbar`;
globalRte = this.initRte(document.createElement('div'));
//Avoid closing on toolbar clicking //Avoid closing on toolbar clicking
on(toolbar, 'mousedown', e => e.stopPropagation()); on(toolbar, 'mousedown', e => e.stopPropagation());
@ -77,48 +77,89 @@ module.exports = () => {
canvas.getToolsEl().appendChild(toolbar); canvas.getToolsEl().appendChild(toolbar);
}, },
/** /**
* Add a new action to the RTE toolbar * Init the built-in RTE
* @param {HTMLElement} el
* @return {RichTextEditor}
* @private
*/
initRte(el) {
const pfx = this.pfx;
const actionbarContainer = toolbar;
const actionbar = this.actionbar;
const actions = this.actions || config.actions;
const classes = {
actionbar: `${pfx}actionbar`,
button: `${pfx}action`,
active: `${pfx}active`,
};
const rte = new RichTextEditor({
el,
classes,
actions,
actionbar,
actionbarContainer,
});
if (rte.actionbar) {
this.actionbar = rte.actionbar;
}
if (rte.actions) {
this.actions = rte.actions;
}
return rte;
},
/**
* Add a new action to the built-in RTE toolbar
* @param {string} name Action name * @param {string} name Action name
* @param {Object} opts Action options * @param {Object} action Action options
* @example * @example
* rte.add('bold', { * rte.add('bold', {
* icon: '<b>B</b>', * icon: '<b>B</b>',
* title: 'Bold', * attributes: {title: 'Bold',}
* result: rte => rte.exec('bold') * result: rte => rte.exec('bold')
* }); * });
* rte.add('link', { * rte.add('link', {
* icon: 'L', * icon: 'L',
* title: 'Link', * attributes: {title: 'Link',}
* result: rte => { * result: rte =>
* const url = window.prompt('Enter the link URL') * rte.insertHTML(`<a href="#">${rte.selection()}</a>`)
* if (url) rte.exec('createLink', url)
* }
* }); * });
*/ */
add(name, opts = {}) { add(name, action = {}) {
opts.name = name; action.name = name;
actions.push(opts); globalRte.getActions().push(action);
//gloabl.addAction(); globalRte.addAction(action, {sync: 1});
}, },
/** /**
* Get the command by its name * Get the action by its name
* @param {string} command Command name * @param {string} name Action name
* @return {Model} * @return {Object}
* @example * @example
* var cm = rte.get('fontSize'); * const action = rte.get('bold');
* // {name: 'bold', ...}
*/ */
get(command) { get(name) {
return commands.where({command})[0]; let result;
globalRte.getActions().forEach(action => {
if (action.name == name) {
result = action;
}
});
return result;
}, },
/** /**
* Returns the collection of commands * Get all actions
* @return {Collection} * @return {Array}
*/ */
getAll() { getAll() {
return commands; return globalRte.getActions();
}, },
/** /**
@ -153,24 +194,11 @@ module.exports = () => {
enable(view, rte) { enable(view, rte) {
lastEl = view.el; lastEl = view.el;
const em = config.em; const em = config.em;
const pfx = this.pfx;
const el = view.getChildrenContainer(); const el = view.getChildrenContainer();
const customRte = this.customRte; const customRte = this.customRte;
const actionbar = this.actionbar;
const actionbarContainer = toolbar;
const classes = {
actionbar: `${pfx}actionbar`,
button: `${pfx}action`,
active: `${pfx}active`,
};
toolbar.style.display = ''; toolbar.style.display = '';
rte = customRte ? customRte.enable(el, rte) : rte = customRte ? customRte.enable(el, rte) : this.initRte(el).enable();
new RichTextEditor({el, actionbarContainer, classes, actionbar}).enable();
if (rte.actionbar) {
this.actionbar = rte.actionbar;
}
if (em) { if (em) {
setTimeout(this.udpatePosition.bind(this), 0); setTimeout(this.udpatePosition.bind(this), 0);
@ -190,6 +218,7 @@ module.exports = () => {
* */ * */
disable(view, rte) { disable(view, rte) {
const customRte = this.customRte; const customRte = this.customRte;
const style = toolbar.style;
var el = view.getChildrenContainer(); var el = view.getChildrenContainer();
if (customRte) { if (customRte) {
@ -198,13 +227,14 @@ module.exports = () => {
rte.disable(); rte.disable();
} }
toolbar.style.display = 'none'; style.display = 'none';
style.top = 0;
style.left = 0;
}, },
/** /**
* Return the toolbar element * Get the toolbar element
* @return {HTMLElement} * @return {HTMLElement}
* @private
*/ */
getToolbarEl() { getToolbarEl() {
return toolbar; return toolbar;

49
src/rich_text_editor/model/RichTextEditor.js

@ -5,7 +5,7 @@ import {on, off} from 'utils/mixins'
const RTE_KEY = '_rte'; const RTE_KEY = '_rte';
const actions = { const defActions = {
bold: { bold: {
name: 'bold', name: 'bold',
icon: '<b>B</b>', icon: '<b>B</b>',
@ -38,6 +38,12 @@ const actions = {
}, },
result: (rte) => rte.insertHTML(`<a class="link" href="">${rte.selection()}</a>`) result: (rte) => rte.insertHTML(`<a class="link" href="">${rte.selection()}</a>`)
}, },
avoid: {
name: 'avoid',
icon: '<strike>avoid</strike>',
attributes: {title: 'avoid'},
result: (rte) => rte.insertHTML(`<b>Avoid</b>`)
},
} }
export default class RichTextEditor { export default class RichTextEditor {
@ -49,22 +55,25 @@ export default class RichTextEditor {
return el[RTE_KEY]; return el[RTE_KEY];
} }
//el.oninput = e => settings.onChange && settings.onChange(e.target.innerHTML);
//el.onkeydown = e => (e.which === 9 && e.preventDefault());
el[RTE_KEY] = this; el[RTE_KEY] = this;
this.el = el; this.el = el;
this.doc = el.ownerDocument; this.doc = el.ownerDocument;
//el.oninput = e => settings.onChange && settings.onChange(e.target.innerHTML);
//el.onkeydown = e => (e.which === 9 && e.preventDefault());
this.updateActiveActions = this.updateActiveActions.bind(this); this.updateActiveActions = this.updateActiveActions.bind(this);
settings.actions = settings.actions const settAct = settings.actions || [];
? settings.actions.map(action => { settAct.forEach((action, i) => {
if (typeof action === 'string') { if (typeof action === 'string') {
return actions[action]; action = defActions[action];
} else if (actions[action.name]) { } else if (defActions[action.name]) {
return {...actions[action.name], ...action}; action = {...defActions[action.name], ...action};
} }
return action; settAct[i] = action;
}) : Object.keys(actions).map(action => actions[action]) });
const actions = settAct.length ? settAct :
Object.keys(defActions).map(action => defActions[action])
settings.classes = { ...{ settings.classes = { ...{
actionbar: 'actionbar', actionbar: 'actionbar',
@ -77,6 +86,7 @@ export default class RichTextEditor {
this.actionbar = actionbar; this.actionbar = actionbar;
this.settings = settings; this.settings = settings;
this.classes = classes; this.classes = classes;
this.actions = actions;
if (!actionbar) { if (!actionbar) {
const actionbarCont = settings.actionbarContainer; const actionbarCont = settings.actionbarContainer;
@ -84,7 +94,7 @@ export default class RichTextEditor {
actionbar.className = classes.actionbar; actionbar.className = classes.actionbar;
actionbarCont.appendChild(actionbar); actionbarCont.appendChild(actionbar);
this.actionbar = actionbar; this.actionbar = actionbar;
settings.actions.forEach(action => this.addAction(action)) actions.forEach(action => this.addAction(action))
} }
settings.styleWithCSS && this.exec('styleWithCSS'); settings.styleWithCSS && this.exec('styleWithCSS');
@ -94,7 +104,7 @@ export default class RichTextEditor {
} }
updateActiveActions() { updateActiveActions() {
this.actions().forEach(action => { this.getActions().forEach(action => {
const btn = action.btn; const btn = action.btn;
const active = this.classes.active; const active = this.classes.active;
btn.className = btn.className.replace(active, '').trim(); btn.className = btn.className.replace(active, '').trim();
@ -110,6 +120,7 @@ export default class RichTextEditor {
this.el.contentEditable = true; this.el.contentEditable = true;
on(this.el, 'mouseup keyup', this.updateActiveActions) on(this.el, 'mouseup keyup', this.updateActiveActions)
this.syncActions(); this.syncActions();
this.updateActiveActions();
this.el.focus(); this.el.focus();
return this; return this;
} }
@ -125,7 +136,7 @@ export default class RichTextEditor {
* Sync actions with the current RTE * Sync actions with the current RTE
*/ */
syncActions() { syncActions() {
this.actions().forEach(action => { this.getActions().forEach(action => {
const event = action.event || 'click'; const event = action.event || 'click';
action.btn[`on${event}`] = e => { action.btn[`on${event}`] = e => {
action.result(this); action.result(this);
@ -137,8 +148,10 @@ export default class RichTextEditor {
/** /**
* Add new action to the actionbar * Add new action to the actionbar
* @param {Object} action * @param {Object} action
* @param {Object} [opts={}]
*/ */
addAction(action) { addAction(action, opts = {}) {
const sync = opts.sync;
const btn = document.createElement('span'); const btn = document.createElement('span');
const icon = action.icon; const icon = action.icon;
const attr = action.attributes || {}; const attr = action.attributes || {};
@ -156,14 +169,18 @@ export default class RichTextEditor {
} }
this.actionbarEl().appendChild(btn); this.actionbarEl().appendChild(btn);
if (sync) {
this.syncActions();
}
} }
/** /**
* Get the array of current actions * Get the array of current actions
* @return {Array} * @return {Array}
*/ */
actions() { getActions() {
return this.settings.actions; return this.actions;
} }
/** /**

Loading…
Cancel
Save