shaoyongjun ab00b85c8f to:sync
2024-10-31 01:32:52 +08:00

481 lines
19 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use strict";
import {MyRecovery} from "../model/MyRecovery.js";
import {MyDocItem} from "../model/MyDocItem.js";
import {MyMapItem} from "../model/MyMapItem.js";
export class MyBiz {
constructor() {
/**
* 输入事件
*/
window.myEdit.eventListener.RegisterEventHandle('input', window.myEdit.eventListener.InputListener);
window.myEdit.eventListener.RegisterEventHandle('compositionstart', window.myEdit.eventListener.CompositionstartListener);
window.myEdit.eventListener.RegisterEventHandle('compositionend', window.myEdit.eventListener.CompositionendListener);
// 初始化第一个输入框
let newParagraph = document.createElement("p");
newParagraph.setAttribute("contenteditable", "true");
let uuid = window.myEdit.utils.Uuid()
let curOrder = window.myEdit.ctx.incrementNumThenReturn();
newParagraph.setAttribute("data-id", uuid)
newParagraph.setAttribute("id", uuid)
newParagraph.setAttribute("data-order", curOrder)
newParagraph.onkeydown = window.myEdit.eventListener.KeydownListener
newParagraph.innerHTML = "<br>"
//添加一行
window.myEdit.utils.AddNewParagraph(newParagraph);
}
/**
* 根据类型名称解析 样式的 class 名称
* @param styleName
* @returns {string}
*/
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"
}
}
/**
* 输入事件
* @param e
*/
inputHandle(e) {
let curP = window.myEdit.utils.GetEventTarget(e);
this.updateText(curP)
}
/**
* 中文输入开始事件
* @param e
*/
compositionstartHandle(e) {
// console.log("compositionstart")
window.myEdit.ctx.inCompositionEvent = true
}
/**
* 中文输入结束事件
* @param e
*/
compositionendHandle(e) {
// console.log("compositionend")
let curP = window.myEdit.utils.GetEventTarget(e);
this.updateText(curP)
//中文输入结束
window.myEdit.ctx.inCompositionEvent = false
}
/**
* 撤销事件
* @param event
*/
cancelHandle(event) {
console.log('触发ctrl + Z 事件', event.target)
if (window.myEdit.ctx.latestOpDoc !== undefined && window.myEdit.ctx.latestOpDoc !== null) {
//恢复
window.myEdit.ctx.latestOpDoc.recovery();
//测试展示
window.myEdit.ctx.showTestText()
//阻止事件
window.myEdit.utils.ProhibitDefaultEvent(event);
}
window.myEdit.ctx.latestOpDoc = null
}
/**
* 删除事件
* @param event
*/
deleteHandle(event) {
let curP = window.myEdit.utils.GetEventTarget(event);
let cNo = parseInt(curP.getAttribute("data-order"))
//维护最近一次编辑的内容
if (window.myEdit.ctx.latestOpDoc === undefined
|| window.myEdit.ctx.latestOpDoc === null
|| window.myEdit.ctx.latestOpDoc.getData().getAttribute("data-id") !== curP.getAttribute("data-id")) {
window.myEdit.ctx.latestOpDoc = new MyRecovery(curP.cloneNode(true), function () {
let cNo = parseInt(this.data.getAttribute("data-order"))
console.log("恢复", this.data, cNo, " this: ", this)
if (cNo > 1) {
window.myEdit.utils.InsertAfter(this.data, document.querySelector("#noteshare p[data-order='" + (cNo - 1) + "']"))
} else {
//添加元素到首位 todo_xxx
// window.myEdit.ctx.MyRoot.insertBefore(this.data, window.myEdit.ctx.MyRoot.children[0])
window.myEdit.ctx.MyRoot.insertBefore(this.data, window.myEdit.ctx.MyRoot.children[0]);
}
// 恢复该元素展示
window.myEdit.ctx.MyDocMap.get(cNo).setHidden(false);
})
}
//如果是第一行
let previousSibling = curP.previousSibling
console.log(curP, previousSibling === undefined, previousSibling.id === undefined)
if (previousSibling === undefined || previousSibling.id === undefined) {
//显示用户的输入内容
window.myEdit.ctx.showTestText()
return
}
console.log('触发删除', curP.innerHTML, cNo)
let curS = window.myEdit.utils.GetSelection();
// console.log("当前内容: ", curP.innerHTML, " 当前选区 ", curS)
//处理前面没有内容,后面还有内容需要拼接到上层的场景
if ((curS.isCollapsed && curS.anchorOffset === 0) || curP.innerHTML === '<br>') {
let curNodeRetainHtml = curP.innerHTML
//阻止事件传递
window.myEdit.utils.ProhibitDefaultEvent(event);
//设置该元素隐藏
window.myEdit.ctx.MyDocMap.get(cNo).setHidden(true)
//删除当前元素
// curP.remove()
curP.innerHTML = "<br/>"
let emptyRowNoList = window.myEdit.ctx.MyDocMap.get("emptyRowNoList");
if (emptyRowNoList === undefined || emptyRowNoList === null) {
emptyRowNoList = [];
window.myEdit.ctx.MyDocMap.set("emptyRowNoList", emptyRowNoList);
}
emptyRowNoList.push(cNo);
//拼接
if (curNodeRetainHtml !== '<br>') {
previousSibling.innerHTML = previousSibling.innerHTML + curNodeRetainHtml
}
//收起选区到一个点,光标落在一个可编辑元素上
window.getSelection().setPosition(previousSibling, 1);
}
//显示用户的输入内容
window.myEdit.ctx.showTestText();
}
/**
* 回车事件
* @param event
* @param onkeydownHandle
*/
enterHandler(event) {
//阻止事件
window.myEdit.utils.ProhibitDefaultEvent(event);
//uuid
let uuid = window.myEdit.utils.Uuid();
//rowNo
let rowNo = 0;
let emptyRowNoList = window.myEdit.ctx.MyDocMap.get("emptyRowNoList");
console.log(emptyRowNoList);
if (emptyRowNoList === undefined || emptyRowNoList === null) {
rowNo = window.myEdit.ctx.incrementNumThenReturn();
//添加新元素
let newParagraph = document.createElement("p")
newParagraph.setAttribute("contenteditable", "true")
newParagraph.setAttribute("data-id", uuid)
newParagraph.setAttribute("id", uuid)
newParagraph.setAttribute("data-order", rowNo)
newParagraph.onkeydown = window.myEdit.eventListener.KeydownListener
newParagraph.innerHTML = "<br>"
window.myEdit.ctx.MyRoot.appendChild(newParagraph)
window.myEdit.ctx.MyDocMap.set(rowNo, new MyMapItem(uuid))
//收起选区到一个点,光标落在一个可编辑元素上
window.getSelection().setPosition(newParagraph, 0);
return
}
let sortArr = emptyRowNoList.sort((a, b) => a - b)
console.log(sortArr);
// 最小值
rowNo = sortArr[0];
let newParagraph = document.querySelector("#noteshare p[data-order='" + rowNo + "']");
newParagraph.innerHTML = "<br>";
window.myEdit.ctx.MyDocMap.get(rowNo).setHidden(false);
//收起选区到一个点,光标落在一个可编辑元素上
window.getSelection().setPosition(newParagraph, 0)
}
/**
* 更新文档
* @param {*} e
*/
updateText(curP) {
if (window.myEdit.ctx.inCompositionEvent) {
return;
}
let myP = new MyDocItem(curP);
let cNo = myP.parseOrder();
let mapItem = window.myEdit.ctx.getMapItem(cNo)
//内容不变则不处理
let h5CurLen = curP.innerText.length
let myDocNodeLen = (mapItem && mapItem.getSource()) ? mapItem.getSource().length : 0
if (h5CurLen === myDocNodeLen) {
return
}
mapItem.setSource(curP.innerText)
// console.log("curPTx: ", curP.innerText, "MyDocMap : ", utils.MyDocMap)
//显示用户的输入内容
window.myEdit.ctx.showTestText()
}
/**
* 空格键处理
* @param {*} event
*/
emptyKeyWorkHandler(event) {
let curP = window.myEdit.utils.GetEventTarget(event);
let myDocItem = new MyDocItem(curP);
let inputLength = curP.innerText.length
/**
* h1 ~ h6
*/
if (curP.innerText.startsWith("#") && curP.innerHTML.endsWith("&nbsp;")) {
let curNo = myDocItem.parseOrder();
let mapNode = window.myEdit.ctx.MyDocMap.get(curNo);
// console.log(curP, " - ", curP.innerHTML, curP.innerHTML.startsWith("# "))
if (curP.innerHTML.startsWith("#&nbsp;") || curP.innerHTML.startsWith("# ")) {
mapNode.getStyle().setNodeType("h1")
this.becomeAnotherElement(curP, "h1", onkeydownHandle)
} else if (curP.innerHTML.startsWith("##&nbsp;")) {
mapNode.getStyle().setNodeType("h2")
this.becomeAnotherElement(curP, "h2", onkeydownHandle)
} else if (curP.innerHTML.startsWith("###&nbsp;")) {
mapNode.getStyle().setNodeType("h3")
this.becomeAnotherElement(curP, "h3", onkeydownHandle)
} else if (curP.innerHTML.startsWith("####&nbsp;")) {
mapNode.getStyle().setNodeType("h4")
this.becomeAnotherElement(curP, "h4", onkeydownHandle)
} else if (curP.innerHTML.startsWith("#####&nbsp;")) {
mapNode.getStyle().setNodeType("h5")
this.becomeAnotherElement(curP, "h5", onkeydownHandle)
} else {
mapNode.getStyle().setNodeType("h6")
this.becomeAnotherElement(curP, "h6", onkeydownHandle)
}
}
/**
* 无序列表效果
*/
if (inputLength === 2 && curP.innerText.startsWith("-") && curP.innerHTML.endsWith("&nbsp;")) {
let curNo = myDocItem.parseOrder();
let mapNode = window.myEdit.ctx.MyDocMap.get(curNo);
mapNode.getStyle().setPreStyle("ul", true)
//clean
curP.innerHTML = ""
mapNode.setSource("")
//根据上一层级元素动态选择 todo
curP.setAttribute("style", "padding-left: 1rem;")
//新增元素
let newParagraph = document.createElement("span");
newParagraph.setAttribute("contenteditable", "false")
//∙ vs ∘
newParagraph.innerHTML = "∙ &nbsp;"
curP.append(newParagraph)
//添加一个选区
var selObj = window.myEdit.utils.GetSelection();
var rangeObj = document.createRange()
rangeObj.selectNode(curP)
selObj.addRange(rangeObj)
//收起选区到一个点,光标落在一个可编辑元素上
window.myEdit.utils.GetSelection().collapse(curP, true)
}
/**
* 有序列表效果
*/
if (inputLength > 2 && inputLength <= 5 && isNum(curP.innerText.substring(0, inputLength - 2)) && curP.innerHTML.endsWith(".&nbsp;")) {
let num = curP.innerText.substring(0, inputLength - 2)
console.log(curP.innerText, num)
let curNo = myDocItem.parseOrder();
let mapNode = window.myEdit.ctx.MyDocMap.get(curNo);
mapNode.getStyle().setPreStyle("ol", num)
//clean
curP.innerHTML = ""
mapNode.setSource("")
//todo
curP.setAttribute("style", "padding-left: 1rem;")
//新增元素
let newParagraph = document.createElement("span");
newParagraph.setAttribute("contenteditable", "false");
newParagraph.innerHTML = num + ".&nbsp;"
curP.append(newParagraph);
//收起选区到一个点,光标落在一个可编辑元素上
window.myEdit.utils.GetSelection().collapse(curP, true)
}
}
/**
* 变成另一个元素
* @param {*} elementName
*/
becomeAnotherElement(elementName) {
let newParagraph = document.createElement(elementName)
newParagraph.setAttribute("contenteditable", "true")
newParagraph.setAttribute("data-id", this.self.getAttribute("data-id"))
newParagraph.setAttribute("id", this.self.getAttribute("data-id"))
newParagraph.setAttribute("data-order", this.self.getAttribute("data-order"))
newParagraph.onkeydown = onkeydownHandle
//todo 支持 有数据的行 在行首输入 #
// if()
// switch (elementName){
// case "h1":
// }
newParagraph.innerHTML = "<br>"
window.myEdit.utils.InsertAfter(newParagraph, this.self)
this.self.remove();
this.self = newParagraph;
//matData
let curNo = parseOrder(this.self)
let mapNode = utils.MyDocMap.get(curNo)
mapNode.setSource("")
//收起选区到一个点,光标落在一个可编辑元素上
window.myEdit.utils.GetSelection().setPosition(newParagraph, 0)
}
/**
* 包围样式事件处理
* @param event
*/
surroundContentsByStyleHandler(event) {
let curS = window.myEdit.utils.GetSelection();
let curP = window.myEdit.utils.GetEventTarget(event);
let styleName = curP.getAttribute("data-value");
if (styleName === undefined) {
styleName = curP.parentNode.getAttribute("data-value");
}
let className = this.parseStyleName2ClassName(styleName)
//todo 只对 nodeType = p 执行
console.log("当前光标信息: ", curS, styleName, " className: ", className, curP)
for (let i = 0; i < curS.rangeCount; i++) {
let curSec = curS.getRangeAt(i);
let curPe = curSec.commonAncestorContainer;
//一个元素节点,例如 <p> 和 <div>。
let curPeIsP = curPe.nodeType === 1 && curPe.nodeName === "P";
let curPeParentIsP = curPe.parentNode.nodeType === 1 && curPe.parentNode.nodeName === "P";
let curPeParentIsDIV = curPe.parentNode.nodeType === 1 && curPe.parentNode.nodeName === "DIV";
let curPeParentIsSpan = curPe.parentNode.nodeType === 1 && (curPe.parentNode.nodeName === 'SPAN"' || curPe.parentNode.nodeName === 'SPAN');
let start = curSec.startOffset;
let end = curSec.endOffset;
console.log(" 当前选区信息 : ", curSec,
"\ncurPe: ", curPe,
"\ncurPeP: ", curPe.parentNode, curPe.parentNode.nodeType, curPe.parentNode.nodeName,
"\ncurPeIsP: ", curPeIsP,
"\ncurPeParentIsP : ", curPeParentIsP,
"\ncurPeParentIsDIV", curPeParentIsDIV,
"\ncurPeParentIsSpan", curPeParentIsSpan,
"\nclassName: ", className,
"\ntart: ", start,
"\nend: ", end)
let curPEle = null;
//第一次选择的时候将整行转换成<p><span></span></p>
if (!curPeIsP && curPeParentIsP) {
//没选择,则退出
if (start === end) {
return
} else {
// div
}
let curStartP = curSec.startContainer.parentElement;
console.log("debug1: ", curStartP, curStartP.nodeType, curStartP.nodeName)
//维护最近一次编辑的内容(暂时只支持恢复最近一次编辑)
window.myEdit.ctx.latestOpDoc = new MyRecovery(curStartP.cloneNode(true), function () {
console.log("恢复上一步样式1", this.innerHTML)
let curEl = document.getElementById(this.data.getAttribute("id"));
curEl.innerHTML = this.data.innerHTML;
//文本映射 直接覆盖 map 中的 childrenStyle
window.myEdit.utils.SyncMapItemChildrenStyle(this.data);
})
let curHtml = ""
for (let j = 0; j < curStartP.innerText.length; j++) {
// console.log(curStartP.innerText.charAt(j))
if (j >= start && j < end) {
curHtml += '<span class=' + className + '>' + curStartP.innerText.charAt(j) + '</span>';
} else {
curHtml += '<span>' + curStartP.innerText.charAt(j) + '</span>';
}
}
curStartP.innerHTML = curHtml;
curPEle = curStartP;
//光标保持
// curS.collapseToEnd();
// window.myEdit.utils.GetSelection().setPosition(newParagraph, 0);
} else {
let tmpPNode = curSec.commonAncestorContainer;
if (!curPeIsP && curPeParentIsSpan) {
tmpPNode = curSec.commonAncestorContainer.parentNode.parentNode;
}
console.log("debug2: ", curSec.commonAncestorContainer, tmpPNode, tmpPNode.children, tmpPNode.childNodes)
//维护最近一次编辑的内容(暂时只支持恢复最近一次编辑)
window.myEdit.ctx.latestOpDoc = new MyRecovery(tmpPNode.cloneNode(true), function () {
console.log("恢复上一步样式1", this.data)
let curEl = document.getElementById(this.data.getAttribute("id"));
curEl.innerHTML = this.data.innerHTML;
//文本映射 直接覆盖 map 中的 childrenStyle
window.myEdit.utils.SyncMapItemChildrenStyle(this.data);
})
let myChildren = tmpPNode.childNodes
// let curEleSize = tmpPNode.childNodes.length
for (let j = 0; j < myChildren.length; j++) {
let curEle = myChildren[j]
if (curS.containsNode(curEle, true)) {
curEle.classList.remove(className);
curEle.classList.add(className);
}
}
curPEle = curSec.commonAncestorContainer;
}
//文本映射 直接覆盖 map 中的 childrenStyle
window.myEdit.utils.SyncMapItemChildrenStyle(curPEle);
}
}
}