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.
114 lines (101 loc) • 3.14 kB
JavaScript
import { platform } from '../util'
class SurfaceManager {
constructor(editorSession) {
this.editorSession = editorSession
this.surfaces = {}
this._state = {
selection: null
}
editorSession.onUpdate('selection', this._onSelectionChanged, this)
editorSession.onPostRender(this._recoverDOMSelection, this)
}
dispose() {
this.editorSession.off(this)
}
/**
* Get Surface instance
*
* @param {String} name Name under which the surface is registered
* @return {ui/Surface} The surface instance
*/
getSurface(name) {
if (name) {
return this.surfaces[name]
}
}
/**
* Get the currently focused Surface.
*
* @return {ui/Surface} Surface instance
*/
getFocusedSurface() {
const sel = this._state.selection
if (sel && sel.surfaceId) {
return this.getSurface(sel.surfaceId)
}
}
getSurfaces() {
// HACK: not yet. we would need a polyfill
// return Object.values(this.surfaces)
return Object.keys(this.surfaces).map(key => this.surfaces[key])
}
/**
* Register a surface
*
* @param surface {ui/Surface} A new surface instance to register
*/
registerSurface(surface) {
const id = surface.getId()
if (this.surfaces[id]) {
console.error(`A surface with id ${id} has already been registered.`)
}
this.surfaces[id] = surface
}
/**
* Unregister a surface
*
* @param surface {ui/Surface} A surface instance to unregister
*/
unregisterSurface(surface) {
surface.off(this)
let surfaceId = surface.getId()
// TODO: this is not working, has side-effects
// with inline-nodes (see #985)
// if (surface === this.getFocusedSurface()) {
// this.editorSession.setSelection(null)
// }
let registeredSurface = this.surfaces[surfaceId]
if (registeredSurface === surface) {
delete this.surfaces[surfaceId]
}
}
_onSelectionChanged(selection) {
const state = this._state
state.selection = selection
// HACK: removing DOM selection *and* blurring when having a CustomSelection
// otherwise we will receive events on the wrong surface
// instead of bubbling up to GlobalEventManager
if (selection && selection.isCustomSelection() && platform.inBrowser) {
window.getSelection().removeAllRanges()
window.document.activeElement.blur()
}
}
/*
At the end of the update flow, make sure the surface is focused
and displays the right DOM selection
*/
_recoverDOMSelection() {
// do not rerender the selection if the editorSession has
// been blurred, e.g., while some component, such as Find-And-Replace
// dialog has the focus
if (this.editorSession._blurred) return
let focusedSurface = this.getFocusedSurface()
// console.log('focusedSurface', focusedSurface)
if (focusedSurface && !focusedSurface.isDisabled()) {
// console.log('Rendering selection on surface', focusedSurface.getId(), this.editorSession.getSelection().toString());
focusedSurface._focus()
focusedSurface.rerenderDOMSelection()
}
}
}
export default SurfaceManager