UNPKG

substance

Version:

Substance is a JavaScript library for web-based content editing. It provides building blocks for realizing custom text editors and web-based publishing systems.

170 lines (146 loc) 3.87 kB
import { TextNode, Document, EditorSession, Configurator, AbstractEditor, TextPropertyEditor, BasePackage } from '../../index.es' const { UndoCommand, RedoCommand, SelectAllCommand } = BasePackage // TODO: maybe AbstractEditor is too heavy? // still we need to do almost the same, so that nothing // from the parent is leaking through to the children export default class TextInput extends AbstractEditor { constructor(parent, props = {}) { super(parent, _createEditorSession(props)) this.doc = this.editorSession.getDocument() } render($$) { let el = $$(this._getTagName()).addClass('sc-text-input') el.append( $$(TextInputEditor, { path: ['input', 'content'] }).ref('input') .on('enter', this._onEnter) .on('escape', this._onEscape) ) return el } didMount() { // set the cursor at the end of the content this.refs.input.selectLast() } dispose() { super.dispose() this.doc.dispose() this.editorSession.dispose() } // this component manages itself shouldRerender() { return false } getContent() { return this.getDocument().getContent() } _getDocument() { return this.context.editorSession.getDocument() } _getTagName() { return this.props.tagName || 'div' } _onEnter(event) { event.stopPropagation() this.el.emit('confirm') } _onEscape(event) { event.stopPropagation() this.el.emit('cancel') } } function _createEditorSession(props) { let config = new Configurator() config.addNode(TextNode) config.addCommand('undo', UndoCommand) config.addCommand('redo', RedoCommand) config.addCommand('select-all', SelectAllCommand) config.addKeyboardShortcut('CommandOrControl+z', { command: 'undo' }) config.addKeyboardShortcut('CommandOrControl+shift+z', { command: 'redo' }) config.addKeyboardShortcut('CommandOrControl+a', { command: 'select-all' }) config.defineSchema({ name: 'text-input', // FIXME: this does not make sense here // as we do not have a container model defaultTextType: 'text', // FIXME: the name 'ArticleClass' is not general enough // plus: the configurator does not fail when this is not specified ArticleClass: TextInputDocument, }) if (props.package) { config.import(props.package) } let doc = config.createArticle() if (props.content) { doc.set(['input', 'content'], props.content) } let editorSession = new EditorSession(doc, { configurator: config }) return { editorSession } } class TextInputDocument extends Document { constructor(...args) { super(...args) this.create({ type: 'text', id: 'input', content: '' }) } getContentNode() { return this.get('input') } getContent() { return this.getContentNode().getText() } } // TODO: would be good if there were some events triggered by // Surfaces class TextInputEditor extends TextPropertyEditor { onKeyDown(event) { let handled = false if (event.keyCode === 27) { handled = true this.el.emit('escape') } if (handled) { event.stopPropagation() event.preventDefault() } else { super.onKeyDown(event) } } selectLast() { const doc = this.getDocument() const input = doc.getContentNode() this.editorSession.setSelection({ type: 'property', path: input.getTextPath(), startOffset: input.getLength(), surfaceId: this.id }) } selectAll() { const doc = this.getDocument() const input = doc.getContentNode() this.editorSession.setSelection({ type: 'property', path: input.getTextPath(), startOffset: 0, endffset: input.getLength(), surfaceId: this.id }) } _handleEnterKey(...args) { super._handleEnterKey(...args) this.el.emit('enter') } }