255 lines
8.3 KiB
JavaScript
Executable File
255 lines
8.3 KiB
JavaScript
Executable File
import { Node } from './jsmind.node.js'
|
|
import { logger, Direction } from './jsmind.common.js'
|
|
|
|
export class Mind {
|
|
constructor() {
|
|
this.name = null
|
|
this.author = null
|
|
this.version = null
|
|
this.root = null
|
|
this.selected = null
|
|
this.nodes = {}
|
|
}
|
|
get_node(node_id) {
|
|
if (node_id in this.nodes) {
|
|
return this.nodes[node_id]
|
|
} else {
|
|
logger.warn('the node[id=' + node_id + '] can not be found')
|
|
return null
|
|
}
|
|
}
|
|
set_root(node_id, topic, data) {
|
|
if (this.root == null) {
|
|
this.root = new Node(node_id, 0, topic, data, true)
|
|
this._put_node(this.root)
|
|
return this.root
|
|
} else {
|
|
logger.error('root node is already exist')
|
|
return null
|
|
}
|
|
}
|
|
add_node(parent_node, node_id, topic, data, direction, expanded, idx) {
|
|
if (!Node.is_node(parent_node)) {
|
|
logger.error('the parent_node ' + parent_node + ' is not a node.')
|
|
return null
|
|
}
|
|
var node_index = idx || -1
|
|
var node = new Node(
|
|
node_id,
|
|
node_index,
|
|
topic,
|
|
data,
|
|
false,
|
|
parent_node,
|
|
parent_node.direction,
|
|
expanded
|
|
)
|
|
if (parent_node.isroot) {
|
|
node.direction = direction || Direction.right
|
|
}
|
|
if (this._put_node(node)) {
|
|
parent_node.children.push(node)
|
|
this._update_index(parent_node)
|
|
} else {
|
|
logger.error("fail, the node id '" + node.id + "' has been already exist.")
|
|
node = null
|
|
}
|
|
return node
|
|
}
|
|
insert_node_before(node_before, node_id, topic, data, direction) {
|
|
if (!Node.is_node(node_before)) {
|
|
logger.error('the node_before ' + node_before + ' is not a node.')
|
|
return null
|
|
}
|
|
var node_index = node_before.index - 0.5
|
|
return this.add_node(node_before.parent, node_id, topic, data, direction, true, node_index)
|
|
}
|
|
get_node_before(node) {
|
|
if (!Node.is_node(node)) {
|
|
var the_node = this.get_node(node)
|
|
if (!the_node) {
|
|
logger.error('the node[id=' + node + '] can not be found.')
|
|
return null
|
|
} else {
|
|
return this.get_node_before(the_node)
|
|
}
|
|
}
|
|
if (node.isroot) {
|
|
return null
|
|
}
|
|
var idx = node.index - 2
|
|
if (idx >= 0) {
|
|
return node.parent.children[idx]
|
|
} else {
|
|
return null
|
|
}
|
|
}
|
|
insert_node_after(node_after, node_id, topic, data, direction) {
|
|
if (!Node.is_node(node_after)) {
|
|
logger.error('the node_after ' + node_after + ' is not a node.')
|
|
return null
|
|
}
|
|
var node_index = node_after.index + 0.5
|
|
return this.add_node(node_after.parent, node_id, topic, data, direction, true, node_index)
|
|
}
|
|
get_node_after(node) {
|
|
if (!Node.is_node(node)) {
|
|
var the_node = this.get_node(node)
|
|
if (!the_node) {
|
|
logger.error('the node[id=' + node + '] can not be found.')
|
|
return null
|
|
} else {
|
|
return this.get_node_after(the_node)
|
|
}
|
|
}
|
|
if (node.isroot) {
|
|
return null
|
|
}
|
|
var idx = node.index
|
|
var brothers = node.parent.children
|
|
if (brothers.length > idx) {
|
|
return node.parent.children[idx]
|
|
} else {
|
|
return null
|
|
}
|
|
}
|
|
move_node(node, before_id, parent_id, direction) {
|
|
if (!Node.is_node(node)) {
|
|
logger.error('the parameter node ' + node + ' is not a node.')
|
|
return null
|
|
}
|
|
if (!parent_id) {
|
|
parent_id = node.parent.id
|
|
}
|
|
return this._move_node(node, before_id, parent_id, direction)
|
|
}
|
|
_flow_node_direction(node, direction) {
|
|
if (typeof direction === 'undefined') {
|
|
direction = node.direction
|
|
} else {
|
|
node.direction = direction
|
|
}
|
|
var len = node.children.length
|
|
while (len--) {
|
|
this._flow_node_direction(node.children[len], direction)
|
|
}
|
|
}
|
|
_move_node_internal(node, before_id) {
|
|
if (!!node && !!before_id) {
|
|
if (before_id == '_last_') {
|
|
node.index = -1
|
|
this._update_index(node.parent)
|
|
} else if (before_id == '_first_') {
|
|
node.index = 0
|
|
this._update_index(node.parent)
|
|
} else {
|
|
var node_before = !!before_id ? this.get_node(before_id) : null
|
|
if (
|
|
node_before != null &&
|
|
node_before.parent != null &&
|
|
node_before.parent.id == node.parent.id
|
|
) {
|
|
node.index = node_before.index - 0.5
|
|
this._update_index(node.parent)
|
|
}
|
|
}
|
|
}
|
|
return node
|
|
}
|
|
_move_node(node, before_id, parent_id, direction) {
|
|
if (!!node && !!parent_id) {
|
|
var parent_node = this.get_node(parent_id)
|
|
if (Node.inherited(node, parent_node)) {
|
|
logger.error('can not move a node to its children')
|
|
return null
|
|
}
|
|
if (node.parent.id != parent_id) {
|
|
// remove from parent's children
|
|
var sibling = node.parent.children
|
|
var si = sibling.length
|
|
while (si--) {
|
|
if (sibling[si].id == node.id) {
|
|
sibling.splice(si, 1)
|
|
break
|
|
}
|
|
}
|
|
let origin_parent = node.parent
|
|
node.parent = parent_node
|
|
parent_node.children.push(node)
|
|
this._update_index(origin_parent)
|
|
}
|
|
|
|
if (node.parent.isroot) {
|
|
if (direction == Direction.left) {
|
|
node.direction = direction
|
|
} else {
|
|
node.direction = Direction.right
|
|
}
|
|
} else {
|
|
node.direction = node.parent.direction
|
|
}
|
|
this._move_node_internal(node, before_id)
|
|
this._flow_node_direction(node)
|
|
}
|
|
return node
|
|
}
|
|
remove_node(node) {
|
|
if (!Node.is_node(node)) {
|
|
logger.error('the parameter node ' + node + ' is not a node.')
|
|
return false
|
|
}
|
|
if (node.isroot) {
|
|
logger.error('fail, can not remove root node')
|
|
return false
|
|
}
|
|
if (this.selected != null && this.selected.id == node.id) {
|
|
this.selected = null
|
|
}
|
|
// clean all subordinate nodes
|
|
var children = node.children
|
|
var ci = children.length
|
|
while (ci--) {
|
|
this.remove_node(children[ci])
|
|
}
|
|
// clean all children
|
|
children.length = 0
|
|
var node_parent = node.parent
|
|
// remove from parent's children
|
|
var sibling = node_parent.children
|
|
var si = sibling.length
|
|
while (si--) {
|
|
if (sibling[si].id == node.id) {
|
|
sibling.splice(si, 1)
|
|
break
|
|
}
|
|
}
|
|
// remove from global nodes
|
|
delete this.nodes[node.id]
|
|
// clean all properties
|
|
for (var k in node) {
|
|
delete node[k]
|
|
}
|
|
// remove it's self
|
|
node = null
|
|
this._update_index(node_parent)
|
|
return true
|
|
}
|
|
_put_node(node) {
|
|
if (node.id in this.nodes) {
|
|
logger.warn("the node_id '" + node.id + "' has been already exist.")
|
|
return false
|
|
} else {
|
|
this.nodes[node.id] = node
|
|
return true
|
|
}
|
|
}
|
|
_update_index(node) {
|
|
if (node instanceof Node) {
|
|
node.children.sort(Node.compare)
|
|
for (var i = 0; i < node.children.length; i++) {
|
|
node.children[i].index = i + 1
|
|
}
|
|
}
|
|
}
|
|
}
|