419 lines
12 KiB
JavaScript
419 lines
12 KiB
JavaScript
/** *
|
||
* 工具类
|
||
*/
|
||
(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 = "<br>"
|
||
|
||
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,
|
||
}
|
||
|
||
})() |