/** * * 工具类 */ (function () { /** * 最新修改的元素 */ const latestOpDoc = null class MyRecovery { constructor(data, func) { this.data = data; this.func = func; } getData() { return this.data; } getFun() { return this.func; } recovery() { this.func(); } } /** * 行数增加记录 */ const num = 0 /** * 是否开始输入中文 */ const inCompositionEvent = false; /** * 我的文档数据 */ const MyDocMap = new Map() // push,推一个在后面,就是 append 的意思 // pop,从后面拉走,配合 push 就是栈 // unshift,从前面加一个数据,就是 insert(it, 0) 的意思 // shift,前面拉个数据走,配合 shift 就是一个反向栈,配合 push 就是队列 class MyQueue { constructor(size) { this.insertIndex = 0 this.delIndex = 0 this.capacity = 0; this.size = size; this.arr = new Array(size); } push(handle) { if (this.capacity === this.arr.length) { console.log("满了"); this.capacity--; this.arr[this.capacity] = null; //todo 替代 // this.end++; } this.arr[this.capacity] = handle; this.capacity++; } pull() { if (this.capacity <= 0) { return null } this.capacity--; //到底回退 if (this.shift > this.size) { this.shift = 0; } return this.arr[this.shift]; } } class MyNode { constructor(id) { this.id = id this.hidden = false this.style = new InnerStyle() } getHidden() { return this.hidden } setHidden(val) { this.hidden = val } setSource(source) { this.source = source } getSource() { return this.source } getStyle() { return this.style } } class InnerStyle { constructor() { this.nodeType = "p" //map-> index:classList this.childrenStyle = null; this.preStyle = null; this.getNodeType = function getNodeType() { return this.nodeType } this.setNodeType = function setNodeType(nodeType) { this.nodeType = nodeType } //前置类型 如 ul ol 代码块 等 this.setPreStyle = function setPreStyle(k, v) { if (this.preStyle == null) { this.preStyle = new MyKV(k, v); } } this.getPreStyle = function getPreStyle() { return this.preStyle } } setChildrenStyle(index, classList) { if (this.childrenStyle === null) { this.childrenStyle = new Map(); } this.childrenStyle.set(index, classList) } getChildrenStyle(index) { return this.childrenStyle.get(index); } getChildrenStyleMap() { return this.childrenStyle; } setChildrenStyleMapNull() { this.childrenStyle = null; } } class MyKV { constructor(k, v) { this.k = k this.v = v this.getK = function getK() { return this.k } this.getV = function getV() { return this.v } } } /** * 主节点元素 */ const MyRoot = document.getElementById("noteshare") function isNum(value) { return !isNaN(parseFloat(value)) && isFinite(value) } function getSelection() { return window.getSelection() || document.selection } /** * * @returns 生产uuid */ function uuid() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx' .replace(/[xy]/g, function (c) { const r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8) return v.toString(16) }).split("-")[0] } /** * 在目标元素后面插叙 新元素 * @param {*} newElement * @param {*} targetElement */ function insertAfter(newElement, targetElement) { // console.log("开始: ",newElement, targetElement) var parent = targetElement.parentNode if (parent.lastChild == targetElement) { // 如果最后的节点是目标元素,则直接添加。因为默认是最后 parent.appendChild(newElement) } else { parent.insertBefore(newElement, targetElement.nextSibling) //如果不是,则插入在目标元素的下一个兄弟节点 的前面。也就是目标元素的后面 } } function parseOrder(curP) { return parseInt(curP.getAttribute("data-order")) } /** * * @param {*} curP * @param onkeydownHandle */ function firstCmd(curP, onkeydownHandle) { let newParagraph; let inputLength = curP.innerText.length /** * h1 ~ h6 */ if (curP.innerText.startsWith("#") && curP.innerHTML.endsWith(" ")) { let curNo = parseOrder(curP) let mapNode = utils.MyDocMap.get(curNo) // console.log(curP, " - ", curP.innerHTML, curP.innerHTML.startsWith("# ")) if (curP.innerHTML.startsWith("# ") || curP.innerHTML.startsWith("# ")) { mapNode.getStyle().setNodeType("h1") becomeAnotherElement(curP, "h1", onkeydownHandle) } else if (curP.innerHTML.startsWith("## ")) { mapNode.getStyle().setNodeType("h2") becomeAnotherElement(curP, "h2", onkeydownHandle) } else if (curP.innerHTML.startsWith("### ")) { mapNode.getStyle().setNodeType("h3") becomeAnotherElement(curP, "h3", onkeydownHandle) } else if (curP.innerHTML.startsWith("#### ")) { mapNode.getStyle().setNodeType("h4") becomeAnotherElement(curP, "h4", onkeydownHandle) } else if (curP.innerHTML.startsWith("##### ")) { mapNode.getStyle().setNodeType("h5") becomeAnotherElement(curP, "h5", onkeydownHandle) } else { mapNode.getStyle().setNodeType("h6") becomeAnotherElement(curP, "h6", onkeydownHandle) } } /** * 无序列表效果 */ if (inputLength === 2 && curP.innerText.startsWith("-") && curP.innerHTML.endsWith(" ")) { let curNo = parseOrder(curP) let mapNode = utils.MyDocMap.get(curNo) mapNode.getStyle().setPreStyle("ul", true) //clean curP.innerHTML = "" mapNode.setSource("") //根据上一层级元素动态选择 todo curP.setAttribute("style", "padding-left: 1rem;") //新增元素 newParagraph = document.createElement("span"); newParagraph.setAttribute("contenteditable", "false") //∙ vs ∘ newParagraph.innerHTML = "∙  " curP.append(newParagraph) //添加一个选区 var selObj = window.getSelection() var rangeObj = document.createRange() rangeObj.selectNode(curP) selObj.addRange(rangeObj) //收起选区到一个点,光标落在一个可编辑元素上 window.getSelection().collapse(curP, true) } /** * 有序列表效果 */ if (inputLength > 2 && inputLength <= 5 && isNum(curP.innerText.substring(0, inputLength - 2)) && curP.innerHTML.endsWith(". ")) { let num = curP.innerText.substring(0, inputLength - 2) console.log(curP.innerText, num) let curNo = parseOrder(curP) let mapNode = utils.MyDocMap.get(curNo) mapNode.getStyle().setPreStyle("ol", num) //clean curP.innerHTML = "" mapNode.setSource("") //todo curP.setAttribute("style", "padding-left: 1rem;") //新增元素 newParagraph = document.createElement("span"); newParagraph.setAttribute("contenteditable", "false") newParagraph.innerHTML = num + ". " curP.append(newParagraph) //添加一个选区 var selObj = window.getSelection() var rangeObj = document.createRange() rangeObj.selectNode(curP) selObj.addRange(rangeObj) //收起选区到一个点,光标落在一个可编辑元素上 window.getSelection().collapse(curP, true) } } /** * 变成另一个元素 * @param {*} curP * @param {*} elementName */ function becomeAnotherElement(curP, elementName, onkeydownHandle) { var newParagraph = document.createElement(elementName) newParagraph.setAttribute("contenteditable", "true") newParagraph.setAttribute("data-id", curP.getAttribute("data-id")) newParagraph.setAttribute("id", curP.getAttribute("data-id")) newParagraph.setAttribute("data-order", curP.getAttribute("data-order")) newParagraph.onkeydown = onkeydownHandle //todo 支持 有数据的行 在行首输入 # // if() // switch (elementName){ // case "h1": // } newParagraph.innerHTML = "
" insertAfter(newParagraph, curP) curP.remove() //matData let curNo = parseOrder(curP) let mapNode = utils.MyDocMap.get(curNo) mapNode.setSource("") //收起选区到一个点,光标落在一个可编辑元素上 window.getSelection().setPosition(newParagraph, 0) } function parseStyleName2ClassName(styleName) { switch (styleName) { case "b": return "childStyleStrong"; case "i": return "childStyleI"; case "u": return "childStyleU"; case "c_red": return "childStyleColor"; case "del": return "childStyleDel" } } function syncOnePInfo(p) { //子元素为空不处理 if (p.children.length <= 0) { return } // let id = p.getAttribute("id"); let order = parseInt(p.getAttribute("data-order")); let curMapData = this.MyDocMap.get(order); //清空重置 curMapData.getStyle().setChildrenStyleMapNull(); for (let i = 0; i < p.children.length; i++) { let curItem = p.children[i]; let tmpClassList = curItem.classList; if (tmpClassList != null && tmpClassList.length > 0) { curMapData.getStyle().setChildrenStyle(i, tmpClassList); } } console.log("curPEle : ", p, " children: ", p.children, " childrenMap: ", curMapData.getStyle().getChildrenStyleMap()) } window.utils = { isNum, uuid, parseOrder, getSelection, insertAfter, firstCmd, becomeAnotherElement, parseStyleName2ClassName, syncOnePInfo, latestOpDoc, num, inCompositionEvent, MyDocMap, MyRoot, MyNode, InnerStyle, MyKV, MyQueue, MyRecovery, } })()