* Recursively divide HTML string to two types of nodes: * 1. Block element * 2. Document Fragments contained text and markup tags like a, b, i etc. * * @param {Node} wrapper - wrapper of paster HTML content * @returns {Node[]}
(wrapper: Node)
| 943 | * @returns {Node[]} |
| 944 | */ |
| 945 | private getNodes(wrapper: Node): Node[] { |
| 946 | const children = Array.from(wrapper.childNodes); |
| 947 | let elementNodeProcessingResult: Node[] | void; |
| 948 | |
| 949 | const reducer = (nodes: Node[], node: Node): Node[] => { |
| 950 | if ($.isEmpty(node) && !$.isSingleTag(node as HTMLElement)) { |
| 951 | return nodes; |
| 952 | } |
| 953 | |
| 954 | const lastNode = nodes[nodes.length - 1]; |
| 955 | |
| 956 | let destNode: Node = new DocumentFragment(); |
| 957 | |
| 958 | if (lastNode && $.isFragment(lastNode)) { |
| 959 | destNode = nodes.pop(); |
| 960 | } |
| 961 | |
| 962 | switch (node.nodeType) { |
| 963 | /** |
| 964 | * If node is HTML element: |
| 965 | * 1. Check if it is inline element |
| 966 | * 2. Check if it contains another block or substitutable elements |
| 967 | */ |
| 968 | case Node.ELEMENT_NODE: |
| 969 | elementNodeProcessingResult = this.processElementNode(node, nodes, destNode); |
| 970 | |
| 971 | if (elementNodeProcessingResult) { |
| 972 | return elementNodeProcessingResult; |
| 973 | } |
| 974 | break; |
| 975 | |
| 976 | /** |
| 977 | * If node is text node, wrap it with DocumentFragment |
| 978 | */ |
| 979 | case Node.TEXT_NODE: |
| 980 | destNode.appendChild(node); |
| 981 | |
| 982 | return [...nodes, destNode]; |
| 983 | |
| 984 | default: |
| 985 | return [...nodes, destNode]; |
| 986 | } |
| 987 | |
| 988 | return [...nodes, ...Array.from(node.childNodes).reduce(reducer, [])]; |
| 989 | }; |
| 990 | |
| 991 | return children.reduce(reducer, []); |
| 992 | } |
| 993 | |
| 994 | /** |
| 995 | * Compose paste event with passed type and detail |