blob: 69a64e18de71816d276592312be4aa304dd36b99 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
const docMap = {}
/**
* Add a document object into docMap.
* @param {string} id
* @param {object} document
*/
export function addDoc (id, doc) {
if (id) {
docMap[id] = doc
}
}
/**
* Get the document object by id.
* @param {string} id
*/
export function getDoc (id) {
return docMap[id]
}
/**
* Remove the document from docMap by id.
* @param {string} id
*/
export function removeDoc (id) {
delete docMap[id]
}
/**
* @deprecated
* Get listener by document id.
* @param {string} id
* @return {object} listener
*/
export function getListener (id) {
const doc = docMap[id]
if (doc && doc.listener) {
return doc.listener
}
return null
}
/**
* Get TaskCenter instance by id.
* @param {string} id
* @return {object} TaskCenter
*/
export function getTaskCenter (id) {
const doc = docMap[id]
if (doc && doc.taskCenter) {
return doc.taskCenter
}
return null
}
/**
* Append body node to documentElement.
* @param {object} document
* @param {object} node
* @param {object} before
*/
export function appendBody (doc, node, before) {
const { documentElement } = doc
if (documentElement.pureChildren.length > 0 || node.parentNode) {
return
}
const children = documentElement.children
const beforeIndex = children.indexOf(before)
if (beforeIndex < 0) {
children.push(node)
}
else {
children.splice(beforeIndex, 0, node)
}
if (node.nodeType === 1) {
if (node.role === 'body') {
node.docId = doc.id
node.ownerDocument = doc
node.parentNode = documentElement
linkParent(node, documentElement)
}
else {
node.children.forEach(child => {
child.parentNode = node
})
setBody(doc, node)
node.docId = doc.id
node.ownerDocument = doc
linkParent(node, documentElement)
delete doc.nodeMap[node.nodeId]
}
documentElement.pureChildren.push(node)
sendBody(doc, node)
}
else {
node.parentNode = documentElement
doc.nodeMap[node.ref] = node
}
}
function sendBody (doc, node) {
const body = node.toJSON()
if (doc && doc.taskCenter && typeof doc.taskCenter.send === 'function') {
doc.taskCenter.send('dom', { action: 'createBody' }, [body])
}
}
/**
* Set up body node.
* @param {object} document
* @param {object} element
*/
export function setBody (doc, el) {
el.role = 'body'
el.depth = 1
delete doc.nodeMap[el.nodeId]
el.ref = '_root'
doc.nodeMap._root = el
doc.body = el
}
/**
* Establish the connection between parent and child node.
* @param {object} child node
* @param {object} parent node
*/
export function linkParent (node, parent) {
node.parentNode = parent
if (parent.docId) {
node.docId = parent.docId
node.ownerDocument = parent.ownerDocument
node.ownerDocument.nodeMap[node.nodeId] = node
node.depth = parent.depth + 1
}
node.children.forEach(child => {
linkParent(child, node)
})
}
/**
* Get the next sibling element.
* @param {object} node
*/
export function nextElement (node) {
while (node) {
if (node.nodeType === 1) {
return node
}
node = node.nextSibling
}
}
/**
* Get the previous sibling element.
* @param {object} node
*/
export function previousElement (node) {
while (node) {
if (node.nodeType === 1) {
return node
}
node = node.previousSibling
}
}
/**
* Insert a node into list at the specified index.
* @param {object} target node
* @param {array} list
* @param {number} newIndex
* @param {boolean} changeSibling
* @return {number} newIndex
*/
export function insertIndex (target, list, newIndex, changeSibling) {
/* istanbul ignore next */
if (newIndex < 0) {
newIndex = 0
}
const before = list[newIndex - 1]
const after = list[newIndex]
list.splice(newIndex, 0, target)
if (changeSibling) {
before && (before.nextSibling = target)
target.previousSibling = before
target.nextSibling = after
after && (after.previousSibling = target)
}
return newIndex
}
/**
* Move the node to a new index in list.
* @param {object} target node
* @param {array} list
* @param {number} newIndex
* @param {boolean} changeSibling
* @return {number} newIndex
*/
export function moveIndex (target, list, newIndex, changeSibling) {
const index = list.indexOf(target)
/* istanbul ignore next */
if (index < 0) {
return -1
}
if (changeSibling) {
const before = list[index - 1]
const after = list[index + 1]
before && (before.nextSibling = after)
after && (after.previousSibling = before)
}
list.splice(index, 1)
let newIndexAfter = newIndex
if (index <= newIndex) {
newIndexAfter = newIndex - 1
}
const beforeNew = list[newIndexAfter - 1]
const afterNew = list[newIndexAfter]
list.splice(newIndexAfter, 0, target)
if (changeSibling) {
beforeNew && (beforeNew.nextSibling = target)
target.previousSibling = beforeNew
target.nextSibling = afterNew
afterNew && (afterNew.previousSibling = target)
}
if (index === newIndexAfter) {
return -1
}
return newIndex
}
/**
* Remove the node from list.
* @param {object} target node
* @param {array} list
* @param {boolean} changeSibling
*/
export function removeIndex (target, list, changeSibling) {
const index = list.indexOf(target)
/* istanbul ignore next */
if (index < 0) {
return
}
if (changeSibling) {
const before = list[index - 1]
const after = list[index + 1]
before && (before.nextSibling = after)
after && (after.previousSibling = before)
}
list.splice(index, 1)
}