mylomen-server/static/js/styleCmd.js
shaoyongjun c31252f2c8 to:sync
2024-10-28 01:33:33 +08:00

329 lines
12 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.

/** * 样式 */
(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)