mylomen-server/static/js/styleCmd.js

329 lines
12 KiB
JavaScript
Raw Normal View History

2024-10-28 01:33:33 +08:00
/** * 样式 */
(function (utils) {
function inputHandle(e) {
if (!utils.inCompositionEvent) {
updateText(e)
}
}
function compositionstartHandle(e) {
// console.log("compositionstart")
utils.inCompositionEvent = true
}
function compositionendHandle(e) {
// console.log("compositionend")
updateText(e)
utils.inCompositionEvent = false
}
/**
* 鼠标按下事件
*/
function windowsCtrZHandle(e) {
const event = e || window.event //标准化事件处理
const keyCode = event.keyCode || event.which || event.charCode
const metaKey = event.metaKey
// console.log("windows键盘事件 ", event, keyCombination, metaKey, keyCode)
//撤销
if (metaKey && keyCode === 90) {
console.log('触发ctrl + Z 事件', e.target)
if (utils.latestOpDoc !== undefined && utils.latestOpDoc !== null) {
// //
// let cNo = parseInt(utils.latestOpDoc.getAttribute("data-order"))
// console.log("恢复", utils.latestOpDoc, cNo)
// if (cNo > 1) {
// let qq = "#noteshare p[data-order='" + (cNo - 1) + "']"
// // console.log("qq: ", qq)
// utils.insertAfter(utils.latestOpDoc, document.querySelector(qq))
// } else {
// //添加元素到首位
// yanxuelu.insertBefore(utils.latestOpDoc, utils.MyRoot.children[0])
// }
// utils.MyDocMap.get(cNo).setHidden(false)
//恢复
utils.latestOpDoc.recovery();
// utils.MyDocMap.get(cNo).setSource(latestOpDoc.innerText)
//
showTestText()
event.preventDefault()
event.returnValue = false
}
utils.latestOpDoc = null
}
}
/**
* 鼠标按下事件 & 键盘组合事件
* @param {*} e
*/
function onkeydownHandle(e) {
const event = e || window.event //标准化事件处理
// window.event 等价于 event参数
// 有些浏览器除了通过keyCode获取输入键code还可以通过whichcharCode获取这么写是出于浏览器兼容性考虑
const keyCode = event.keyCode || event.which || event.charCode
const keyCombination = event.ctrlKey
const metaKey = event.metaKey
// console.log("键盘事件 ", event, keyCombination, metaKey, keyCode)
// ctrl + c 复制
if (keyCombination && keyCode === 67) {
// 阻止默认事件
event.preventDefault()
event.returnValue = false
console.log('触发ctrl + c 事件', e.target)
}
//撤销
if (metaKey && keyCode === 90) {
// console.log('触发ctrl + Z 事件', e.target)
if (utils.latestOpDoc !== undefined && utils.latestOpDoc !== null) {
// console.log(utils.latestOpDoc)
//恢复
utils.latestOpDoc.recovery();
//
// console.log(MyDocMap.get(cNo))
let cNo = parseInt(utils.latestOpDoc.getData().getAttribute("data-order"))
utils.MyDocMap.get(cNo).setHidden(false)
// utils.MyDocMap.get(cNo).setSource(latestOpDoc.innerText)
//
showTestText()
//阻止事件
event.preventDefault()
event.returnValue = false
}
utils.latestOpDoc = null
}
//删除
if (keyCode === 46 || keyCode === 8) {
let curP = event.target
let cNo = parseInt(curP.getAttribute("data-order"))
//维护最近一次编辑的内容
if (utils.latestOpDoc === undefined || utils.latestOpDoc === null || utils.latestOpDoc.getData().getAttribute("data-id") !== curP.getAttribute("data-id")) {
utils.latestOpDoc = new utils.MyRecovery(curP.cloneNode(true), function () {
let cNo = parseInt(this.data.getAttribute("data-order"))
console.log("恢复", this.data, cNo)
if (cNo > 1) {
utils.insertAfter(this.data, document.querySelector("#noteshare p[data-order='" + (cNo - 1) + "']"))
} else {
//添加元素到首位
utils.MyRoot.insertBefore(this.data, utils.MyRoot.children[0])
}
// 恢复该元素展示
utils.MyDocMap.get(cNo).setHidden(false)
})
}
//如果是第一行
let previousSibling = curP.previousSibling
// console.log(curP, previousSibling == undefined ,previousSibling.id == undefined)
if (previousSibling === undefined || previousSibling.id === undefined) {
//显示用户的输入内容
showTestText()
return
}
// console.log('触发删除', curP.innerHTML, cNo, utils.num, utils.MyDocMap.get(cNo + 1))
let curS = window.getSelection()
// console.log("当前内容: ", curP.innerHTML, " 当前选区 ", curS)
//处理前面没有内容,后面还有内容需要拼接到上层的场景
if ((curS.isCollapsed && curS.anchorOffset === 0) || curP.innerHTML === '<br>') {
let curNodeRetainHtml = curP.innerHTML
//异步修正顺序(第一行删除不掉)
// if (curP.innerHTML === '<br>' ) {
// console.log("删除当前行。选取信息: ", curS)
//阻止事件传递
event.preventDefault()
event.returnValue = false
//设置该元素隐藏
utils.MyDocMap.get(cNo).setHidden(true)
//删除当前元素
curP.remove()
//拼接
if (curNodeRetainHtml !== '<br>') {
previousSibling.innerHTML = previousSibling.innerHTML + curNodeRetainHtml
}
//收起选区到一个点,光标落在一个可编辑元素上
window.getSelection().setPosition(previousSibling, 1);
}
//显示用户的输入内容
showTestText();
}
//回车事件
if (keyCode === 13 /* && currentNode === key.lastElementChild */) {
event.preventDefault()
let uuid = utils.uuid()
let curOrder = ++(utils.num)
var newParagraph = document.createElement("p")
newParagraph.setAttribute("contenteditable", "true")
newParagraph.setAttribute("data-id", uuid)
newParagraph.setAttribute("id", uuid)
newParagraph.setAttribute("data-order", curOrder)
newParagraph.onkeydown = onkeydownHandle
newParagraph.focus()
newParagraph.innerHTML = "<br>"
utils.MyRoot.appendChild(newParagraph)
utils.MyDocMap.set(curOrder, new utils.MyNode(uuid))
//收起选区到一个点,光标落在一个可编辑元素上
window.getSelection().setPosition(newParagraph, 0)
}
}
/**
*
*/
function showTestText() {
//显示用户的输入内容
const obj = {};
for ([k, v] of utils.MyDocMap.entries()) {
if (v.getHidden() && v.getHidden() === true) {
continue
}
obj[k] = v
}
// console.log("当前文档结构数: ",obj);
// var userInput = document.getElementById("testInput")
// userInput.value = JSON.stringify(obj)
}
/**
* 更新文档
* @param {*} e
*/
function updateText(e) {
let curP = e.target
//是否需要变更元素类型
utils.firstCmd(curP, onkeydownHandle)
let cNo = parseInt(curP.getAttribute("data-order"))
let cp = utils.MyDocMap.get(cNo)
//内容不变则不处理
let h5CurLen = curP.innerText.length
let myDocNodeLen = (cp && cp.getSource()) ? cp.getSource().length : 0
if (h5CurLen === myDocNodeLen) {
return
}
cp.setSource(curP.innerText)
// console.log("curPTx: ", curP.innerText, "MyDocMap : ", utils.MyDocMap)
//显示用户的输入内容
showTestText()
}
function surroundContentsByStyle() {
let curS = utils.getSelection()
let curSec = curS.getRangeAt(0)
let styleName = this.getAttribute("data-value");
let className = utils.parseStyleName2ClassName(styleName)
//todo 只对 nodeType = p 执行
// console.log("当前光标信息: ", curS, " 当前选区信息 : ", curSec)
for (let i = 0; i < curS.rangeCount; i++) {
let curSec = curS.getRangeAt(i)
let curEleSize = curSec.commonAncestorContainer.childNodes.length
let curStartP = curSec.startContainer.parentElement
//todo 先支持 一行。
let start = curSec.startOffset;
let end = curSec.endOffset;
// console.log(curStartP.cloneNode(true), styleName, start, end, " curEleSize: ", curEleSize)
let curPEle = null;
//第一次选择的时候将整行转换成<p><span></span></p>
if (curEleSize === 0) {
//没选择,则退出
if (start === end) {
return
}
// console.log("debug1: ", curSec.commonAncestorContainer)
//维护最近一次编辑的内容(暂时只支持恢复最近一次编辑)
utils.latestOpDoc = new utils.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
utils.syncOnePInfo(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 contenteditable="true" class=' + className + '>' + curStartP.innerText.charAt(j) + '</span>';
} else {
curHtml += '<span>' + curStartP.innerText.charAt(j) + '</span>';
}
}
curStartP.innerHTML = curHtml;
curPEle = curStartP;
} else {
// console.log("debug2: ", curSec.commonAncestorContainer)
//维护最近一次编辑的内容(暂时只支持恢复最近一次编辑)
utils.latestOpDoc = new utils.MyRecovery(curSec.commonAncestorContainer.cloneNode(true), function () {
console.log("恢复上一步样式1", this.data)
let curEl = document.getElementById(this.data.getAttribute("id"));
curEl.innerHTML = this.data.innerHTML;
//文本映射 直接覆盖 map 中的 childrenStyle
utils.syncOnePInfo(this.data);
})
let myChildren = curSec.commonAncestorContainer.children
for (let j = 0; j < curEleSize; j++) {
let curEle = myChildren[j]
if (curS.containsNode(curEle, true)) {
curEle.classList.remove(className);
curEle.classList.add(className);
}
}
curPEle = curSec.commonAncestorContainer;
}
//文本映射 直接覆盖 map 中的 childrenStyle
utils.syncOnePInfo(curPEle)
}
}
window.styleCmd = {
inputHandle, compositionstartHandle, compositionendHandle,
onkeydownHandle, windowsCtrZHandle,
surroundContentsByStyle,
showTestText,
updateText,
}
})(utils)