function appendNode (parent, insNode, sibling, originNode) {
                if (util.onlyZeroWidthSpace(insNode)) {
                    insNode.innerHTML = util.zeroWidthSpace;
                    so = eo = 1;
                }

                if (insNode.nodeType === 3) {
                    parent.insertBefore(insNode, sibling);
                    return insNode;
                }

                const insChildren = (moveComplete ? insNode : originNode).childNodes;
                let format = insNode.cloneNode(false);
                let first = null;
                let c = null;

                while (insChildren[0]) {
                    c = insChildren[0];
                    if (util._notTextNode(c) && !util.isBreak(c) && !util.isListCell(format)) {
                        if (format.childNodes.length > 0) {
                            if (!first) first = format;
                            parent.insertBefore(format, sibling);
                            format = insNode.cloneNode(false);
                        }
                        parent.insertBefore(c, sibling);
                        if (!first) first = c;
                    } else {
                        format.appendChild(c);
                    }
                }

                if (format.childNodes.length > 0) {
                    if (util.isListCell(parent) && util.isListCell(format) && util.isList(sibling)) {
                        if (newList) {
                            first = sibling;
                            while(sibling) {
                                format.appendChild(sibling);
                                sibling = sibling.nextSibling;
                            }
                            parent.parentNode.insertBefore(format, parent.nextElementSibling);
                        } else {
                            const originNext = originNode.nextElementSibling;
                            const detachRange = util.detachNestedList(originNode, false);
                            if ((rangeElement !== detachRange) || (originNext !== originNode.nextElementSibling)) {
                                const fChildren = format.childNodes;
                                while (fChildren[0]) {
                                    originNode.appendChild(fChildren[0]);
                                }

                                rangeElement = detachRange;
                                reset = true;
                            }
                        }
                    } else {
                        parent.insertBefore(format, sibling);
                    }

                    if (!first) first = format;
                }

                return first;
            }
@description The elements of the "selectedFormats" array are detached from the "rangeElement" element. ("LI" tags are converted to "P" tags)
When "selectedFormats" is null, all elements are detached and return {cc: parentNode, sc: nextSibling, ec: previousSibling, removeArray: [Array of removed elements]}.
@param {Element} rangeElement Range format element (PRE, BLOCKQUOTE, OL, UL...)
@param {Array|null} selectedFormats Array of format elements (P, DIV, LI...) to remove.
If null, Applies to all elements and return {cc: parentNode, sc: nextSibling, ec: previousSibling}
@param {Element|null} newRangeElement The node(rangeElement) to replace the currently wrapped node.
@param {Boolean} remove If true, deleted without detached.
@param {Boolean} notHistoryPush When true, it does not update the history stack and the selection object and return EdgeNodes (util.getEdgeChildNodes)
@returns {Object}