From 0bd5a87973030b0f9ca31d3aaa34a5d3d807409d Mon Sep 17 00:00:00 2001 From: shaoyongjun Date: Tue, 5 Nov 2024 22:43:34 +0800 Subject: [PATCH] to:sync --- static/css/myEdit.css | 252 ++++++++-------- static/css/myEdit.css.old | 194 +++++++++++++ static/css/normalize.css | 2 +- static/js/common/MyRecovery.js | 28 ++ static/js/common/a4Utils.js | 37 +++ static/js/common/ctx.js | 139 +++++++++ static/js/common/demo.js | 19 ++ static/js/common/doc.js | 41 +++ static/js/common/h5_newParagraph.js | 13 + static/js/common/node.js | 41 +++ static/js/common/utils.js | 160 ++++++++++ static/js/event/MyEventListener.js | 162 +++++++++++ .../event/impl/AdjustMyFontSizeEventImpl.js | 34 +++ static/js/event/impl/ApplyStyleEventImpl.js | 157 ++++++++++ static/js/event/impl/CancelEventImpl.js | 26 ++ static/js/event/impl/CopyEventImpl.js | 13 + static/js/event/impl/DelEventImpl.js | 83 ++++++ static/js/event/impl/EmptyInputEventImpl.js | 115 ++++++++ static/js/event/impl/EnterEventImpl.js | 18 ++ static/js/event/impl/InputEventImpl.js | 34 +++ static/js/event/impl/KeyDownEventImpl.js | 42 +++ static/js/event/impl/KeyUpEventImpl.js | 49 ++++ static/js/event/impl/MouseDownEventImpl.js | 33 +++ static/js/event/impl/MutationObserverImpl.js | 93 ++++++ static/js/event/impl/PasteEventImpl.js | 13 + static/js/event/impl/RSizeEventImpl.js | 103 +++++++ static/js/index.js | 22 ++ static/js/init.go | 49 ++-- static/js/{lib => lib.old}/biz/MyBiz.js | 0 static/js/{lib => lib.old}/common/MyUtils.js | 0 .../{lib => lib.old}/event/MyEventListener.js | 0 static/js/{lib => lib.old}/main.js | 0 .../js/{lib => lib.old}/model/InnerStyle.js | 0 static/js/{lib => lib.old}/model/MyDocItem.js | 0 static/js/{lib => lib.old}/model/MyKV.js | 0 static/js/{lib => lib.old}/model/MyMapItem.js | 0 .../js/{lib => lib.old}/model/MyRecovery.js | 0 static/js/{lib => lib.old}/todolist | 0 static/js/lib/sea.js | 2 + static/yanxuelu.html | 273 +++++++++++------- static/yanxuelu.html.old | 155 ++++++++++ 41 files changed, 2158 insertions(+), 244 deletions(-) create mode 100644 static/css/myEdit.css.old create mode 100644 static/js/common/MyRecovery.js create mode 100644 static/js/common/a4Utils.js create mode 100644 static/js/common/ctx.js create mode 100644 static/js/common/demo.js create mode 100644 static/js/common/doc.js create mode 100644 static/js/common/h5_newParagraph.js create mode 100644 static/js/common/node.js create mode 100644 static/js/common/utils.js create mode 100644 static/js/event/MyEventListener.js create mode 100644 static/js/event/impl/AdjustMyFontSizeEventImpl.js create mode 100644 static/js/event/impl/ApplyStyleEventImpl.js create mode 100644 static/js/event/impl/CancelEventImpl.js create mode 100644 static/js/event/impl/CopyEventImpl.js create mode 100644 static/js/event/impl/DelEventImpl.js create mode 100644 static/js/event/impl/EmptyInputEventImpl.js create mode 100644 static/js/event/impl/EnterEventImpl.js create mode 100644 static/js/event/impl/InputEventImpl.js create mode 100644 static/js/event/impl/KeyDownEventImpl.js create mode 100644 static/js/event/impl/KeyUpEventImpl.js create mode 100644 static/js/event/impl/MouseDownEventImpl.js create mode 100644 static/js/event/impl/MutationObserverImpl.js create mode 100644 static/js/event/impl/PasteEventImpl.js create mode 100644 static/js/event/impl/RSizeEventImpl.js create mode 100644 static/js/index.js rename static/js/{lib => lib.old}/biz/MyBiz.js (100%) rename static/js/{lib => lib.old}/common/MyUtils.js (100%) rename static/js/{lib => lib.old}/event/MyEventListener.js (100%) rename static/js/{lib => lib.old}/main.js (100%) rename static/js/{lib => lib.old}/model/InnerStyle.js (100%) rename static/js/{lib => lib.old}/model/MyDocItem.js (100%) rename static/js/{lib => lib.old}/model/MyKV.js (100%) rename static/js/{lib => lib.old}/model/MyMapItem.js (100%) rename static/js/{lib => lib.old}/model/MyRecovery.js (100%) rename static/js/{lib => lib.old}/todolist (100%) create mode 100644 static/js/lib/sea.js create mode 100644 static/yanxuelu.html.old diff --git a/static/css/myEdit.css b/static/css/myEdit.css index b0cfe3f..59f6a7c 100644 --- a/static/css/myEdit.css +++ b/static/css/myEdit.css @@ -1,7 +1,54 @@ /* 字体 */ -:root { - /* font-size: calc(0.5em + 1vw); */ - /*font-size: 62.5%;*/ +/*:root {*/ +/* font-size: calc(0.5em + 1vw); */ +/*font-size: 62.5%;*/ +/*}*/ + +body, html { + width: 100%; + height: 100%; +} + +/* border + padding + body = width */ +*, :after, :before { + box-sizing: border-box; + + /*选中可编辑框是 外层隐藏黑线*/ + outline: none; +} + +html { + font-family: sans-serif; + line-height: 1.15; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; + -ms-overflow-style: scrollbar; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0) +} + +/*@-ms-viewport {*/ +/* width: device-width;*/ +/*}*/ + +body { + color: #262626; + font-family: Chinese Quote, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Helvetica Neue, Helvetica, Arial, sans-serif; + font-variant: tabular-nums; + line-height: 1.5715; + background-color: #fff; + font-feature-settings: "tnum", "tnum"; + + display: flex; + flex-direction: column; + align-items: center; + + /*background-color: #ffebc3;*/ +} + +hr { + box-sizing: content-box; + height: 0; + overflow: visible } /* style sheet for "A4" printing */ @@ -18,49 +65,86 @@ } } -* { - /* margin: 1px 2px; - padding: 1px 2px; */ - /*font-family: Roboto-Regular, PingFang SC, SF Pro SC, SF Pro Text, SF Pro Icons, Helvetica Neue, Roboto, Helvetica, Arial, sans-serif;*/ - outline: none; - /* box-sizing: border-box; */ -} - -body { - font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", Helvetica, Arial, "Microsoft YaHei", 微软雅黑, 黑体, Heiti, sans-serif, SimSun, 宋体, serif, SourceSansPro; - - display: flex; - flex-direction: column; - justify-content: center; - /*align-items: center;*/ - - /*background-color: #ffebc3;*/ -} header { - /*position: relative;*/ - /*top: 0;*/ + position: fixed; /*border: 1px yellow solid;*/ - /*!* height: 8rem; *!*/ - /*z-index: 9999;*/ - /*left: 0;*/ + z-index: 9999; + top: 0; + left: 0; /*right: 0;*/ - /*width: 100%;*/ + width: 100%; + min-height: 580rem; + + /*background-color: #ffebc3;*/ + /*background-color: deepskyblue;*/ /*响应式*/ - /*display: flex;*/ - /*flex-direction:column;*/ - /*flex-wrap: nowrap;*/ -} - -main { display: flex; flex-direction: column; align-items: center; + /*flex-wrap: nowrap;*/ } -#noteshare { - width: 80%; +#head_top{ + width: 100%; + height: 320rem; + + border: 1px #f5f5f5 solid; + /*box-shadow: 0 40rem 80rem rgba(31, 35, 41, 0.1);*/ + background-color: rgb(255, 255, 255); + /*background-color: blue;*/ + + font-size: 16px; + display: flex; + justify-content: center; + align-items: center; +} + +.fixStylePosition { + display: block; + width: 100%; + height: 260rem; + + /*border: 1px #dee0e3 solid;*/ + /*border: 1px orange solid;*/ + + background-color: rgb(255, 255, 255); + border: 1px #f5f5f5 solid; + /*box-shadow: 0 40rem 80rem rgba(31, 35, 41, 0.1);*/ +} + +.fixStyleOut { + /*border: 1px blue solid;*/ + margin: 0 0; + width: auto; + /*height: 130rem;*/ + padding: 50rem 50rem; + + display: flex; + justify-content: center; + align-items: center; + /*align-content: center;*/ +} + +.fixStyleInnerSpan { + margin: 0 80rem; +} + +main { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + + margin-top: 580rem; + /*min-height: 80%;*/ + + /*border: 1px greenyellow solid;*/ +} + +#yxl_note { + width: 60%; /* width: 21cm; */ min-height: 2000rem; /* font-size: 1.5rem; */ @@ -77,7 +161,7 @@ main { } -#noteshare p { +#yxl_note p { /*border: 1px rgb(248, 245, 245) solid;*/ margin: 0 0; padding: 0 0; @@ -109,86 +193,26 @@ main { margin: 0 60rem; } -.childStyleStrong { - font-weight: bold -} - -.childStyleI { - font-style: italic; -} - -.childStyleU { - text-decoration: underline; - /*/ / 中划线 / / text-decoration: line-through;*/ -} - -.childStyleDel { - text-decoration: line-through; -} - -.childStyleColor { - color: red; +footer{ + width: 100%; } -.fixStylePosition { - display: none; - position: fixed; - z-index: 99; - width: auto; - /*height: 200rem;*/ +/*@media screen and ( max-width: 1024px ) {*/ +/* !*当屏幕尺寸小于768px时,应用下面的css样式*!*/ +/* .fixStylePosition {*/ +/* display: block;*/ +/* z-index: 99;*/ +/* top: 0;*/ +/* width: 100%;*/ +/* min-height: 200rem;*/ +/* margin-bottom: 3rem;*/ +/* }*/ - padding: 20rem 30rem; - /*padding: 0.6rem 1rem 0.6rem 1rem;*/ - justify-content: center; - align-items: center; - align-content: center; - border-radius: 80rem; - border: 1px #dee0e3 solid; - background-color: rgb(255, 255, 255); - /*box-shadow: 0.1rem 0.1rem 0.1rem 0.1rem lightgrey;*/ - box-shadow: 0 40rem 80rem rgba(31, 35, 41, 0.1); -} +/* #_style_utils svg {*/ +/* width: 400rem;*/ +/* height: 400rem;*/ +/* margin: 50rem 0;*/ +/* }*/ -.fixStyleOut { - /*border: 1px blue solid;*/ - margin: 0 0; - width: auto; - /*height: 130rem;*/ - /*padding: 20rem 20rem;*/ - - display: flex; - justify-content: center; - align-items: center; - align-content: center; -} - -.fixStyleInnerSpan { - margin: 0 80rem; -} - -@media screen and ( max-width: 1024px ) { - /*当屏幕尺寸小于768px时,应用下面的css样式*/ - .fixStylePosition { - display: block; - z-index: 99; - top: 0; - width: 100%; - min-height: 200rem; - margin-bottom: 3rem; - } - - body { - top: 1%; - } - - #_style_utils svg { - width: 400rem; - height: 400rem; - margin: 50rem 0; - } - - main { - margin-top: 500rem; - } -} +/*}*/ diff --git a/static/css/myEdit.css.old b/static/css/myEdit.css.old new file mode 100644 index 0000000..b0cfe3f --- /dev/null +++ b/static/css/myEdit.css.old @@ -0,0 +1,194 @@ +/* 字体 */ +:root { + /* font-size: calc(0.5em + 1vw); */ + /*font-size: 62.5%;*/ +} + +/* style sheet for "A4" printing */ +@media print and (width: 21cm) and (height: 29.7cm) { + @page { + margin: 3cm; + } +} + +/* style sheet for "letter" printing */ +@media print and (width: 8.5in) and (height: 11in) { + @page { + margin: 1in; + } +} + +* { + /* margin: 1px 2px; + padding: 1px 2px; */ + /*font-family: Roboto-Regular, PingFang SC, SF Pro SC, SF Pro Text, SF Pro Icons, Helvetica Neue, Roboto, Helvetica, Arial, sans-serif;*/ + outline: none; + /* box-sizing: border-box; */ +} + +body { + font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", Helvetica, Arial, "Microsoft YaHei", 微软雅黑, 黑体, Heiti, sans-serif, SimSun, 宋体, serif, SourceSansPro; + + display: flex; + flex-direction: column; + justify-content: center; + /*align-items: center;*/ + + /*background-color: #ffebc3;*/ +} + +header { + /*position: relative;*/ + /*top: 0;*/ + /*border: 1px yellow solid;*/ + /*!* height: 8rem; *!*/ + /*z-index: 9999;*/ + /*left: 0;*/ + /*right: 0;*/ + /*width: 100%;*/ + + /*响应式*/ + /*display: flex;*/ + /*flex-direction:column;*/ + /*flex-wrap: nowrap;*/ +} + +main { + display: flex; + flex-direction: column; + align-items: center; +} + +#noteshare { + width: 80%; + /* width: 21cm; */ + min-height: 2000rem; + /* font-size: 1.5rem; */ + + /*border: 1px red solid;*/ + margin: auto auto; + padding: 100rem 100rem; + /*box-shadow: 0 40rem 80rem rgba(31, 35, 41, 0.1);*/ + + /*响应式*/ + /*display: flex;*/ + /*flex-direction:column;*/ + /*flex-wrap: nowrap;*/ + +} + +#noteshare p { + /*border: 1px rgb(248, 245, 245) solid;*/ + margin: 0 0; + padding: 0 0; + /* border: none; */ + + /*响应式*/ + flex: 1 1 100%; +} + + +#testInput { + width: 60%; + min-height: 1000rem; + border: 1px rgb(0, 140, 255) solid; + margin: 20px auto; + justify-content: center; +} + +::selection { + color: antiquewhite; + background-color: cadetblue; + text-shadow: #00a9ff; +} + +.my-divider-item { + background-color: #e9e9eb; + width: 1px; + height: 180rem; + margin: 0 60rem; +} + +.childStyleStrong { + font-weight: bold +} + +.childStyleI { + font-style: italic; +} + +.childStyleU { + text-decoration: underline; + /*/ / 中划线 / / text-decoration: line-through;*/ +} + +.childStyleDel { + text-decoration: line-through; +} + +.childStyleColor { + color: red; +} + + +.fixStylePosition { + display: none; + position: fixed; + z-index: 99; + width: auto; + /*height: 200rem;*/ + + padding: 20rem 30rem; + /*padding: 0.6rem 1rem 0.6rem 1rem;*/ + justify-content: center; + align-items: center; + align-content: center; + border-radius: 80rem; + border: 1px #dee0e3 solid; + background-color: rgb(255, 255, 255); + /*box-shadow: 0.1rem 0.1rem 0.1rem 0.1rem lightgrey;*/ + box-shadow: 0 40rem 80rem rgba(31, 35, 41, 0.1); +} + +.fixStyleOut { + /*border: 1px blue solid;*/ + margin: 0 0; + width: auto; + /*height: 130rem;*/ + /*padding: 20rem 20rem;*/ + + display: flex; + justify-content: center; + align-items: center; + align-content: center; +} + +.fixStyleInnerSpan { + margin: 0 80rem; +} + +@media screen and ( max-width: 1024px ) { + /*当屏幕尺寸小于768px时,应用下面的css样式*/ + .fixStylePosition { + display: block; + z-index: 99; + top: 0; + width: 100%; + min-height: 200rem; + margin-bottom: 3rem; + } + + body { + top: 1%; + } + + #_style_utils svg { + width: 400rem; + height: 400rem; + margin: 50rem 0; + } + + main { + margin-top: 500rem; + } +} diff --git a/static/css/normalize.css b/static/css/normalize.css index 443e1a6..9732f7e 100644 --- a/static/css/normalize.css +++ b/static/css/normalize.css @@ -405,7 +405,7 @@ select { button, html input[type="button"], -/* 1 */ + /* 1 */ input[type="reset"], input[type="submit"] { -webkit-appearance: button; diff --git a/static/js/common/MyRecovery.js b/static/js/common/MyRecovery.js new file mode 100644 index 0000000..b5ae3fe --- /dev/null +++ b/static/js/common/MyRecovery.js @@ -0,0 +1,28 @@ +"use strict"; +/** + * 恢复实体 + */ +define(function (require, exports, module) { + + class MyRecovery { + constructor(data, func) { + this.data = data; + this.func = func; + } + + getData() { + return this.data; + } + + getFun() { + return this.func; + } + + recovery() { + this.func(); + } + } + + //导出 + module.exports= MyRecovery; +}); \ No newline at end of file diff --git a/static/js/common/a4Utils.js b/static/js/common/a4Utils.js new file mode 100644 index 0000000..ef6a17d --- /dev/null +++ b/static/js/common/a4Utils.js @@ -0,0 +1,37 @@ +"use strict"; +define(function (require, exports, module) { + class A4Utils { + constructor() { + let dpi = this.GetDPI(); + let width_mm = 210; // A4纸宽度,单位:毫米 + let height_mm = 297; // A4纸高度,单位:毫米 + let width_px = this.MmToPixel(width_mm, dpi); + let height_px = this.MmToPixel(height_mm, dpi); + this.width = width_px; + this.height = height_px; + } + + /** + * A4纸 + */ + GetDPI() { + let tempDiv = document.createElement("div"); + tempDiv.style.width = "1in"; + tempDiv.style.visibility = "hidden"; + document.body.appendChild(tempDiv); + let dpi = tempDiv.offsetWidth; + document.body.removeChild(tempDiv); + return dpi; + } + + MmToPixel(mm, dpi) { + // 1 inch = 25.4 mm + let inches = mm / 25.4; + let pixels = inches * dpi; + return Math.round(pixels); + } + } + + + module.exports = new A4Utils(); +}) \ No newline at end of file diff --git a/static/js/common/ctx.js b/static/js/common/ctx.js new file mode 100644 index 0000000..91d1ef3 --- /dev/null +++ b/static/js/common/ctx.js @@ -0,0 +1,139 @@ +"use strict"; +define(function (require, exports, module) { + console.log(("import ctx")) + + class MyCtx { + #MyRoot = null; + + constructor() { + console.log(("ctx init")); + + //可以修改的 + let editFrontSize = localStorage.getItem('editFrontSize'); + if (editFrontSize !== undefined && editFrontSize !== null) { + this.editFrontSize = editFrontSize; + } else { + this.editFrontSize = 14; + } + + this.usn = "syjSyj"; + this.docType = 0; + + // 获取 User-Agent 字符串 + const userAgent = window.navigator.userAgent; + // 判断是否是手机 + this.isMobile = /mobi|android|iphone|ipad|ipod/i.test(userAgent.toLocaleLowerCase()) || this.getScreenWidth() < 768; + this.isIOS = /iphone|ipad|ipod/i.test(userAgent.toLocaleLowerCase()) || this.getScreenWidth() < 768; + this.isAndroid = /android/i.test(userAgent.toLocaleLowerCase()) || this.getScreenWidth() < 768; + // 判断是否是平板电脑 + this.isTablet = /tablet/i.test(userAgent.toLocaleLowerCase()) || (this.getScreenWidth() >= 768 && this.getScreenWidth() < 1024); + + //屏幕宽高 + this.screenWidth = 0; + this.screenHeight = 0; + + //默认a4 纸 + const a4Utils = require('./a4Utils'); + this.designWith = a4Utils.width; + + //h5 this.MyRoot + //文档map + this.doc = new Map(); + //行号 + this.rowNo = 0; + //是否开始输入中文 + this.inCompositionEvent = false; + + //最近一次操作 + this.latestOpDoc = null; + + + //初始化 + } + + MyRoot() { + if (this.#MyRoot === null) { + this.#MyRoot = document.getElementById("yxl_note"); + } + return this.#MyRoot + } + + getMapItem(orderNo) { + return this.docMap.get(orderNo); + } + + incrementNumThenReturn() { + return this.rowNo++; + } + + getScreenWidth() { + return window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; + } + + getScreenHeight() { + return window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; + } + + + /** + * 新增一个元素 + * @param newParagraph + */ + addNewParagraph(newParagraph) { + //docRoot + this.MyRoot.appendChild(newParagraph); + + //mapRoot + let myP = new MyDocItem(newParagraph); + let curOrder = myP.parseOrder(); + let uuid = myP.parseUuid(); + this.doc.set(curOrder, new MyMapItem(uuid)) + + //收起选区到一个点,光标落在一个可编辑元素上 + window.myEdit.utils.GetSelection().setPosition(newParagraph, 0); + } + + /** + * 同步某一行数据到对应的 map节点 + * @param docP + * @constructor + */ + SyncMapItemChildrenStyle(docP) { + //子元素为空不处理 + let items = docP.childNodes; + if (items.length <= 0) { + return + } + + //构造参数 + let curMyP = new MyDocItem(docP); + let mapItem = window.myEdit.ctx.getMapItem(curMyP.parseOrder()); + + //清空重置 + // console.log(mapItem); + mapItem.getStyle().setChildrenStyleMapNull(); + //遍历 + for (let i = 0; i < items.length; i++) { + let curItem = items[i]; + let tmpClassList = curItem.classList; + if (tmpClassList != null && tmpClassList.length > 0) { + mapItem.getStyle().setChildrenStyle(i, tmpClassList); + } + } + + // console.log("sync docP : ", docP, " children: ", docP.children, " childrenMap: ", mapItem.getStyle().getChildrenStyleMap()) + } + + /** + * + */ + showTestText() { + + } + + } + + + // 初始化一次 + module.exports = new MyCtx(); +}) \ No newline at end of file diff --git a/static/js/common/demo.js b/static/js/common/demo.js new file mode 100644 index 0000000..3b14bfc --- /dev/null +++ b/static/js/common/demo.js @@ -0,0 +1,19 @@ +"use strict"; +define(function (require, exports, module) { + console.log(("import common")) + + class Demo { + constructor() { + console.log(("init")) + } + + hello() { + console.log("hello") + } + + } + + + module.exports = Demo; + // module.exports = new Utils(); +}) \ No newline at end of file diff --git a/static/js/common/doc.js b/static/js/common/doc.js new file mode 100644 index 0000000..41ee194 --- /dev/null +++ b/static/js/common/doc.js @@ -0,0 +1,41 @@ +"use strict"; +define(function (require, exports, module) { + console.log(("import common")) + + class Doc { + #docType; + #docId; + #content; + + constructor(docType, docId, title) { + this.#docType = docType; + this.#docId = docId; + this.title = title; + this.#content = new Map(); + } + + getDocType() { + return this.#docType; + } + + getDocId() { + return this.#docId; + } + + getContent() { + return this.#content; + } + + getNode(rowNo) { + return this.#content.get(rowNo.toString()); + } + + setNode(rowNo, node) { + this.#content.set(rowNo.toString(), node); + } + + } + + + module.exports = Doc; +}) \ No newline at end of file diff --git a/static/js/common/h5_newParagraph.js b/static/js/common/h5_newParagraph.js new file mode 100644 index 0000000..bc5f0df --- /dev/null +++ b/static/js/common/h5_newParagraph.js @@ -0,0 +1,13 @@ +"use strict"; +/** + * 使用样式事件 + */ +define(function (require, exports, module) { + + function handle(event) { + + } + + //导出 + exports.handle = handle; +}); \ No newline at end of file diff --git a/static/js/common/node.js b/static/js/common/node.js new file mode 100644 index 0000000..927e0c7 --- /dev/null +++ b/static/js/common/node.js @@ -0,0 +1,41 @@ +"use strict"; +define(function (require, exports, module) { + console.log(("import common")) + + class Node { + #id; + #source; + #innerStyleList; + + constructor(nodeId, start, end, source, type = "yxu_p") { + this.#id = nodeId; + this.#source = source; + this.type = type; + this.start = start; + this.end = end; + this.collpseChildren = false; + + //样式数组 [{"k1":"v1","k2":"k2"},{}] + this.#innerStyleList = []; + } + + getNodeId() { + return this.#id; + } + + getInnerStyleList() { + return this.#innerStyleList; + } + + updateInnerStyleList(styleList) { + this.#innerStyleList = styleList; + } + + updateSource(source) { + this.source = source; + } + } + + + module.exports = Node; +}) \ No newline at end of file diff --git a/static/js/common/utils.js b/static/js/common/utils.js new file mode 100644 index 0000000..bf9ff93 --- /dev/null +++ b/static/js/common/utils.js @@ -0,0 +1,160 @@ +"use strict"; +define(function (require, exports, module) { + return { + /** + * + */ + charSources: '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_'.split(''), + + + /** + * 十进制 转 63进制 + * @param val + * @constructor + */ + Parse10To63(val) { + if (val <= 10) { + return (val - 1) + ""; + } + + let sources = this.charSources; + let result = []; + let num = 0; + let mx = 63, baseMix = 63; + let tmp = 0; + while (val > 0) { + + let mod = val % mx; + + if (num === 0) { + tmp = mod - 1; + result.push(sources[tmp]) + val = val - mod; + } else { + tmp = mod / (mx / baseMix); + result.push(sources[tmp - 1]) + val = val - mod; + } + // 递增 + num++; + mx = mx * baseMix; + + //log + // console.log("mod: ", mod, " mx: ", mx, " val: ", val, " tmp: ", tmp) + } + + return result.reverse().join('') + }, + + /** + * 生成UUID + * @param usn + * @param docType + * @returns {string} + * @constructor + */ + Uuid(usn, docType = 0) { + let sources = this.charSources; + let radix = sources.length; + let uuid = []; + let myCrypto = window.crypto; + //1. docIdPrefix长度3 + let docIdPrefix = ""; + if (myCrypto) { + //生成一个 8位的数组,长度是 3 + let num = new Uint8Array(3); + //随机生成 + myCrypto.getRandomValues(num); + // console.log("Your lucky numbers:"); + for (let i = 0; i < 3; i++) { + uuid[i] = sources[num[i] >> 2] + } + // docId + uid + docType + ts + docIdPrefix = uuid.join(''); + } else { + // Compact form + for (let i = 0; i < 3; i++) uuid[i] = sources[0 | Math.random() * radix]; + docIdPrefix = uuid.join(''); + } + + + //2. 基于 2024-11-03 16:37:38 1730623058 最大长度可自增 + let curTs4Sec = Date.parse(new Date()) / 1000 - 1730623058; + let tsStr = this.Parse10To63(curTs4Sec); + // console.log("curTs4Sec : ", curTs4Sec, " tsStr: ", tsStr) + // docId(长度固定3) + uid(长度固定6) + docType(长度固定1) + ts(短期内1-6) + return docIdPrefix + docType + usn + tsStr; + }, + /** + * 阻止默认事件 + * @constructor + */ + ProhibitDefaultEvent(event) { + event.preventDefault() + event.returnValue = false + }, + + + /** + * 获取 触发事件的元素 + * @param event + * @constructor + */ + GetEventTarget(event) { + return event.target + }, + + + ParseEvent(e) { + return e || window.event //标准化事件处理 + }, + + + GetKeyCode(event) { + return event.keyCode || event.which || event.charCode + }, + + /** + * 当前选区。 兼容不同浏览器 + * @returns {Selection|*} + */ + GetSelection() { + return window.getSelection() || document.selection + }, + + /** + * 是否是数字 + * @param value + * @returns {boolean} + */ + IsNum(value) { + return !isNaN(parseFloat(value)) && isFinite(value) + }, + + /** + * 在节点node后面插入新节点newNode + * @method InsertAfter + * @param { Node } node 目标节点 + * @param { Node } newNode 新插入的节点, 该节点将置于目标节点之后 + * @return { Node } 新插入的节点 + */ + InsertAfter(node, newNode) { + return node.nextSibling + ? node.parentNode.insertBefore(newNode, node.nextSibling) + : node.parentNode.appendChild(newNode) + }, + + TriggerFocus(selector) { + const targetElement = document.querySelector(selector); + if (document.createEvent) { + const event = document.createEvent('HTMLEvents'); + event.initEvent('focus', true, false); + targetElement.dispatchEvent(event); + } else if (document.createEventObject) { + //兼容IE + targetElement.fireEvent('focus'); + } + } + + } +}); \ No newline at end of file diff --git a/static/js/event/MyEventListener.js b/static/js/event/MyEventListener.js new file mode 100644 index 0000000..204ef25 --- /dev/null +++ b/static/js/event/MyEventListener.js @@ -0,0 +1,162 @@ +"use strict"; +define(function (require, exports, module) { + /** + * 解决事件监听 this 问题,这里 转接一下 + */ + class MyEventListener { + + constructor() { + //resize + window.addEventListener('resize', this.RSizeListener, true); + window.addEventListener('pageshow', this.RSizeListener, true); + window.addEventListener('DOMContentLoaded', this.RSizeListener, true); + /** + * 窗口事件. + * js中的键盘事件只有三种:keydown、keyup、keypress。 + * 它们触发的顺序是:keydown -> keypress -> keyup。 + * 当按下一个键不放开,一般会重复地触发 keydown+keypress,直到放开后触发一个 keyup 事件。 + */ + window.addEventListener('keydown', this.KeydownListener, false); + //keyup + window.addEventListener('keyup', this.KeyUpListener, false); + // window.addEventListener('DOMsubtreeModified', function (e) { + // console.log("DOMsubtreeModified : ", e) + // }); + + let mutationHandle = require("./impl/MutationObserverImpl") + // 并将回调函数传给它 + let MutationObserver = window.MutationObserver || window.WebKitMutationObserver; + let observer = new MutationObserver(function (mutationList, observer) { + mutationHandle.handle(mutationList); + }); + + // 在 MutationObserver 实例上调用 `observe` 方法, + // 并将要观察的元素与选项传给此方法 + observer.observe(document.getElementById("yxl_note"), + { + // 当元素的属性变化时触发回调(默认为 false)。 + attributes: true, + //当目标节点的子节点被添加或删除时触发回调(默认为 false)。 + childList: true, + // 当设置为 true 时,监视目标节点及其所有后代节点的变化(默认为 false)。 + subtree: true, + // 当节点的文本内容变化时触发回调(默认为 false)。 + characterData: true, + //当属性变化时,记录变化前的属性值(默认为 false)。 + attributeOldValue: true, + // 当文本节点变化时,记录变化前的文本内容(默认为 false)。 + characterDataOldValue: true + }); + + + //这里监听鼠标按下事件 + document.getElementById("_style_utils").addEventListener("mousedown", this.Mousedown, false); + + //样式事件监听 + let styleList = document.getElementsByClassName("fixStyleInnerSpan"); + console.log("styleList : ", styleList); + if (styleList && styleList.length > 0) { + for (let i = 0; i < styleList.length; i++) { + console.log(styleList[i]); + styleList[i].addEventListener('click', this.ApplyStyleListener, false); + } + } + + + //+/- + document.getElementById("my_fontSize+").addEventListener("click", this.AdjustMyFontSize, true) + document.getElementById("my_fontSize-").addEventListener("click", this.AdjustMyFontSize, true) + document.getElementById("my_fontSize0").addEventListener("click", this.AdjustMyFontSize, true) + } + + AdjustMyFontSize(e) { + const handle = require('./impl/AdjustMyFontSizeEventImpl'); + handle.handle(e); + } + + Mousedown(e) { + const handle = require('./impl/MouseDownEventImpl'); + handle.handle(e); + } + + + /** + * 使用样式事件 + * @param e + * @constructor + */ + ApplyStyleListener(e) { + const handle = require('./impl/ApplyStyleEventImpl'); + handle.handle(e); + } + + /** + * + * @param {*} e + */ + KeydownListener(e) { + const keyDownHandle = require('./impl/KeyDownEventImpl'); + keyDownHandle.handle(e); + } + + /** + * + * @param e + * @constructor + */ + KeyUpListener(e) { + const keyUpHandle = require('./impl/KeyUpEventImpl'); + keyUpHandle.handle(e); + } + + /** + * 输入事件 + * @param e + * @constructor + */ + InputListener(e) { + const handle = require('./impl/InputEventImpl'); + handle.handle(e); + } + + /** + * 中文输入开始事件 + * @param e + * @constructor + */ + CompositionstartListener(e) { + const utils = require('../common/utils'); + const event = utils.ParseEvent(e); + // window.myEdit.biz.compositionstartHandle(event); + } + + /** + * 中文输入结束事件 + * @param e + * @constructor + */ + CompositionendListener(e) { + const utils = require('../common/utils'); + const event = utils.ParseEvent(e); + console.log("Compositionend : ", event) + // window.myEdit.biz.compositionendHandle(event); + } + + /** + * 尺寸变化事件 + * @param e + * @constructor + */ + RSizeListener(e) { + console.log("RSizeListener : ", e); + let handle = require("./impl/RSizeEventImpl"); + handle.handle(e); + } + + + } + + // 初始化一次 + module.exports = new MyEventListener(); +}); + diff --git a/static/js/event/impl/AdjustMyFontSizeEventImpl.js b/static/js/event/impl/AdjustMyFontSizeEventImpl.js new file mode 100644 index 0000000..f37a5d4 --- /dev/null +++ b/static/js/event/impl/AdjustMyFontSizeEventImpl.js @@ -0,0 +1,34 @@ +"use strict"; +/** + * 使用样式事件 + */ +define(function (require, exports, module) { + + function handle(e) { + const ctx = require("../../common/ctx"); + const utils = require("../../common/utils"); + + let event = utils.ParseEvent(e); + let curEl = utils.GetEventTarget(event); + let curId = curEl.getAttribute("id"); + if (curId === "my_fontSize0") { + localStorage.clear(); + location.reload(); + return + } else if (curId === "my_fontSize+") { + ctx.editFrontSize++; + } else { + ctx.editFrontSize--; + } + + //触发resize + let resizeImp = require("./RSizeEventImpl"); + resizeImp.refreshEditFrontSize(); + + //保存在本地 + localStorage.setItem('editFrontSize', ctx.editFrontSize); + } + + //导出 + exports.handle = handle; +}); \ No newline at end of file diff --git a/static/js/event/impl/ApplyStyleEventImpl.js b/static/js/event/impl/ApplyStyleEventImpl.js new file mode 100644 index 0000000..dc80a1d --- /dev/null +++ b/static/js/event/impl/ApplyStyleEventImpl.js @@ -0,0 +1,157 @@ +"use strict"; +/** + * 使用样式事件 + */ +define(function (require, exports, module) { + + function handle(event) { + let utils = require("../../common/utils"); + let curS = utils.GetSelection(); + + let curP = utils.GetEventTarget(event); + let styleK = curP.getAttribute("data-k"); + let styleV = curP.getAttribute("data-v"); + if (styleK === undefined || styleK === null) { + styleK = curP.closest("span").getAttribute("data-k"); + styleV = curP.closest("span").getAttribute("data-v"); + // console.log("closest: ", curP, curP.closest("span")) + } + + for (let i = 0; i < curS.rangeCount; i++) { + let curRange = curS.getRangeAt(i); + let curCommonEle = curRange.commonAncestorContainer; + let start = curRange.startOffset; + let end = curRange.endOffset; + if (start > end) { + let tmpS = start; + start = end; + end = tmpS; + } + if (start === end) { + continue + } + + // //一个元素节点,例如

。 + // let curComIsSpan = curCommonEle.nodeType === 1 && curCommonEle.nodeName === "SPAN"; + // let curComParentIsP = curCommonEle.parentNode.nodeType === 1 && curCommonEle.parentNode.nodeName === "P"; + // let curComParentIsDiv = curCommonEle.parentNode.nodeType === 1 && curCommonEle.parentNode.nodeName === "DIV"; + // let curComParentIsSpan = curCommonEle.parentNode.nodeType === 1 && (curCommonEle.parentNode.nodeName === 'SPAN"' || curCommonEle.parentNode.nodeName === 'SPAN'); + // console.log(" 当前选区信息 : ", curRange, + // "\ncurCommonEle: ", curCommonEle, + // "\ncurCommonEleParent: ", curCommonEle.parentNode, curCommonEle.parentNode.nodeType, curCommonEle.parentNode.nodeName, + // "\ncurCommonEleParentParent: ", curCommonEle.parentNode.parentNode, curCommonEle.parentNode.parentNode.nodeType, curCommonEle.parentNode.parentNode.nodeName, + // + // "\ncurComParentIsSpan: ", curComParentIsSpan, + // "\ncurComParentIsP : ", curComParentIsP, + // "\ncurComParentIsDiv", curComParentIsDiv, + // "\ncurComIsSpan", curComIsSpan, + // + // "\nstyleK: ", styleK, + // "\nstyleV: ", styleV, + // "\ntart: ", start, + // "\nend: ", end); + + let curSpanContent = curCommonEle; + if (curSpanContent.nodeName !== "SPAN" || curSpanContent.getAttribute("data-flag") !== "span_content") { + curSpanContent = curSpanContent.parentElement.closest("span[data-flag='span_content']"); + } + console.log("curSpanContent : ", curSpanContent, curCommonEle); + if (curSpanContent.childNodes.length <= 0) { + continue + } + let firstItem = curSpanContent.childNodes[0]; + console.log("curSpanContent : ", curSpanContent, curSpanContent.childNodes, firstItem.nodeName, firstItem.nodeType); + let isEmptyStyle = curSpanContent.childNodes.length === 1 && firstItem.nodeName === "#text" && firstItem.nodeType === 3; + if (isEmptyStyle) { + let copySpan = curSpanContent.cloneNode(); + copySpan.innerHTML = ""; + for (let j = 0; j < curSpanContent.innerText.length; j++) { + // console.log(curStartP.innerText.charAt(j)) + if (j >= start && j < end) { + let tmpSpan = document.createElement("span"); + tmpSpan.innerText = curSpanContent.innerText.charAt(j); + applySpanStyleKV(tmpSpan, styleK, styleV); + copySpan.append(tmpSpan); + } else { + let tmpSpan = document.createElement("span"); + tmpSpan.innerText = curSpanContent.innerText.charAt(j); + copySpan.append(tmpSpan); + } + } + + curSpanContent.innerHTML = copySpan.innerHTML; + + //光标保持 + let s = window.getSelection(); + if (s.rangeCount > 0) s.removeAllRanges(); + let newR = document.createRange(); + //重新获取元素 + let tmpP = curSpanContent; + let childrenSize = tmpP.childNodes.length; + console.log("debug007: ", tmpP, start, end, childrenSize) + newR.setStart(tmpP, start); + newR.setEnd(tmpP, end); + //区域 添加 到选区 + s.addRange(newR); + } else { + let total = 0, effectNum = 0; + for (let j = 0; j < curSpanContent.childNodes.length; j++) { + let tmpSpan = curSpanContent.childNodes[j]; + if (curS.containsNode(tmpSpan, true)) { + total++; + if (spanContainsStyleKV(tmpSpan, styleK, styleV)) { + console.dir(tmpSpan); + } else { + effectNum++; + applySpanStyleKV(tmpSpan, styleK, styleV); + } + } + } + + //如果没有设置任何一个 则取消 + if (effectNum === 0) { + for (let j = 0; j < curSpanContent.childNodes.length; j++) { + let tmpSpan = curSpanContent.childNodes[j]; + if (curS.containsNode(tmpSpan, true)) { + removeSpanStyleKV(tmpSpan, styleK, styleV); + } + } + } + } + } + } + + function removeSpanStyleKV(span, styleK, styleV) { + let kList = styleK.toString().split(","); + let vList = styleV.toString().split(","); + for (let i = 0; i < kList.length; i++) { + if (span.style.getPropertyValue(kList[0]) === vList[0]) { + span.style.removeProperty(kList[0]); + } + } + } + + function spanContainsStyleKV(span, styleK, styleV) { + let kList = styleK.toString().split(","); + let vList = styleV.toString().split(","); + let total = kList.length, match = 0; + for (let i = 0; i < kList.length; i++) { + if (span.style.getPropertyValue(kList[0]) === vList[0]) { + match++; + } + } + + return total === match; + } + + function applySpanStyleKV(span, styleK, styleV) { + let kList = styleK.toString().split(","); + let vList = styleV.toString().split(","); + for (let i = 0; i < kList.length; i++) { + span.style.setProperty(kList[i], vList[i]); + } + } + + //导出 + exports.handle = handle; +}); \ No newline at end of file diff --git a/static/js/event/impl/CancelEventImpl.js b/static/js/event/impl/CancelEventImpl.js new file mode 100644 index 0000000..f240e75 --- /dev/null +++ b/static/js/event/impl/CancelEventImpl.js @@ -0,0 +1,26 @@ +"use strict"; +/** + * 撤销事件 + */ +define(function (require, exports, module) { + + function handle(e) { + const utils = require('../../common/utils'); + const ctx = require('../../common/ctx'); + let event = utils.ParseEvent(e); + console.log('触发ctrl + Z 事件', event.target) + if (ctx.latestOpDoc !== undefined && ctx.latestOpDoc !== null) { + //恢复 + ctx.latestOpDoc.recovery(); + //测试展示 + ctx.showTestText() + //阻止事件 + utils.ProhibitDefaultEvent(event); + } + + ctx.latestOpDoc = null + } + + //导出 + exports.handle = handle; +}); \ No newline at end of file diff --git a/static/js/event/impl/CopyEventImpl.js b/static/js/event/impl/CopyEventImpl.js new file mode 100644 index 0000000..4b551f6 --- /dev/null +++ b/static/js/event/impl/CopyEventImpl.js @@ -0,0 +1,13 @@ +"use strict"; +/** + * 拷贝事件 + */ +define(function (require, exports, module) { + + function handle(event) { + + } + + //导出 + exports.handle = handle; +}); \ No newline at end of file diff --git a/static/js/event/impl/DelEventImpl.js b/static/js/event/impl/DelEventImpl.js new file mode 100644 index 0000000..a7f896c --- /dev/null +++ b/static/js/event/impl/DelEventImpl.js @@ -0,0 +1,83 @@ +"use strict"; + +/** + * 删除事件 + */ +define(function (require, exports, module) { + + function handle(event) { + const ctx = require("../../common/ctx"); + const utils = require("../../common/utils"); + const MyRecovery = require("../../common/MyRecovery"); + let curP = utils.GetEventTarget(event); + let cNo = parseInt(curP.getAttribute("id")); + + //维护最近一次编辑的内容 + if (ctx.latestOpDoc === undefined + || ctx.latestOpDoc === null + || ctx.latestOpDoc.getData().getAttribute("data-id") !== curP.getAttribute("data-id")) { + + //记录最近一次删除 for 撤销 + ctx.latestOpDoc = new MyRecovery(curP.cloneNode(true), function () { + let cNo = parseInt(this.data.getAttribute("id")) + console.log("恢复", this.data, cNo, " this: ", this) + if (cNo > 1) { + + utils.InsertAfter(this.data, document.getElementById((cNo - 1) + "")) + } else { + //添加元素到首位 todo_xxx + // ctx.MyRoot.insertBefore(this.data, ctx.MyRoot.children[0]) + ctx.MyRoot().insertBefore(this.data, ctx.MyRoot.children[0]); + } + + // 恢复该元素展示 + ctx.getMapItem(cNo).setHidden(false); + }) + } + + + //如果是第一行 + let previousSibling = curP.previousSibling + // console.log(curP, previousSibling === undefined, previousSibling.id === undefined) + if (previousSibling === undefined || previousSibling.id === undefined) { + //显示用户的输入内容 + ctx.showTestText(); + return + } + + + console.log('触发删除', curP.innerHTML, cNo) + let curS = utils.GetSelection(); + // console.log("当前内容: ", curP.innerHTML, " 当前选区 :", curS) + //处理前面没有内容,后面还有内容需要拼接到上层的场景 + if ((curS.isCollapsed && curS.anchorOffset === 0) || curP.innerHTML === '
') { + let curNodeRetainHtml = curP.innerHTML + //阻止事件传递 + utils.ProhibitDefaultEvent(event); + //设置该元素隐藏 + ctx.MyDocMap.get(cNo).setHidden(true) + //删除当前元素 + // curP.remove() + curP.innerHTML = "
" + let emptyRowNoList = ctx.getMapItem("emptyRowNoList"); + if (emptyRowNoList === undefined || emptyRowNoList === null) { + emptyRowNoList = []; + ctx.MyDocMap.set("emptyRowNoList", emptyRowNoList); + } + emptyRowNoList.push(cNo); + //拼接 + if (curNodeRetainHtml !== '
') { + previousSibling.innerHTML = previousSibling.innerHTML + curNodeRetainHtml + } + + //收起选区到一个点,光标落在一个可编辑元素上 + window.getSelection().setPosition(previousSibling, 1); + } + + //显示用户的输入内容 + ctx.showTestText(); + } + + //导出 + exports.handle = handle; +}); \ No newline at end of file diff --git a/static/js/event/impl/EmptyInputEventImpl.js b/static/js/event/impl/EmptyInputEventImpl.js new file mode 100644 index 0000000..5a88e72 --- /dev/null +++ b/static/js/event/impl/EmptyInputEventImpl.js @@ -0,0 +1,115 @@ +"use strict"; +/** + * 输入内容为空,如# /- /1. /等 触发事件 + */ +define(function (require, exports, module) { + + function handle(event) { + const utils = require('../../common/utils'); + const Node = require('../../common/node'); + let curP = utils.GetEventTarget(event); + let myDocItem = new Node(curP); + // let inputLength = curP.innerText.length + // console.log("emptyKeyWorkHandler :", curP, " _'", curP.innerHTML, "'_'", curP.innerText, "'_", + // "\neq1", curP.innerHTML.startsWith(" # "), + // "\neq2", curP.innerHTML.startsWith(" # "), + // "\neq3", curP.innerHTML.startsWith("# "), + // "\neq4", curP.innerHTML.startsWith("# "), + // + // "\neqV1", curP.innerText.startsWith(" # "), + // "\neqV2", curP.innerText.startsWith(" # "), + // "\neqV3", curP.innerText.startsWith("# "), + // "\neqV4", curP.innerText.startsWith("# "), + // + // ) + /** + * h1 ~ h6 + */ + if (curP.innerText.startsWith("#")) { + let curNo = myDocItem.parseOrder(); + let mapNode = ctx.MyDocMap.get(curNo); + if (curP.innerHTML.startsWith("######")) { + mapNode.getStyle().setNodeType("h6") + curP.innerHTML = curP.innerHTML.replace("######", "") + this.becomeAnotherElement(curP, "h6") + } else if (curP.innerHTML.startsWith("#####")) { + mapNode.getStyle().setNodeType("h5") + curP.innerHTML = curP.innerHTML.replace("#####", "") + this.becomeAnotherElement(curP, "h5") + } else if (curP.innerHTML.startsWith("####")) { + mapNode.getStyle().setNodeType("h4") + curP.innerHTML = curP.innerHTML.replace("####", "") + this.becomeAnotherElement(curP, "h4") + } else if (curP.innerHTML.startsWith("###")) { + mapNode.getStyle().setNodeType("h3") + curP.innerHTML = curP.innerHTML.replace("###", "") + this.becomeAnotherElement(curP, "h3") + } else if (curP.innerHTML.startsWith("##")) { + mapNode.getStyle().setNodeType("h2") + curP.innerHTML = curP.innerHTML.replace("##", "") + this.becomeAnotherElement(curP, "h2") + } else { + mapNode.getStyle().setNodeType("h1") + curP.innerHTML = curP.innerHTML.replace("#", "") + this.becomeAnotherElement(curP, "h1") + } + } + + /** + * 无序列表效果 + */ + if (curP.innerText.startsWith("-")) { + let curNo = myDocItem.parseOrder(); + let mapNode = ctx.getMapItem(curNo); + mapNode.getStyle().setPreStyle("ul", true) + + //clean + let historyContent = curP.innerHTML.replace("-", ""); + mapNode.setSource(curP.innerText) + + //根据上一层级元素动态选择 todo + curP.setAttribute("style", "padding-left: 1rem;") + //新增元素 + let newParagraph = document.createElement("span"); + newParagraph.setAttribute("contenteditable", "false"); + //∙ vs ∘ + newParagraph.innerHTML = "∙  " + curP.innerHTML = "" + curP.append(newParagraph); + curP.innerHTML = curP.innerHTML + historyContent + + //收起选区到一个点,光标落在一个可编辑元素上 + utils.GetSelection().collapse(curP, true) + } + + /** + * 有序列表效果 + */ + let preContent = curP.innerText.split("\.")[0] + if (window.myEdit.utils.IsNum(preContent)) { + let curNo = myDocItem.parseOrder(); + let mapNode = ctx.MyDocMap.get(curNo); + mapNode.getStyle().setPreStyle("ol", preContent) + + //clean + let historyContent = curP.innerHTML.replace(preContent + ".", ""); + mapNode.setSource(curP.innerText) + //todo + curP.setAttribute("style", "padding-left: 1rem;") + //新增元素 + let newParagraph = document.createElement("span"); + newParagraph.setAttribute("contenteditable", "false"); + newParagraph.innerHTML = preContent + ". " + curP.innerHTML = "" + curP.append(newParagraph); + curP.innerHTML = curP.innerHTML + historyContent + + //收起选区到一个点,光标落在一个可编辑元素上 + utils.GetSelection().collapse(curP, true) + } + + } + + //导出 + exports.handle = handle; +}); \ No newline at end of file diff --git a/static/js/event/impl/EnterEventImpl.js b/static/js/event/impl/EnterEventImpl.js new file mode 100644 index 0000000..4a053eb --- /dev/null +++ b/static/js/event/impl/EnterEventImpl.js @@ -0,0 +1,18 @@ +"use strict"; +/** + * 回车事件 + */ +define(function (require, exports, module) { + + function handle(e) { + const utils = require('../../common/utils'); + let event = utils.ParseEvent(e); + let curEl = utils.GetEventTarget(event); + + // console.log("Enter event", event, "\ncurEl: ", curEl) + + } + + //导出 + exports.handle = handle; +}); \ No newline at end of file diff --git a/static/js/event/impl/InputEventImpl.js b/static/js/event/impl/InputEventImpl.js new file mode 100644 index 0000000..08f6738 --- /dev/null +++ b/static/js/event/impl/InputEventImpl.js @@ -0,0 +1,34 @@ +"use strict"; + +/** + * 输入事件 + */ +define(function (require, exports, module) { + + function handle(e) { + const utils = require('../../common/utils'); + const event = utils.ParseEvent(e); + let curP = utils.GetEventTarget(e); + + console.log("input : ", event, + "\ntext: '", event.data + "'" + , "\ncurP: ", curP) + let testDiv = document.getElementById("testDevice") + testDiv.innerText = + "\ninput: " + event.data + " isEmpty: " + (event.data === " "); + + + //更新内容 + + // this.updateText(curP) + + //处理空行转换 + if (event.data === " ") { + let emptyHandle = require("./EmptyInputEventImpl"); + emptyHandle.handle(e); + } + } + + //导出 + exports.handle = handle; +}); \ No newline at end of file diff --git a/static/js/event/impl/KeyDownEventImpl.js b/static/js/event/impl/KeyDownEventImpl.js new file mode 100644 index 0000000..76795da --- /dev/null +++ b/static/js/event/impl/KeyDownEventImpl.js @@ -0,0 +1,42 @@ +"use strict"; +/** + * 鼠标 keyDown 事件 + */ +define(function (require, exports, module) { + + function handle(e) { + const utils = require('../../common/utils') + const event = utils.ParseEvent(e); + let curP = utils.GetEventTarget(e); + const keyCode = utils.GetKeyCode(event); + const keyCombination = event.ctrlKey + const metaKey = event.metaKey + + // console.log("keyDown : ", event, + // "\nevent.data: '", event.data + "'", + // "\nkeyCode: '", keyCode + "'" + // , "\ncurP: ", curP); + + //支持全屏撤销 + if (metaKey && keyCode === 90) { + // const cancelHandle = require('./CancelEventImpl') + // cancelHandle.handle(e); + return; + } + + //回车事件,禁止处理。防止生成 div + if (keyCode === 13) { + // utils.ProhibitDefaultEvent(event); + } + + //在鼠标按下的时候删除,体验更好 + if (keyCode === 46 || keyCode === 8) { + // const delHandle = require('./DelEventImpl') + // delHandle.handle(e); + // return; + } + } + + //导出 + exports.handle = handle; +}); \ No newline at end of file diff --git a/static/js/event/impl/KeyUpEventImpl.js b/static/js/event/impl/KeyUpEventImpl.js new file mode 100644 index 0000000..470deee --- /dev/null +++ b/static/js/event/impl/KeyUpEventImpl.js @@ -0,0 +1,49 @@ +"use strict"; +/** + * 鼠标 keyUp 事件 + */ +define(function (require, exports, module) { + + function handle(e) { + const utils = require('../../common/utils') + const event = utils.ParseEvent(e); + // console.log("this: ", this, e, e.target, "\n event: ", event) + const keyCode = utils.GetKeyCode(event); + const keyCombination = event.ctrlKey + const metaKey = event.metaKey + + let curP = utils.GetEventTarget(e); + // console.log("键盘事件 ", event, keyCombination, metaKey, keyCode, "\ncurP: ", curP) + + + // ctrl + c 复制 + if (keyCombination && keyCode === 67) { + // 阻止默认事件 + // utils.ProhibitDefaultEvent(event); + // console.log('触发ctrl + c 事件', e.target) + } + + //撤销 + if (metaKey && keyCode === 90) { + // const cancelHandle = require('./CancelEventImpl') + // cancelHandle.handle(e); + return; + } + + //删除 + if (keyCode === 46 || keyCode === 8) { + //todo 什么也不处理 + return; + } + + //回车事件 + if (keyCode === 13 /* && currentNode === key.lastElementChild */) { + // const enterHandle = require('./EnterEventImpl') + // enterHandle.handle(e); + // return; + } + } + + //导出 + exports.handle = handle; +}); \ No newline at end of file diff --git a/static/js/event/impl/MouseDownEventImpl.js b/static/js/event/impl/MouseDownEventImpl.js new file mode 100644 index 0000000..7159398 --- /dev/null +++ b/static/js/event/impl/MouseDownEventImpl.js @@ -0,0 +1,33 @@ +"use strict"; +/** + * 使用样式事件 + */ +define(function (require, exports, module) { + + function handle(e) { + const utils = require('../../common/utils'); + const ctx = require('../../common/ctx'); + const event = utils.ParseEvent(e); + + + let curElement = utils.GetEventTarget(event); + let id = curElement.getAttribute("id"); + if (id !== "_style_utils") { + id = curElement.closest("#_style_utils").getAttribute("id"); + } + console.log("mousedown: ", event, + "\ncurElement:", curElement, + "\nid : ", id) + //这里监听鼠标按下事件 + // if (id === "_style_utils") { + // //阻止事件,for 应用 样式 + // utils.ProhibitDefaultEvent(event); + // } + //阻止事件,for 应用 样式 + utils.ProhibitDefaultEvent(event); + + } + + //导出 + exports.handle = handle; +}); \ No newline at end of file diff --git a/static/js/event/impl/MutationObserverImpl.js b/static/js/event/impl/MutationObserverImpl.js new file mode 100644 index 0000000..eb37d43 --- /dev/null +++ b/static/js/event/impl/MutationObserverImpl.js @@ -0,0 +1,93 @@ +"use strict"; +/** + * 使用样式事件 + */ +define(function (require, exports, module) { + + function handle(mutationList) { + for (let mutation of mutationList) { + + + switch (mutation.type) { + case "childList": + addNewP(mutation); + break; + case "characterData": + updateText(mutation); + break; + default: { + other(mutation); + } + } + } + } + + function other(mutation) { + console.log("mutation : ", mutation, + // 观察的变动类型(attributes、characterData或者childList)。 + "\ntype", mutation.type, + //发生变动的DOM节点。 + "\ntarget", mutation.target, + "\ntargetParent", mutation.target.parentElement, mutation.target.parentNode, + //新增的DOM节点。 + "\naddedNodes", mutation.addedNodes, + //删除的DOM节点。 + "\nremovedNodes", mutation.removedNodes, + //前一个同级节点,如果没有则返回null。 + "\npreviousSibling", mutation.previousSibling, + //下一个同级节点,如果没有则返回null。 + "\nnextSibling", mutation.nextSibling, + //发生变动的属性。如果设置了attributeFilter,则只返回预先指定的属性。 + "\nattributeName", mutation.attributeName, + //变动前的值。这个属性只对attribute和characterData变动有效,如果发生childList变动,则返回null。 + "\noldValue", mutation.oldValue); + } + + function addNewP(mutation) { + let target = mutation.target; + if (target.nodeName === "DIV" && mutation.previousSibling !== null) { + console.log( + "target: ", target, + "\nnodeType: ", target.nodeType, + "\nnodeName: ", target.nodeName, + "\ndata: ", target.value, + "\n next: ", mutation.previousSibling.nextSibling + ) + + let utils = require("../../common/utils"); + let ctx = require("../../common/ctx"); + let curP = mutation.previousSibling.nextSibling; + if (curP !== undefined && curP !== null) { + curP.id = utils.Uuid(ctx.usn, ctx.docType); + curP.setAttribute("data-order", ctx.incrementNumThenReturn()); + } + } + + } + + function updateText(mutation) { + let target = mutation.target; + if (target.nodeType === 3 && target.nodeName === "#text") { + // console.log( + // "target: ", target, + // "\nnodeType: ", target.nodeType, + // "\nnodeName: ", target.nodeName, + // "\ndata: ", target.value, + // "\nparentNode: ", target.parentNode, + // "\nparentNode_parentNode: ", target.parentNode.parentNode, + // ) + + // let curSpan = target.parentNode; + // let curP = target.parentNode.parentNode; + + + + + } else { + other(mutation); + } + } + + //导出 + exports.handle = handle; +}); \ No newline at end of file diff --git a/static/js/event/impl/PasteEventImpl.js b/static/js/event/impl/PasteEventImpl.js new file mode 100644 index 0000000..05ea9fe --- /dev/null +++ b/static/js/event/impl/PasteEventImpl.js @@ -0,0 +1,13 @@ +"use strict"; +/** + * 粘贴事件 + */ +define(function (require, exports, module) { + + function handle(event) { + + } + + //导出 + exports.handle = handle; +}); \ No newline at end of file diff --git a/static/js/event/impl/RSizeEventImpl.js b/static/js/event/impl/RSizeEventImpl.js new file mode 100644 index 0000000..031716d --- /dev/null +++ b/static/js/event/impl/RSizeEventImpl.js @@ -0,0 +1,103 @@ +"use strict"; +define(function (require, exports, module) { + + function handle(e) { + const ctx = require("../../common/ctx"); + let historyScreenW = ctx.screenWidth; + let curScreenW = ctx.getScreenWidth(); + if (historyScreenW === curScreenW) { + return + } + + //调整 + refreshEditFrontSize() + refreshRootFrontSize(); + + //更新 + ctx.screenWidth = ctx.getScreenWidth(); + ctx.screenHeight = ctx.getScreenHeight(); + } + + /** + * 刷新跟节点 front-size + * @constructor + */ + function refreshRootFrontSize() { + const ctx = require("../../common/ctx"); + let curDoc = document.documentElement;//当前文档的 root 元素 + let curClientW = ctx.getScreenWidth(); + if (!curClientW) { + return + } + + let designWidth = ctx.designWith; + //set 1rem = viewWidth/10 (支持响应式) + let nowFrontSize = ((curClientW / designWidth) / 10) + 'px'; + curDoc.style.fontSize = nowFrontSize; + console.log("curClientW :", curClientW, "designWidth: ", designWidth, "-> ", nowFrontSize); + let testDiv = document.getElementById("testDevice"); + testDiv.innerText += "\nnowFrontSize: " + nowFrontSize; + // testDiv.innerText = testDiv.innerText + + // // "\n navigator_userAgent :" + navigator.userAgent.toLocaleLowerCase() + + // "\n isMobile :" + /mobi|android|iphone|ipad|ipod/i.test(navigator.userAgent.toLocaleLowerCase()) + + // "\n isIOS :" + /iphone|ipad|ipod/.test(window.navigator.userAgent.toLocaleLowerCase()) + + // "\n isAndroid :" + /android/.test(window.navigator.userAgent.toLocaleLowerCase()) + + // "\n window.width :" + window.innerWidth + + // "\n curClientW :" + curClientW + + // " \n designWidth: " + designWidth + + // "\n 1rem = " + nowFrontSize; + + } + + + function refreshEditFrontSize() { + const ctx = require("../../common/ctx"); + let curClientW = ctx.getScreenWidth(); + if (!curClientW) { + return + } + + let dpr = window.devicePixelRatio || 1;//当前设置下 物理像素和虚拟像素的比值 + if (!dpr) { + //devicePixelRatio这个属性是可以获取到设备的dpr + let devicePixelRatio = win?.devicePixelRatio; + //判断dpr是否为整数 + let isRegularDpr = devicePixelRatio.toString().match(/^[1-9]\d*$/g) + if (isRegularDpr) { + // 对于是整数的dpr,对dpr进行操作 + if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) { + dpr = 3; + } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)) { + dpr = 2; + } else { + dpr = 1; + } + } else { + // 其他设备下,仍旧使用1倍的方案 + dpr = 1; + } + } + + let myEditFrontSize = document.getElementById("myEdit_main"); + // if (document.documentElement.clientWidth <= 720) { + // myEditFrontSize.style.fontSize = (window.myEdit.ctx.editFrontSize + 6) + 'px'; + // } else { + // myEditFrontSize.style.fontSize = window.myEdit.ctx.editFrontSize * dpr + 'px'; + // } + // myEditFrontSize.style.fontSize = window.myEdit.ctx.editFrontSize * dpr + 'px'; + if (ctx.isTablet) { + myEditFrontSize.style.fontSize = ctx.editFrontSize * dpr + 'px'; + } else { + myEditFrontSize.style.fontSize = ctx.editFrontSize + 'px'; + } + + // console.log("myEditFrontSize: ", myEditFrontSize.style.fontSize); + let testDiv = document.getElementById("testDevice"); + testDiv.innerText = "\ndpr: " + dpr + "\nmyEditFrontSize: " + myEditFrontSize.style.fontSize; + } + + + //导出 + exports.handle = handle; + exports.refreshEditFrontSize = refreshEditFrontSize; +}); \ No newline at end of file diff --git a/static/js/index.js b/static/js/index.js new file mode 100644 index 0000000..8a5fb78 --- /dev/null +++ b/static/js/index.js @@ -0,0 +1,22 @@ +"use strict"; +define(function (require) { + const ctx = require('./common/ctx'); + const eventListener = require('./event/MyEventListener') + const utils = require('./common/utils') + console.log("uuid1 -10 : ", utils.Uuid(ctx.usn)); + + + // 初始化第一个输入框 + let newParagraph = document.createElement("p"); + //内置span + let span = document.createElement("span"); + span.append(document.createElement("br")); + span.setAttribute("data-flag","span_content") + newParagraph.append(span); + //添加一行 + ctx.MyRoot().append(newParagraph); + //收起选区到一个点,光标落在一个可编辑元素上 + utils.GetSelection().setPosition(newParagraph, 0); + + +}) \ No newline at end of file diff --git a/static/js/init.go b/static/js/init.go index d02753a..5a5d496 100644 --- a/static/js/init.go +++ b/static/js/init.go @@ -3,63 +3,72 @@ package js import ( "embed" "io/fs" - "os" ) import _ "embed" -//go:embed */*/*.js +//go:embed *.js +var indexList embed.FS + +//go:embed */*.js var jsList embed.FS -//go:embed lib/main.js -var jsMain embed.FS +//go:embed event/impl/* +var eventImplJs embed.FS var jsMap = initJsMap() func initJsMap() map[string][]byte { var dataMap = make(map[string][]byte) + //index.js + btData, _ := indexList.ReadFile("index.js") + dataMap["index.js"] = btData - btys, _ := jsMain.ReadFile("lib/main.js") - dataMap["lib/main.js"] = btys - - list := initJsMapInner("lib/biz") + //eventImpl + list, err := eventImplJs.ReadDir("event/impl") + if err != nil { + panic(err) + return nil + } if list != nil && len(list) > 0 { for _, file := range list { //读取配置文件 - data, err := jsList.ReadFile("lib/biz/" + file.Name()) + data, err := eventImplJs.ReadFile("event/impl/" + file.Name()) if err == nil { - dataMap["lib/biz/"+file.Name()] = data + dataMap["event/impl/"+file.Name()] = data } } } - list = initJsMapInner("lib/common") + list = initJsMapInner("lib") if list != nil && len(list) > 0 { for _, file := range list { //读取配置文件 - data, err := jsList.ReadFile("lib/common/" + file.Name()) + data, err := jsList.ReadFile("lib/" + file.Name()) if err == nil { - dataMap["lib/common/"+file.Name()] = data + dataMap["lib/"+file.Name()] = data } } } - list = initJsMapInner("lib/event") + + list = initJsMapInner("common") if list != nil && len(list) > 0 { for _, file := range list { //读取配置文件 - data, err := jsList.ReadFile("lib/event/" + file.Name()) + data, err := jsList.ReadFile("common/" + file.Name()) if err == nil { - dataMap["lib/event/"+file.Name()] = data + dataMap["common/"+file.Name()] = data } } } - list = initJsMapInner("lib/model") + + list = initJsMapInner("event") if list != nil && len(list) > 0 { for _, file := range list { //读取配置文件 - data, err := jsList.ReadFile("lib/model/" + file.Name()) + data, err := jsList.ReadFile("event/" + file.Name()) if err == nil { - dataMap["lib/model/"+file.Name()] = data + dataMap["event/"+file.Name()] = data } } } @@ -70,7 +79,7 @@ func initJsMap() map[string][]byte { func initJsMapInner(path string) []fs.DirEntry { list, err := jsList.ReadDir(path) if err != nil { - os.Exit(-1) + panic(err) return nil } diff --git a/static/js/lib/biz/MyBiz.js b/static/js/lib.old/biz/MyBiz.js similarity index 100% rename from static/js/lib/biz/MyBiz.js rename to static/js/lib.old/biz/MyBiz.js diff --git a/static/js/lib/common/MyUtils.js b/static/js/lib.old/common/MyUtils.js similarity index 100% rename from static/js/lib/common/MyUtils.js rename to static/js/lib.old/common/MyUtils.js diff --git a/static/js/lib/event/MyEventListener.js b/static/js/lib.old/event/MyEventListener.js similarity index 100% rename from static/js/lib/event/MyEventListener.js rename to static/js/lib.old/event/MyEventListener.js diff --git a/static/js/lib/main.js b/static/js/lib.old/main.js similarity index 100% rename from static/js/lib/main.js rename to static/js/lib.old/main.js diff --git a/static/js/lib/model/InnerStyle.js b/static/js/lib.old/model/InnerStyle.js similarity index 100% rename from static/js/lib/model/InnerStyle.js rename to static/js/lib.old/model/InnerStyle.js diff --git a/static/js/lib/model/MyDocItem.js b/static/js/lib.old/model/MyDocItem.js similarity index 100% rename from static/js/lib/model/MyDocItem.js rename to static/js/lib.old/model/MyDocItem.js diff --git a/static/js/lib/model/MyKV.js b/static/js/lib.old/model/MyKV.js similarity index 100% rename from static/js/lib/model/MyKV.js rename to static/js/lib.old/model/MyKV.js diff --git a/static/js/lib/model/MyMapItem.js b/static/js/lib.old/model/MyMapItem.js similarity index 100% rename from static/js/lib/model/MyMapItem.js rename to static/js/lib.old/model/MyMapItem.js diff --git a/static/js/lib/model/MyRecovery.js b/static/js/lib.old/model/MyRecovery.js similarity index 100% rename from static/js/lib/model/MyRecovery.js rename to static/js/lib.old/model/MyRecovery.js diff --git a/static/js/lib/todolist b/static/js/lib.old/todolist similarity index 100% rename from static/js/lib/todolist rename to static/js/lib.old/todolist diff --git a/static/js/lib/sea.js b/static/js/lib/sea.js new file mode 100644 index 0000000..dd70294 --- /dev/null +++ b/static/js/lib/sea.js @@ -0,0 +1,2 @@ +/*! Sea.js 3.0.0 | seajs.org/LICENSE.md */ +!function(a,b){function c(a){return function(b){return{}.toString.call(b)=="[object "+a+"]"}}function d(){return A++}function e(a){return a.match(D)[0]}function f(a){for(a=a.replace(E,"/"),a=a.replace(G,"$1/");a.match(F);)a=a.replace(F,"/");return a}function g(a){var b=a.length-1,c=a.charCodeAt(b);return 35===c?a.substring(0,b):".js"===a.substring(b-2)||a.indexOf("?")>0||47===c?a:a+".js"}function h(a){var b=v.alias;return b&&x(b[a])?b[a]:a}function i(a){var b=v.paths,c;return b&&(c=a.match(H))&&x(b[c[1]])&&(a=b[c[1]]+c[2]),a}function j(a){var b=v.vars;return b&&a.indexOf("{")>-1&&(a=a.replace(I,function(a,c){return x(b[c])?b[c]:a})),a}function k(a){var b=v.map,c=a;if(b)for(var d=0,e=b.length;e>d;d++){var f=b[d];if(c=z(f)?f(a)||a:a.replace(f[0],f[1]),c!==a)break}return c}function l(a,b){var c,d=a.charCodeAt(0);if(J.test(a))c=a;else if(46===d)c=(b?e(b):v.cwd)+a;else if(47===d){var g=v.cwd.match(K);c=g?g[0]+a.substring(1):a}else c=v.base+a;return 0===c.indexOf("//")&&(c=location.protocol+c),f(c)}function m(a,b){if(!a)return"";a=h(a),a=i(a),a=h(a),a=j(a),a=h(a),a=g(a),a=h(a);var c=l(a,b);return c=h(c),c=k(c)}function n(a){return a.hasAttribute?a.src:a.getAttribute("src",4)}function o(a,b,c){var d;try{importScripts(a)}catch(e){d=e}b(d)}function p(a,b,c){var d=Y.createElement("script");if(c){var e=z(c)?c(a):c;e&&(d.charset=e)}q(d,b,a),d.async=!0,d.src=a,bb=d,ab?_.insertBefore(d,ab):_.appendChild(d),bb=null}function q(a,b,c){function d(c){a.onload=a.onerror=a.onreadystatechange=null,v.debug||_.removeChild(a),a=null,b(c)}var e="onload"in a;e?(a.onload=d,a.onerror=function(){C("error",{uri:c,node:a}),d(!0)}):a.onreadystatechange=function(){/loaded|complete/.test(a.readyState)&&d()}}function r(){if(bb)return bb;if(cb&&"interactive"===cb.readyState)return cb;for(var a=_.getElementsByTagName("script"),b=a.length-1;b>=0;b--){var c=a[b];if("interactive"===c.readyState)return cb=c}}function s(a){function b(){l=a.charAt(k++)}function c(){return/\s/.test(l)}function d(){return'"'==l||"'"==l}function e(){var c=k,d=l,e=a.indexOf(d,c);if(-1==e)k=m;else if("\\"!=a.charAt(e-1))k=e+1;else for(;m>k;)if(b(),"\\"==l)k++;else if(l==d)break;o&&(r.push(a.slice(c,k-1)),o=0)}function f(){for(k--;m>k;)if(b(),"\\"==l)k++;else{if("/"==l)break;if("["==l)for(;m>k;)if(b(),"\\"==l)k++;else if("]"==l)break}}function g(){return/[a-z_$]/i.test(l)}function h(){var b=a.slice(k-1),c=/^[\w$]+/.exec(b)[0];p={"if":1,"for":1,"while":1,"with":1}[c],n={"break":1,"case":1,"continue":1,"debugger":1,"delete":1,"do":1,"else":1,"false":1,"if":1,"in":1,"instanceof":1,"return":1,"typeof":1,"void":1}[c],o=/^require\s*\(\s*(['"]).+?\1\s*\)/.test(b),o?(c=/^require\s*\(\s*['"]/.exec(b)[0],k+=c.length-2):k+=/^[\w$]+(?:\s*\.\s*[\w$]+)*/.exec(b)[0].length-1}function i(){return/\d/.test(l)||"."==l&&/\d/.test(a.charAt(k))}function j(){var b=a.slice(k-1),c;c="."==l?/^\.\d+(?:E[+-]?\d*)?\s*/i.exec(b)[0]:/^0x[\da-f]*/i.test(b)?/^0x[\da-f]*\s*/i.exec(b)[0]:/^\d+\.?\d*(?:E[+-]?\d*)?\s*/i.exec(b)[0],k+=c.length-1,n=0}if(-1==a.indexOf("require"))return[];for(var k=0,l,m=a.length,n=1,o=0,p=0,q=[],r=[];m>k;)b(),c()||(d()?(e(),n=1):"/"==l?(b(),"/"==l?(k=a.indexOf("\n",k),-1==k&&(k=a.length)):"*"==l?(k=a.indexOf("*/",k),-1==k?k=m:k+=2):n?(f(),n=0):(k--,n=1)):g()?h():i()?j():"("==l?(q.push(p),n=1):")"==l?n=q.pop():(n="]"!=l,o=0));return r}function t(a,b){this.uri=a,this.dependencies=b||[],this.deps={},this.status=0,this._entry=[]}if(!a.seajs){var u=a.seajs={version:"3.0.0"},v=u.data={},w=c("Object"),x=c("String"),y=Array.isArray||c("Array"),z=c("Function"),A=0,B=v.events={};u.on=function(a,b){var c=B[a]||(B[a]=[]);return c.push(b),u},u.off=function(a,b){if(!a&&!b)return B=v.events={},u;var c=B[a];if(c)if(b)for(var d=c.length-1;d>=0;d--)c[d]===b&&c.splice(d,1);else delete B[a];return u};var C=u.emit=function(a,b){var c=B[a];if(c){c=c.slice();for(var d=0,e=c.length;e>d;d++)c[d](b)}return u},D=/[^?#]*\//,E=/\/\.\//g,F=/\/[^/]+\/\.\.\//,G=/([^:/])\/+\//g,H=/^([^/:]+)(\/.+)$/,I=/{([^{]+)}/g,J=/^\/\/.|:\//,K=/^.*?\/\/.*?\//;u.resolve=m;var L="undefined"==typeof window&&"undefined"!=typeof importScripts&&z(importScripts),M=/^(about|blob):/,N,O,P=!location.href||M.test(location.href)?"":e(location.href);if(L){var Q;try{var R=Error();throw R}catch(S){Q=S.stack.split("\n")}Q.shift();for(var T,U=/.*?((?:http|https|file)(?::\/{2}[\w]+)(?:[\/|\.]?)(?:[^\s"]*)).*?/i,V=/(.*?):\d+:\d+\)?$/;Q.length>0;){var W=Q.shift();if(T=U.exec(W),null!=T)break}var X;if(null!=T)var X=V.exec(T[1])[1];O=X,N=e(X||P),""===P&&(P=N)}else{var Y=document,Z=Y.scripts,$=Y.getElementById("seajsnode")||Z[Z.length-1];O=n($),N=e(O||P)}if(L)u.request=o;else{var Y=document,_=Y.head||Y.getElementsByTagName("head")[0]||Y.documentElement,ab=_.getElementsByTagName("base")[0],bb;u.request=p}var cb,db=u.cache={},eb,fb={},gb={},hb={},ib=t.STATUS={FETCHING:1,SAVED:2,LOADING:3,LOADED:4,EXECUTING:5,EXECUTED:6,ERROR:7};t.prototype.resolve=function(){for(var a=this,b=a.dependencies,c=[],d=0,e=b.length;e>d;d++)c[d]=t.resolve(b[d],a.uri);return c},t.prototype.pass=function(){for(var a=this,b=a.dependencies.length,c=0;cf;f++){var g=a.deps[a.dependencies[f]];g.status0&&(d.remain+=e-1,a._entry.shift(),c--)}},t.prototype.load=function(){var a=this;if(!(a.status>=ib.LOADING)){a.status=ib.LOADING;var c=a.resolve();C("load",c);for(var d=0,e=c.length;e>d;d++)a.deps[a.dependencies[d]]=t.get(c[d]);if(a.pass(),a._entry.length)return a.onload(),b;var f={},g;for(d=0;e>d;d++)g=db[c[d]],g.statusb;b++){var d=a._entry[b];0===--d.remain&&d.callback()}delete a._entry},t.prototype.error=function(){var a=this;a.onload(),a.status=ib.ERROR},t.prototype.exec=function(){function a(b){var d=c.deps[b]||t.get(a.resolve(b));if(d.status==ib.ERROR)throw Error("module was broken: "+d.uri);return d.exec()}var c=this;if(c.status>=ib.EXECUTING)return c.exports;if(c.status=ib.EXECUTING,c._entry&&!c._entry.length&&delete c._entry,!c.hasOwnProperty("factory"))return c.non=!0,b;var e=c.uri;a.resolve=function(a){return t.resolve(a,e)},a.async=function(b,c){return t.use(b,c,e+"_async_"+d()),a};var f=c.factory,g=z(f)?f(a,c.exports={},c):f;return g===b&&(g=c.exports),delete c.factory,c.exports=g,c.status=ib.EXECUTED,C("exec",c),c.exports},t.prototype.fetch=function(a){function c(){u.request(g.requestUri,g.onRequest,g.charset)}function d(a){delete fb[h],gb[h]=!0,eb&&(t.save(f,eb),eb=null);var b,c=hb[h];for(delete hb[h];b=c.shift();)a===!0?b.error():b.load()}var e=this,f=e.uri;e.status=ib.FETCHING;var g={uri:f};C("fetch",g);var h=g.requestUri||f;return!h||gb.hasOwnProperty(h)?(e.load(),b):fb.hasOwnProperty(h)?(hb[h].push(e),b):(fb[h]=!0,hb[h]=[e],C("request",g={uri:f,requestUri:h,onRequest:d,charset:z(v.charset)?v.charset(h)||"utf-8":v.charset}),g.requested||(a?a[g.requestUri]=c:c()),b)},t.resolve=function(a,b){var c={id:a,refUri:b};return C("resolve",c),c.uri||u.resolve(c.id,b)},t.define=function(a,c,d){var e=arguments.length;1===e?(d=a,a=b):2===e&&(d=c,y(a)?(c=a,a=b):c=b),!y(c)&&z(d)&&(c=b===s?[]:s(""+d));var f={id:a,uri:t.resolve(a),deps:c,factory:d};if(!L&&!f.uri&&Y.attachEvent&&b!==r){var g=r();g&&(f.uri=g.src)}C("define",f),f.uri?t.save(f.uri,f):eb=f},t.save=function(a,b){var c=t.get(a);c.statusf;f++)b[f]=db[d[f]].exec();c&&c.apply(a,b),delete e.callback,delete e.history,delete e.remain,delete e._entry},e.load()},u.use=function(a,b){return t.use(a,b,v.cwd+"_use_"+d()),u},t.define.cmd={},a.define=t.define,u.Module=t,v.fetchedList=gb,v.cid=d,u.require=function(a){var b=t.get(t.resolve(a));return b.status 📒 - + content="width=device-width, height=device-height,initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"> + - + + + + -
- -
-
-
-
-
- - + +
+
测试
+
+
+ + + + + +
+
+
+
+
+
+
+ + + +
+
+ + + +
+
+
+
+ +
+
+ +
- + + d="m3.414 7.086-.707.707a1 1 0 0 0 0 1.414l7.778 7.778a2 2 0 0 0 2.829 0l7.778-7.778a1 1 0 0 0 0-1.414l-.707-.707a1 1 0 0 0-1.415 0l-7.07 7.07-7.072-7.07a1 1 0 0 0-1.414 0Z" + fill="currentColor">
-
-
-
-
- -
+
+ + + - -
-
- - + + + + - + + + + + + + + + + + +
-
-
-
- - - +
+
+ + + + + + + + + + + - - - + + + + + + + + + + + + + + - - - - - - - - - - -
- -
-
+
+
+
- + + d="M4.2 10.4A1.19 1.19 0 013 9.2 1.19 1.19 0 014.2 8c.23 0 .43.06.6.17.2.1.33.24.44.43.11.18.17.38.17.6 0 .23-.06.43-.17.6-.1.2-.25.34-.43.45-.18.1-.38.16-.6.16zm4.72 0a1.19 1.19 0 01-1.2-1.2A1.19 1.19 0 018.92 8c.22 0 .42.06.6.17.19.1.33.24.44.43.1.18.16.38.16.6a1.22 1.22 0 01-.6 1.04c-.18.11-.38.17-.6.17zm4.72 0a1.19 1.19 0 01-1.2-1.2 1.19 1.19 0 011.2-1.2c.22 0 .42.06.6.17.18.1.33.24.44.43.11.18.16.38.16.6 0 .23-.05.43-.16.6a1.18 1.18 0 01-1.04.6z" + fill="#535353"> +
+
- - - -
-
-
+ -
- -

- 测试编辑 -

- -
-
-
+
+ +

+ 测试编辑 +

+ +
+
+
-
+
-
-
+
+
+
-

- - -

- - \ No newline at end of file diff --git a/static/yanxuelu.html.old b/static/yanxuelu.html.old new file mode 100644 index 0000000..475185c --- /dev/null +++ b/static/yanxuelu.html.old @@ -0,0 +1,155 @@ + + + + + + + + 📒 + + + + + + + + + +
+ +
+
+
+
+
+ + + +
+
+ + + +
+
+
+
+ +
+
+ + + +
+
+ + + +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + +
+ + + + +
+
+
+ +
+ +

+ 测试编辑 +

+ +
+
+
+ +
+ +
+
+ +

+ + +

+ + + + + \ No newline at end of file