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 system. It is developed to power our online editing platform [Substance](http://substance.io).
178 lines (153 loc) • 5.57 kB
JavaScript
// import { getKeyForPath } from '../util'
import { copySelection } from '../model'
import SurfaceManager from './SurfaceManager'
import MarkersManager from './MarkersManager'
import KeyboardManager from './KeyboardManager'
import CommandManager from './CommandManager'
import FindAndReplaceManager from './FindAndReplaceManager'
export default function EditorSessionMixin (AbstractEditorSession) {
class BaseEditorSession extends AbstractEditorSession {
/**
* @param {Configurator} config
* @param {object} options
* @param {boolean} options.inherit true if commands and keyboard shortcuts should be inherited from parent configurations.
*/
_setup (config, options = {}) {
this.config = config
const editorState = this.editorState
const surfaceManager = new SurfaceManager(editorState)
const markersManager = new MarkersManager(editorState)
const keyboardManager = new KeyboardManager(config.getKeyboardShortcuts(options), (commandName, params) => {
return this.executeCommand(commandName, params)
}, this)
const commandManager = new CommandManager(this,
// update commands when document or selection have changed
// TODO: is this really sufficient?
['document', 'selection'],
config.getCommands(options)
)
const findAndReplaceManager = new FindAndReplaceManager(this)
this.surfaceManager = surfaceManager
this.markersManager = markersManager
this.keyboardManager = keyboardManager
this.commandManager = commandManager
this.findAndReplaceManager = findAndReplaceManager
// has to be set before initialisation
this.context = null
// ATTENTION: we need a root DOM element e.g. for finding surfaces
// An editor component should call something like
// ```
// editorSession.setRootComponent(editor.getContent())
// ```
// during didMount()
this._rootComponent = null
}
initialize () {
super.initialize()
// NOTE: in newer implementation, overlayId has been replaced by OverlayCanvas, which is implemented without appState.overlayId
// EXPERIMENTAL: registering a 'reducer' that resets overlayId whenever the selection changes
// this.editorState.addObserver(['selection'], this._resetOverlayId, this, { stage: 'update' })
this.commandManager.initialize()
}
dispose () {
super.dispose()
this.editorState.removeObserver(this)
this.surfaceManager.dispose()
this.markersManager.dispose()
this.commandManager.dispose()
this.findAndReplaceManager.dispose()
}
_createEditorState (document, initialState = {}) {
return Object.assign(super._createEditorState(document, initialState), {
focusedSurface: null,
commandStates: {},
overlayId: null,
findAndReplace: FindAndReplaceManager.defaultState()
})
}
copy () {
const sel = this.getSelection()
const doc = this.getDocument()
if (sel && !sel.isNull() && !sel.isCollapsed()) {
return copySelection(doc, sel)
}
}
cut () {
const sel = this.getSelection()
if (sel && !sel.isNull() && !sel.isCollapsed()) {
const snippet = this.copy()
this.deleteSelection()
return snippet
}
}
deleteSelection (options) {
const sel = this.getSelection()
if (sel && !sel.isNull() && !sel.isCollapsed()) {
this.transaction(tx => {
tx.deleteSelection(options)
}, { action: 'deleteSelection' })
}
}
paste (content, options) {
this.transaction(tx => {
tx.paste(content, options)
}, { action: 'paste' })
return true
}
insertText (text) {
const sel = this.getSelection()
if (sel && !sel.isNull()) {
this.transaction(tx => {
tx.insertText(text)
}, { action: 'insertText' })
}
}
executeCommand (commandName, params) {
return this.commandManager.executeCommand(commandName, params)
}
getCommandStates () {
return this.editorState.commandStates
}
getConfig () {
return this.config
}
getContext () {
return this.context
}
setContext (context) {
this.context = context
}
getFocusedSurface () {
return this.editorState.focusedSurface
}
getSurface (surfaceId) {
return this.surfaceManager.getSurface(surfaceId)
}
getSurfaceForProperty (path) {
return this.surfaceManager._getSurfaceForProperty(path)
}
setRootComponent (rootComponent) {
this._rootComponent = rootComponent
}
getRootComponent () {
return this._rootComponent
}
_resetOverlayId () {
// TODO: in newer implementation, overlayId has been replaced by OverlayCanvas, which is implemented without appState.overlayId
// const overlayId = this.editorState.overlayId
// // overlayId === getKeyForPath(path) => if selection is value &&
// // Overlays of value components (ManyRelationshipComponent, SingleRelationship)
// // need to remain open if the selection is a value selection
// const sel = this.getSelection()
// if (sel && sel.customType === 'value') {
// const valueId = getKeyForPath(sel.data.path)
// if (overlayId !== valueId) {
// this.editorState.overlayId = valueId
// }
// } else {
// this.editorState.overlayId = null
// }
}
}
return BaseEditorSession
}