Browse Source

Merge branch 'dev' of https://github.com/artf/grapesjs into dev

pull/2475/head
Artur Arseniev 7 years ago
parent
commit
84eecaedc5
  1. 30
      src/rich_text_editor/index.js
  2. 76
      src/rich_text_editor/model/RichTextEditor.js
  3. 9
      src/styles/scss/_gjs_rte.scss

30
src/rich_text_editor/index.js

@ -109,7 +109,9 @@ export default () => {
const classes = { const classes = {
actionbar: `${pfx}actionbar`, actionbar: `${pfx}actionbar`,
button: `${pfx}action`, button: `${pfx}action`,
active: `${pfx}active` active: `${pfx}active`,
inactive: `${pfx}inactive`,
disabled: `${pfx}disabled`
}; };
const rte = new RichTextEditor({ const rte = new RichTextEditor({
el, el,
@ -165,6 +167,32 @@ export default () => {
* } * }
* } * }
* }) * })
* // An example with state
* const isValidAnchor = (rte) => {
* // a utility function to help determine if the selected is a valid anchor node
* const anchor = rte.selection().anchorNode;
* const parentNode = anchor && anchor.parentNode;
* const nextSibling = anchor && anchor.nextSibling;
* return (parentNode && parentNode.nodeName == 'A') || (nextSibling && nextSibling.nodeName == 'A')
* }
* rte.add('toggleAnchor', {
* icon: `<span style="transform:rotate(45deg)">&supdsub;</span>`,
* state: (rte, doc) => {
* if (rte && rte.selection()) {
* // `btnState` is a integer, -1 for disabled, 0 for inactive, 1 for active
* return isValidAnchor(rte) ? btnState.ACTIVE : btnState.INACTIVE;
* } else {
* return btnState.INACTIVE;
* }
* },
* result: (rte, action) => {
* if (isValidAnchor(rte)) {
* rte.exec('unlink');
* } else {
* rte.insertHTML(`<a class="link" href="">${rte.selection()}</a>`);
* }
* }
* })
*/ */
add(name, action = {}) { add(name, action = {}) {
action.name = name; action.name = name;

76
src/rich_text_editor/model/RichTextEditor.js

@ -5,6 +5,20 @@ import { on, off } from 'utils/mixins';
const RTE_KEY = '_rte'; const RTE_KEY = '_rte';
const btnState = {
ACTIVE: 1,
INACTIVE: 0,
DISABLED: -1
};
const isValidAnchor = rte => {
const anchor = rte.selection().anchorNode;
const parentNode = anchor && anchor.parentNode;
const nextSibling = anchor && anchor.nextSibling;
return (
(parentNode && parentNode.nodeName == 'A') ||
(nextSibling && nextSibling.nodeName == 'A')
);
};
const defActions = { const defActions = {
bold: { bold: {
name: 'bold', name: 'bold',
@ -37,10 +51,15 @@ const defActions = {
style: 'font-size:1.4rem;padding:0 4px 2px;', style: 'font-size:1.4rem;padding:0 4px 2px;',
title: 'Link' title: 'Link'
}, },
state: (rte, doc) => {
if (rte && rte.selection()) {
return isValidAnchor(rte) ? btnState.ACTIVE : btnState.INACTIVE;
} else {
return btnState.INACTIVE;
}
},
result: rte => { result: rte => {
const anchor = rte.selection().anchorNode; if (isValidAnchor(rte)) {
const nextSibling = anchor && anchor.nextSibling;
if (nextSibling && nextSibling.nodeName == 'A') {
rte.exec('unlink'); rte.exec('unlink');
} else { } else {
rte.insertHTML(`<a class="link" href="">${rte.selection()}</a>`); rte.insertHTML(`<a class="link" href="">${rte.selection()}</a>`);
@ -78,7 +97,9 @@ export default class RichTextEditor {
...{ ...{
actionbar: 'actionbar', actionbar: 'actionbar',
button: 'action', button: 'action',
active: 'active' active: 'active',
disabled: 'disabled',
inactive: 'inactive'
}, },
...settings.classes ...settings.classes
}; };
@ -114,16 +135,34 @@ export default class RichTextEditor {
this.getActions().forEach(action => { this.getActions().forEach(action => {
const btn = action.btn; const btn = action.btn;
const update = action.update; const update = action.update;
const active = this.classes.active; const { active, inactive, disabled } = { ...this.classes };
const state = action.state;
const name = action.name; const name = action.name;
const doc = this.doc; const doc = this.doc;
btn.className = btn.className.replace(active, '').trim(); btn.className = btn.className.replace(active, '').trim();
btn.className = btn.className.replace(inactive, '').trim();
// doc.queryCommandValue(name) != 'false' btn.className = btn.className.replace(disabled, '').trim();
if (doc.queryCommandSupported(name) && doc.queryCommandState(name)) {
btn.className += ` ${active}`; // if there is a state function, which depicts the state,
// i.e. `active`, `disabled`, then call it
if (state) {
switch (state(this, doc)) {
case btnState.ACTIVE:
btn.className += ` ${active}`;
break;
case btnState.INACTIVE:
btn.className += ` ${inactive}`;
break;
case btnState.DISABLED:
btn.className += ` ${disabled}`;
break;
}
} else {
// otherwise default to checking if the name command is supported & enabled
if (doc.queryCommandSupported(name) && doc.queryCommandState(name)) {
btn.className += ` ${active}`;
}
} }
update && update(this, action); update && update(this, action);
}); });
} }
@ -156,11 +195,18 @@ export default class RichTextEditor {
*/ */
syncActions() { syncActions() {
this.getActions().forEach(action => { this.getActions().forEach(action => {
const event = action.event || 'click'; if (this.settings.actionbar) {
action.btn[`on${event}`] = e => { if (
action.result(this, action); !action.state ||
this.updateActiveActions(); (action.state && action.state(this, this.doc) >= 0)
}; ) {
const event = action.event || 'click';
action.btn[`on${event}`] = e => {
action.result(this, action);
this.updateActiveActions();
};
}
}
}); });
} }

9
src/styles/scss/_gjs_rte.scss

@ -33,6 +33,13 @@
} }
&active { &active {
background-color: $mainDkColor; background-color: $mainLhColor;
}
&disabled {
color: $mainLhColor;
cursor: not-allowed;
&:hover {
background-color: unset;
}
} }
} }

Loading…
Cancel
Save