Newer
Older
import { each, keys, includes } from 'lodash'
import {
ContainerEditor as SubstanceContainerEditor,
} from 'substance'
class ContainerEditor extends SubstanceContainerEditor {
constructor (...args) {
super(...args)
this.controlBackButton = this.controlBackButton.bind(this)
// TODO -- there is a hasNativeSpellcheck fn
const isSpellcheckNative = (this.props.spellcheck === 'native')
el.attr('spellcheck', isSpellcheckNative)
// 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
}
Alexandros Georgantas
committed
if (this.isEmpty() && !this.props.disabled) {
this.createText()
// TODO -- why this and not this.focus ?
this.el.focus()
}
Alexandros Georgantas
committed
// Check is this is working properly as the isReadOnlyMode is unstable
// TODO -- this.props.history is deprecated and gives a warning
if (this.props.history) {
this.props.history.listenBefore((location, callback) => {
if (this.props.containerId === 'body' && this.editorSession.hasUnsavedChanges()) {
const editor = this.getEditor()
editor.send('changesNotSaved')
editor.emit('send:route', {location: location.pathname, back: false})
return callback(false)
}
return callback()
})
}
// window.history.pushState(null, null, document.URL)
window.addEventListener('popstate', this.controlBackButton)
// TODO -- review // messes up browser history
controlBackButton () {
// TODO -- why are we pushing this url?
// it is not necessary that that's where the user wants to go
const url = '/books/' + this.props.book.id + '/book-builder'
window.removeEventListener('popstate', this.controlBackButton)
if (this.props.containerId === 'body' && this.editorSession.hasUnsavedChanges()) {
window.history.pushState(null, null, document.URL)
editor.emit('send:route', {
back: true,
location: url
})
onTextInput (event) {
if (!this.props.trackChanges) return super.onTextInput(event)
onTextInputShim (event) {
if (!this.props.trackChanges) return super.onTextInputShim(event)
this.handleTracking({
event: event,
status: 'add',
surfaceEvent: 'input',
keypress: true
})
}
if (!this.props.trackChanges) return super._handleDeleteKey(event)
this.handleTracking({
event: event,
status: 'delete',
surfaceEvent: 'delete'
})
}
_handleSpaceKey (event) {
if (!this.props.trackChanges) return super._handleSpaceKey(event)
this.handleTracking({
event: event,
status: 'add',
surfaceEvent: 'space'
})
}
shouldIgnoreKeypress (event) {
// see Surface's onTextInputShim for comments
if (
event.which === 0 ||
event.charCode === 0 ||
event.keyCode === keys.TAB ||
event.keyCode === keys.ESCAPE ||
Boolean(event.metaKey) ||
(Boolean(event.ctrlKey) ^ Boolean(event.altKey))
) {
return true
}
return false
}
getTextFromKeypress (event) {
let character = String.fromCharCode(event.which)
if (!event.shiftKey) character = character.toLowerCase()
if (character.length === 0) return null
return character
}
handleTracking (options) {
const trackChangesProvider = this.context.trackChangesProvider
const { event, keypress, surfaceEvent } = options
if (!keypress) {
event.preventDefault()
event.stopPropagation()
}
if (keypress) {
if (this.shouldIgnoreKeypress(event)) return
const text = this.getTextFromKeypress(event)
event.data = text
event.preventDefault()
event.stopPropagation()
}
if (!keypress && !event.data) return
if (surfaceEvent === 'delete') {
const direction = (event.keyCode === keyboardKeys.BACKSPACE) ? 'left' : 'right'
options.move = direction
options.key = (direction === 'left') ? 'BACKSPACE' : 'DELETE'
}
// create an empty paragraph with an empty node
// then select it for cursor focus
this.editorSession.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',
containerId: this.props.containerId,
surfaceId: this.props.containerId,
path: [ node.id, 'content' ],
startOffset: 0,
endOffset: 0
})
}.bind(this))
// only runs if editor is in read-only mode
// disables all tools, apart from comments
disableToolbar () {
const commandStates = this.getCommandStates()
const allowed = [
'comment',
'redo',
'save',
'track-change-enable',
'track-change-toggle-view',
'undo'
]
each(keys(commandStates), key => {
if (!includes(allowed, key)) commandStates[key].disabled = true
})
}
getCommandStates () {
const commandManager = this.context.commandManager
return commandManager.getCommandStates()
}
isReadOnlyMode () {
return !this.isEditable() && this.isSelectable()
}
const allLinks = this.el.findAll('a')
each(allLinks, link =>
link.attr('target', '_blank')
)
}
getEditor () {
return this.context.editor
}