import { each, keys, includes } from 'lodash' import { ContainerEditor as SubstanceContainerEditor, // deleteCharacter, // deleteSelection, Surface, uuid } from 'substance' class ContainerEditor extends SubstanceContainerEditor { render ($$) { // TODO -- better ways to write this in es6 var el = Surface.prototype.render.call(this, $$) var doc = this.getDocument() var containerId = this.getContainerId() var containerNode = doc.get(containerId) if (!containerNode) { console.warn('No container node found for ', containerId) } el.addClass('sc-container-editor container-node ' + containerId) .attr({ spellCheck: false, 'data-id': containerId }) // if it IS empty, handle in didMount if (!this.isEmpty()) { containerNode.getNodes().forEach(function (node) { el.append(this._renderNode($$, node).ref(node.id)) }.bind(this)) } // open for editing // TODO -- should maybe change to isEditable ? // or maybe delete it? we never pass a disabled prop explicitly if (!this.props.disabled) { el.addClass('sm-enabled') el.setAttribute('contenteditable', true) } return el } didMount () { // TODO -- replace with super.didMount() Surface.prototype.didMount.apply(this, arguments) this.container.on('nodes:changed', this.onContainerChange, this) // this.context.documentSession.on('didUpdate', (change, info) => { // // console.log(this.getSelection()) // // console.log(this.context.commandManager.getCommandStates().strong.mode) // // console.log(this.context.commandManager.getCommandStates()['track-change'].mode) // console.log('\n did update') // console.log(this.getCommandStates()) // console.log('change', change) // console.log('info', info) // // if (info.track) change.change.info.track = true // }, this) if (this.isEmpty()) this.createText() if (this.isReadOnlyMode()) { const documentSession = this.getDocumentSession() documentSession.on('didUpdate', this.disableToolbar, this) this.addTargetToLinks() } } onTextInput (event) { // console.log(this.context) event.preventDefault() event.stopPropagation() if (!event.data) return this._state.skipNextObservation = true if (!this.props.trackChanges) { this.transaction(function (tx, args) { if (this.domSelection) this.domSelection.clear() args.text = event.data return this.insertText(tx, args) }.bind(this), { action: 'type' }) return } const trackChangesProvider = this.context.trackChangesProvider const status = 'add' trackChangesProvider.handleTransaction(event, status) // const isSelCollapsed = this.getSelection().isCollapsed() // if (!isSelCollapsed) { // const trackChangesProvider = this.context.trackChangesProvider // const status = 'delete' // trackChangesProvider.handleTransaction(status) // } // // this.transaction(function (tx, args) { // if (this.domSelection) this.domSelection.clear() // args.text = event.data // return this.insertText(tx, args) // }.bind(this), { action: 'type' }) // // // don't rewrite the above, call it with super // if (this.props.trackChanges) { // const status = 'add' // trackChangesProvider.handleTransaction(status) // } } _handleDeleteKey (event) { event.preventDefault() event.stopPropagation() let direction = (event.keyCode === keys.BACKSPACE) ? 'left' : 'right' if (this.props.trackChanges) { const trackChangesProvider = this.context.trackChangesProvider const status = 'delete' trackChangesProvider.handleTransaction(event, status, direction) } else { this.transaction(function (tx, args) { args.direction = direction return this.delete(tx, args) }.bind(this), { action: 'delete' }) } } // delete (tx, args) { // let sel = args.selection // if (!sel.isCollapsed()) { // return deleteSelection(tx, args) // } else if (sel.isPropertySelection() || sel.isNodeSelection()) { // return deleteCharacter(tx, args) // } // } // create an empty paragraph with an empty node // then select it for cursor focus createText () { var newSel this.transaction(function (tx) { var container = tx.get(this.props.containerId) var textType = tx.getSchema().getDefaultTextType() var node = tx.create({ id: uuid(textType), type: textType, content: '' }) container.show(node.id) newSel = tx.createSelection({ type: 'property', path: [ node.id, 'content' ], startOffset: 0, endOffset: 0 }) }.bind(this)) this.rerender() this.setSelection(newSel) } // only runs if editor is in read-only mode // disables all tools, apart from comments disableToolbar () { const commandStates = this.getCommandStates() each(keys(commandStates), key => { const allowed = ['comment', 'note', 'save', 'undo', 'redo'] if (!includes(allowed, key)) commandStates[key].disabled = true }) } getCommandStates () { const commandManager = this.context.commandManager return commandManager.getCommandStates() } isReadOnlyMode () { return !this.isEditable() && this.isSelectable() } addTargetToLinks () { const allLinks = this.el.findAll('a') each(allLinks, link => link.attr('target', '_blank') ) } } export default ContainerEditor