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.
220 lines (170 loc) • 4.14 kB
JavaScript
import DataNode from './Node'
/**
Base node type for document nodes.
@example
The following example shows how a new node type is defined.
```js
class Todo extends TextBlock {}
Todo.schema = {
type: 'todo',
content: 'text',
done: { type: 'bool', default: false }
}
```
The following data types are supported:
- `string` bare metal string data type
- `text` a string that carries annotations
- `number` numeric values
- `bool` boolean values
- `id` a node id referencing another node in the document
*/
export default
class DocumentNode extends DataNode {
/**
@param {Document} doc A document instance
@param {object} node properties
*/
constructor(doc, props) {
super(doc, props)
}
_initialize(doc, props) {
this.document = doc
super._initialize(props)
}
/**
Get the Document instance.
@returns {Document}
*/
getDocument() {
return this.document
}
/**
Whether this node has a parent.
`parent` is a built-in property for implementing nested nodes.
@returns {Boolean}
*/
hasParent() {
return Boolean(this.parent)
}
/**
@returns {DocumentNode} the parent node
*/
getParent() {
return this.document.get(this.parent)
}
/**
Get the root node.
The root node is the last ancestor returned
by a sequence of `getParent()` calls.
@returns {DocumentNode}
*/
getRoot() {
let node = this
while(node.parent) {
node = node.parent
}
return node
}
getContainerRoot() {
let node = this
while(node.parent) {
// stop if node is immediate child of a container
if (node.parent.isContainer()) return node
// oherwise traverse up
node = node.parent
}
return node
}
/**
Checks whether this node has children.
@returns {Boolean} default: false
*/
hasChildren() {
return false
}
/**
Get the index of a given child.
@returns {Number} default: -1
*/
getChildIndex(child) { // eslint-disable-line
return -1
}
/**
Get a child node at a given position.
@returns {DocumentNode} default: null
*/
getChildAt(idx) { // eslint-disable-line
return null
}
/**
Get the number of children nodes.
@returns {Number} default: 0
*/
getChildCount() {
return 0
}
// Node categories
// --------------------
// TODO: we should use the same approach everywhere, either as prototype property or as class property
/**
@returns {Boolean} true if node is a block node (e.g. Paragraph, Figure, List, Table)
*/
isBlock() {
return Boolean(this.constructor.isBlock)
}
/**
@returns {Boolean} true if node is a text node (e.g. Paragraph, Codebock)
*/
isText() {
return Boolean(this.constructor.isText)
}
isList() {
return Boolean(this.constructor.isList)
}
isContainer() {
return Boolean(this._isContainer)
}
// annotation categories
isAnnotation() {
return Boolean(this._isAnnotation)
}
isPropertyAnnotation() {
return Boolean(this._isPropertyAnnotation)
}
isContainerAnnotation() {
return Boolean(this._isContainerAnnotation)
}
/**
@returns {Boolean} true if node is an inline node (e.g. Citation)
*/
isInline() {
return Boolean(this.constructor.isInline)
}
}
DocumentNode.prototype._isDocumentNode = true
/**
Declares a node to be treated as block-type node.
BlockNodes are considers the direct descendant of `Container` nodes.
@type {Boolean} default: false
*/
DocumentNode.isBlock = false
/**
Declares a node to be treated as text-ish node.
@type {Boolean} default: false
*/
DocumentNode.isText = false
/**
Declares a node to be treated as {@link model/PropertyAnnotation}.
@type {Boolean} default: false
*/
DocumentNode.isPropertyAnnotation = false
/**
Declares a node to be treated as {@link model/ContainerAnnotation}.
@type {Boolean} default: false
*/
DocumentNode.isContainerAnnotation = false
/**
Declares a node to be treated as {@link model/InlineNode}.
@type {Boolean} default: false
*/
DocumentNode.isInline = false