zview-mobile-editor
Version:
A WYSIWYG text editor base on html5 and vue
133 lines (127 loc) • 4.27 kB
JavaScript
/**
* Created by peak on 2017/2/15.
*/
/**
* add every elements of extArr to sourceArr.
* @param sourceArr
* @param extArr
*/
export const mergeArray = (sourceArr, extArr) => {
// note: Array.prototype.push.apply(arr1,arr2) is unreliable
extArr.forEach((el) => {
sourceArr.push(el)
})
}
/**
* find all the descendant text nodes of a element
* @param ancestor
*/
export const getDescendantTextNodes = (ancestor) => {
if (ancestor.nodeType === Node.TEXT_NODE) {
return [ancestor]
}
const textNodes = []
if (!ancestor.hasChildNodes()) {
return textNodes
}
const childNodes = ancestor.childNodes
for (let i = 0; i < childNodes.length; i++) {
const node = childNodes[i]
if (node.nodeType === Node.TEXT_NODE) {
textNodes.push(node)
} else if (node.nodeType === Node.ELEMENT_NODE) {
mergeArray(textNodes, getDescendantTextNodes(node))
}
}
return textNodes
}
/**
* find all the descendant text nodes of an ancestor element that before the specify end element,
* the ancestor element must contains the end element.
* @param ancestor
* @param endEl
*/
export const getBeforeEndDescendantTextNodes = (ancestor, endEl) => {
const textNodes = []
let endIndex = 0
for (let i = 0; i < ancestor.childNodes.length; i++) {
if (ancestor.childNodes[i].contains(endEl)) {
endIndex = i
break
}
}
for (let i = 0; i <= endIndex; i++) {
const node = ancestor.childNodes[i]
if (node === endEl) {
mergeArray(textNodes, getDescendantTextNodes(node))
} else if (i === endIndex) {
if (node.nodeType === Node.TEXT_NODE) {
textNodes.push(node)
} else if (node.nodeType === Node.ELEMENT_NODE) {
mergeArray(textNodes, getBeforeEndDescendantTextNodes(node, endEl))
}
} else if (node.nodeType === Node.TEXT_NODE) {
textNodes.push(node)
} else if (node.nodeType === Node.ELEMENT_NODE) {
mergeArray(textNodes, getDescendantTextNodes(node))
}
}
return textNodes
}
/**
* find all the descendant text nodes of an ancestor element that after the specify start element,
* the ancestor element must contains the start element.
* @param ancestor
* @param startEl
*/
export const getAfterStartDescendantTextNodes = (ancestor, startEl) => {
const textNodes = []
let startIndex = 0
for (let i = 0; i < ancestor.childNodes.length; i++) {
if (ancestor.childNodes[i].contains(startEl)) {
startIndex = i
break
}
}
for (let i = startIndex; i < ancestor.childNodes.length; i++) {
const node = ancestor.childNodes[i]
if (node === startEl) {
mergeArray(textNodes, getDescendantTextNodes(node))
} else if (i === startIndex) {
if (node.nodeType === Node.TEXT_NODE) {
textNodes.push(node)
} else if (node.nodeType === Node.ELEMENT_NODE) {
mergeArray(textNodes,
getAfterStartDescendantTextNodes(node, startEl))
}
} else if (node.nodeType === Node.TEXT_NODE) {
textNodes.push(node)
} else if (node.nodeType === Node.ELEMENT_NODE) {
mergeArray(textNodes,
getDescendantTextNodes(node))
}
}
return textNodes
}
/**
* get the closest parent block node of a text node.
* @param node
* @return {Node}
*/
export const getParentBlockNode = (node) => {
const blockNodeNames = ['DIV', 'P', 'SECTION', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6',
'OL', 'UL', 'LI', 'TR', 'TD', 'TH', 'TBODY', 'THEAD', 'TABLE', 'ARTICLE', 'HEADER', 'FOOTER']
let container = node
while (container) {
if (blockNodeNames.includes(container.nodeName)) {
break
}
container = container.parentNode
}
return container
}
export const isInlineElement = (node) => {
const inlineNodeNames = ['A', 'ABBR', 'ACRONYM', 'B', 'CITE', 'CODE', 'EM', 'I',
'FONT', 'IMG', 'S', 'SMALL', 'SPAN', 'STRIKE', 'STRONG', 'U', 'SUB', 'SUP']
return inlineNodeNames.includes(node.nodeName)
}