@jx3box/jx3box-editor 3.2.2 → 3.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,6 +2,7 @@
2
2
  // 旧主题色
3
3
  // @primary:#0366d6;
4
4
  @primary:#4f46e5;
5
+ @v4yellow: #f5bd1e;
5
6
 
6
7
  // 文字颜色(黑底、白底)
7
8
  @color: #3d454d;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jx3box/jx3box-editor",
3
- "version": "3.2.2",
3
+ "version": "3.2.3",
4
4
  "description": "JX3BOX Article & Editor",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -15,11 +15,11 @@
15
15
  "dependencies": {
16
16
  "@element-plus/icons-vue": "^2.0.10",
17
17
  "@imengyu/vue3-context-menu": "^1.5.4",
18
- "@jx3box/jx3box-common": "^9.2.4",
19
- "@jx3box/jx3box-data": "^3.9.5",
20
- "@jx3box/jx3box-emotion": "^1.3.1",
21
- "@jx3box/jx3box-macro": "^1.0.4",
22
- "@jx3box/jx3box-talent": "^1.3.14",
18
+ "@jx3box/jx3box-common": "^9.2.1",
19
+ "@jx3box/jx3box-data": "^3.9.4",
20
+ "@jx3box/jx3box-emotion": "^1.3.0",
21
+ "@jx3box/jx3box-macro": "^1.0.3",
22
+ "@jx3box/jx3box-talent": "^1.3.13",
23
23
  "@tinymce/tinymce-vue": "^5.0.0",
24
24
  "axios": "^0.19.2",
25
25
  "cheerio": "^1.1.2",
@@ -89,6 +89,6 @@
89
89
  },
90
90
  "repository": {
91
91
  "type": "git",
92
- "url": "git+https://github.com/iruxu/iruxu-editor.git"
92
+ "url": "git+https://github.com/JX3BOX/jx3box-editor.git"
93
93
  }
94
94
  }
package/src/Article.vue CHANGED
@@ -59,38 +59,38 @@ import Vditor from "vditor";
59
59
  import "github-markdown-css/github-markdown-light.css";
60
60
 
61
61
  // XSS
62
- import execFilterXSS from "./assets/js/xss.js";
62
+ import execFilterXSS from "./assets/js/xss";
63
63
 
64
64
  // 基本文本
65
- import execLazyload from "./assets/js/img.js";
66
- import execFilterIframe from "./assets/js/iframe.js";
67
- import execFilterLink from "./assets/js/a.js";
68
- import execSplitPages from "./assets/js/nextpage.js";
69
- import normalizeMarkdownForVditor from "./assets/js/normalizeMarkdownForVditor.js";
65
+ import execLazyload from "./assets/js/img";
66
+ import execFilterIframe from "./assets/js/iframe";
67
+ import execFilterLink from "./assets/js/a";
68
+ import execSplitPages from "./assets/js/nextpage";
69
+ import normalizeMarkdownForVditor from "./assets/js/normalizeMarkdownForVditor";
70
70
 
71
71
  // 扩展文本
72
- import renderFoldBlock from "./assets/js/fold.js";
73
- import renderDirectory from "./assets/js/directory.js";
74
- import renderKatex from "./assets/js/katex.js";
75
- import renderCode from "./assets/js/code.js";
76
- import renderImgPreview from "./assets/js/renderImgPreview.js";
72
+ import renderFoldBlock from "./assets/js/fold";
73
+ import renderDirectory from "./assets/js/directory";
74
+ import renderKatex from "./assets/js/katex";
75
+ import renderCode from "./assets/js/code";
76
+ import renderImgPreview from "./assets/js/renderImgPreview";
77
77
 
78
78
  // 魔盒
79
- import renderMacro from "./assets/js/macro.js";
80
- import renderTalent from "./assets/js/qixue.js";
81
- import renderTalent2 from "./assets/js/talent2.js";
82
- import renderPzIframe from "./assets/js/pz_iframe.js";
83
- import renderCombo from "./assets/js/combo.js";
84
- import renderAudio from "./assets/js/audio.js";
85
- import Author from "./components/Author.vue";
79
+ import renderMacro from "./assets/js/macro";
80
+ import renderTalent from "./assets/js/qixue";
81
+ import renderTalent2 from "./assets/js/talent2";
82
+ import renderPzIframe from "./assets/js/pz_iframe";
83
+ import renderCombo from "./assets/js/combo";
84
+ import renderAudio from "./assets/js/audio";
85
+ import Author from "./components/Author";
86
86
  import PostAuthor from "./components/PostAuthor.vue";
87
87
 
88
88
  // 剑三
89
- import Item from "./Item.vue";
90
- import Buff from "./Buff.vue";
91
- import Skill from "./Skill.vue";
92
- import Npc from "./Npc.vue";
93
- import renderJx3Element from "./assets/js/jx3_element.js";
89
+ import Item from "./Item";
90
+ import Buff from "./Buff";
91
+ import Skill from "./Skill";
92
+ import Npc from "./Npc";
93
+ import renderJx3Element from "./assets/js/jx3_element";
94
94
 
95
95
  export default {
96
96
  name: "Article",
@@ -27,27 +27,27 @@
27
27
  import markdownRender from "@jx3box/markdown/src/render.vue";
28
28
 
29
29
  // 基本文本
30
- import execLazyload from "./assets/js/img.js";
31
- import execFilterIframe from "./assets/js/iframe.js";
32
- import execFilterLink from "./assets/js/a.js";
33
- import execFilterXSS from "./assets/js/script.js";
30
+ import execLazyload from "./assets/js/img";
31
+ import execFilterIframe from "./assets/js/iframe";
32
+ import execFilterLink from "./assets/js/a";
33
+ import execFilterXSS from "./assets/js/script";
34
34
 
35
35
  // 扩展文本
36
- import renderDirectory from "./assets/js/directory.js";
37
- import renderMacro from "./assets/js/macro.js";
38
- import renderTalent from "./assets/js/qixue.js";
39
- import renderTalent2 from "./assets/js/talent2.js";
40
- import renderKatexAll from "./assets/js/katex.js";
41
- import renderCode from "./assets/js/code.js";
36
+ import renderDirectory from "./assets/js/directory";
37
+ import renderMacro from "./assets/js/macro";
38
+ import renderTalent from "./assets/js/qixue";
39
+ import renderTalent2 from "./assets/js/talent2";
40
+ import { renderKatexAll } from "./assets/js/katex";
41
+ import renderCode from "./assets/js/code";
42
42
 
43
43
  // 剑三
44
- import Item from "./Item.vue";
45
- import Buff from "./Buff.vue";
46
- import Skill from "./Skill.vue";
47
- import Npc from "./Npc.vue";
48
- import renderJx3Element from "./assets/js/jx3_element.js";
49
- import renderImgPreview from "./assets/js/renderImgPreview.js";
50
- import renderAudio from "./assets/js/audio.js";
44
+ import Item from "./Item";
45
+ import Buff from "./Buff";
46
+ import Skill from "./Skill";
47
+ import Npc from "./Npc";
48
+ import renderJx3Element from "./assets/js/jx3_element";
49
+ import renderImgPreview from "./assets/js/renderImgPreview";
50
+ import renderAudio from "./assets/js/audio";
51
51
 
52
52
  import { xssOptions } from "./assets/data/markdown_whitelist.json";
53
53
 
@@ -190,9 +190,9 @@
190
190
  </template>
191
191
 
192
192
  <script>
193
- import { loadStat } from "./service/database.js";
194
- import { loadAuthors, loadEmotions, getLetterPaper } from "./service/cms.js";
195
- import { getUserInfo } from "./service/author.js";
193
+ import { loadStat } from "./service/database";
194
+ import { loadAuthors, loadEmotions, getLetterPaper } from "./service/cms";
195
+ import { getUserInfo } from "./service/author";
196
196
  import JX3BOX from "@jx3box/jx3box-common/data/jx3box.json";
197
197
  import { getLink, showAvatar, resolveImagePath } from "@jx3box/jx3box-common/js/utils";
198
198
  import User from "@jx3box/jx3box-common/js/user";
package/src/GameText.vue CHANGED
@@ -11,7 +11,7 @@
11
11
 
12
12
  <script>
13
13
  import { extractTextContent, getLink, iconLink } from "@jx3box/jx3box-common/js/utils";
14
- import { getResource as getResourceFromNode } from "./service/resource.js";
14
+ import { getResource as getResourceFromNode } from "./service/resource";
15
15
  import { escape } from "lodash";
16
16
  import gameFonts from "./assets/data/game_font.json";
17
17
 
@@ -38,7 +38,7 @@
38
38
  </template>
39
39
 
40
40
  <script>
41
- import Item from "./Item.vue";
41
+ import Item from "./Item";
42
42
  import icon_url from "./assets/js/item/icon_url.js";
43
43
  import item_color from "./assets/js/item/color.js";
44
44
  import item_border from "./assets/js/item/border.js";
package/src/Markdown.vue CHANGED
@@ -35,7 +35,7 @@ import {
35
35
  import Vditor from "vditor";
36
36
  import "vditor/dist/index.css";
37
37
  import "github-markdown-css/github-markdown-light.css";
38
- import normalizeMarkdownForVditor from "./assets/js/normalizeMarkdownForVditor.js";
38
+ import normalizeMarkdownForVditor from "./assets/js/normalizeMarkdownForVditor";
39
39
 
40
40
  const { __cms } = JX3BOX;
41
41
  const UPLOAD_API = `${__cms}api/cms/upload`;
package/src/Resource.vue CHANGED
@@ -286,7 +286,7 @@
286
286
 
287
287
  <script>
288
288
  import { ArrowDown, Histogram } from "@element-plus/icons-vue";
289
- import { loadResource, loadStat, getIcons } from "./service/database.js";
289
+ import { loadResource, loadStat, getIcons } from "./service/database";
290
290
  import JX3BOX from "@jx3box/jx3box-common/data/jx3box.json";
291
291
  import detach_types from "./assets/data/detach_type.json";
292
292
  import { iconLink, getLink as resolveLink } from "@jx3box/jx3box-common/js/utils";
package/src/Tinymce.vue CHANGED
@@ -42,9 +42,9 @@ const { __cdn, __imgPath, __cms } = JX3BOX;
42
42
  // 开发环境走 devServer proxy,避免跨域导致粘贴图片上传“看起来没反应”
43
43
  const apiUrl = process.env.NODE_ENV === "development" ? "/api/cms/upload/tinymce" : __cms + "api/cms/upload/tinymce";
44
44
 
45
- import Upload from "./Upload.vue";
46
- import Resource from "./Resource.vue";
47
- import BoxResource from "./BoxResource.vue";
45
+ import Upload from "./Upload";
46
+ import Resource from "./Resource";
47
+ import BoxResource from "./BoxResource";
48
48
  import Emotion from "@jx3box/jx3box-emotion/src/Emotion.vue";
49
49
 
50
50
  import axios from "axios";
package/src/Upload.vue CHANGED
@@ -88,7 +88,7 @@ import axios from "axios";
88
88
  import { Delete, Plus, UploadFilled, ZoomIn } from "@element-plus/icons-vue";
89
89
  import JX3BOX from "@jx3box/jx3box-common/data/jx3box.json";
90
90
  import allow_types from "@jx3box/jx3box-common/data/conf";
91
- import { showImgPreview } from "./assets/js/renderImgPreview.js";
91
+ import { showImgPreview } from "./assets/js/renderImgPreview";
92
92
  const { __cms } = JX3BOX;
93
93
  const API = __cms + "api/cms/upload";
94
94
  const imgtypes = ["jpg", "png", "gif", "bmp", "webp", "jpeg", "svg"];
@@ -32,12 +32,11 @@
32
32
 
33
33
  h4 {
34
34
  font-size: 15px;
35
- padding: 8px 10px;
35
+ padding: 8px 10px 8px 20px;
36
36
 
37
37
  background-color: #fafbfc;
38
38
  border-radius: 6px;
39
- border-left:4px solid @primary;
40
-
39
+ // border-left:4px solid @primary;
41
40
 
42
41
  position: relative;
43
42
  overflow: hidden;
@@ -45,17 +44,39 @@
45
44
  // border: 1px solid @primary;
46
45
  &::before {
47
46
  content: "";
48
- font-size: 20px;
49
47
  display: block;
50
48
  position: absolute;
51
- width: 80px;
52
- height: 3px;
53
- top: 0;
54
- left: 15px;
55
- // background-color: @primary;
49
+ width: 5px;
50
+ height: 60%;
51
+ top: 50%;
52
+ transform: translateY(-50%);
53
+ left: 10px;
54
+ background-color: @primary;
55
+ border-radius: 10px;
56
+ transition: all 0.2s ease;
56
57
  // border-bottom-right-radius: 20px;
57
58
  // border-bottom-left-radius: 20px;
58
59
  }
60
+ // &::after {
61
+ // content: "";
62
+ // display: block;
63
+ // position: absolute;
64
+ // width: 5px;
65
+ // height: 60%;
66
+ // top: 50%;
67
+ // transform: translateY(-50%);
68
+ // left: 10px;
69
+ // background-color: @v4yellow;
70
+ // border-radius: 10px;
71
+ // z-index: 2;
72
+ // display: none;
73
+ // }
74
+
75
+ &:hover {
76
+ &::before {
77
+ background-color: @v4yellow;
78
+ }
79
+ }
59
80
  }
60
81
 
61
82
  h5 {
@@ -74,6 +95,11 @@
74
95
  bottom: -1px;
75
96
  left: 0;
76
97
  }
98
+ &:hover{
99
+ &::after {
100
+ background-color: @v4yellow;
101
+ }
102
+ }
77
103
  }
78
104
 
79
105
  h6 {
@@ -24,6 +24,7 @@
24
24
  max-width: 100%;
25
25
  overflow-x: auto;
26
26
  text-align: center;
27
+ justify-content: center;
27
28
 
28
29
  .el-pager{
29
30
  margin:0;
@@ -37,8 +37,3 @@
37
37
  display: block;
38
38
  }
39
39
  }
40
-
41
- .w-pz-iframe-wrap {
42
- width: 100%;
43
- overflow: auto;
44
- }
@@ -12,17 +12,17 @@
12
12
  line-height:2.2;
13
13
  color:@color;
14
14
 
15
- td,
16
- th {
15
+ td,th {
17
16
  padding: 6px 10px;
18
- }
19
- td {
20
17
  border: 1px solid #eee;
21
18
  }
22
19
  th {
23
20
  background-color: #fafbfc;
24
21
  font-weight: 500;
25
22
  }
23
+ tr{
24
+ background-color:#fff;
25
+ }
26
26
  tr:nth-child(2n + 1) {
27
27
  background-color: #fafbfc;
28
28
  }
@@ -3,216 +3,62 @@ import $ from "jquery";
3
3
  function renderItem(vm, selector = ".w-jx3-element") {
4
4
  let outer, inner;
5
5
  const pop_class = ".w-jx3-element-pop";
6
- const scopeEl = vm && vm.$el ? vm.$el : document;
7
- const $scope = $(scopeEl);
8
- const uid = vm && vm._uid ? vm._uid : "default";
9
- const ns = `.jx3boxElement_${uid}`;
10
- let lastTappedElement = null;
11
- const debugPop = false;
12
6
 
13
- const isMobile = () => {
14
- if (typeof window === "undefined") return false;
15
-
16
- const coarsePointer =
17
- typeof window.matchMedia === "function" &&
18
- window.matchMedia("(hover: none) and (pointer: coarse)").matches;
19
- const hasTouchEvent = "ontouchstart" in window;
20
- const mobileUA =
21
- typeof navigator !== "undefined" &&
22
- /Android|iPhone|iPad|iPod|Mobile/i.test(navigator.userAgent || "");
23
-
24
- return coarsePointer || (hasTouchEvent && mobileUA);
25
- };
26
-
27
- const cachedPop =
28
- vm &&
29
- vm.__jx3ElementPop &&
30
- vm.__jx3ElementPop.length &&
31
- document.documentElement.contains(vm.__jx3ElementPop[0])
32
- ? vm.__jx3ElementPop
33
- : null;
34
- const $pop = cachedPop || $scope.find(pop_class).first();
35
-
36
- if (!$pop.length) return;
37
- if (isMobile() && vm) {
38
- vm.__jx3ElementPop = $pop;
39
- if ($pop.parent()[0] !== document.body) {
40
- $pop.appendTo(document.body);
41
- }
42
- }
43
-
44
- const getCurrentTarget = (el, e) => {
45
- const $self = $(el).closest(selector);
46
- if ($self.length) return $self;
47
- return $(e.currentTarget || e.target).closest(selector);
48
- };
49
-
50
- const getDataTarget = ($target, e) => {
51
- const $eventTarget = $(e?.target);
52
- const $fromEvent = $eventTarget.closest("[data-type]");
53
- if ($fromEvent.length && $target.has($fromEvent).length) return $fromEvent;
54
- if ($target.attr("data-type")) return $target;
55
-
56
- return $target.find("[data-type]").first();
57
- };
58
-
59
- const getHrefTarget = ($target) => {
60
- if ($target.is("a[href]")) return $target;
61
- return $target.closest("a[href]");
62
- };
63
-
64
- const syncElementData = ($dataTarget, $targetForFallback = null) => {
65
- let type = $dataTarget.attr("data-type");
66
- if (!type && $targetForFallback && $targetForFallback.length) {
67
- const $fallback = $targetForFallback.attr("data-type")
68
- ? $targetForFallback
69
- : $targetForFallback.find("[data-type]").first();
70
- type = $fallback.attr("data-type");
71
- if ($fallback.length) $dataTarget = $fallback;
72
- }
73
- if (!type) return "";
7
+ // 触发时
8
+ $(selector).on("mouseenter", function (e) {
9
+ clearTimeout(outer);
74
10
 
75
- if (type === "item") {
76
- vm.item.id = $dataTarget.attr("data-id");
77
- vm.item.client = $dataTarget.attr("data-client") == "origin" ? 2 : 1;
11
+ // 获取元素数据
12
+ let type = $(e.target).attr("data-type");
13
+ if (type == "item") {
14
+ vm.item.id = $(e.target).attr("data-id");
15
+ vm.item.client = $(e.target).attr("data-client") == "origin" ? 2 : 1;
78
16
  } else if (type === "author") {
79
- vm.author.id = $dataTarget.attr("data-id");
17
+ vm.author.id = $(e.target).attr("data-id");
80
18
  } else if (type === "emotion") {
81
- vm.emotion.id = $dataTarget.attr("data-id");
82
- } else if (vm[type]) {
83
- vm[type].client = $dataTarget.attr("data-client");
84
- vm[type].id = $dataTarget.attr("data-id");
85
- vm[type].level = $dataTarget.attr("data-level");
19
+ vm.emotion.id = $(e.target).attr("data-id");
20
+ } else {
21
+ vm[type].client = $(e.target).attr("data-client");
22
+ vm[type].id = $(e.target).attr("data-id");
23
+ vm[type].level = $(e.target).attr("data-level");
86
24
  }
87
25
 
26
+ // 显示浮层
27
+ $(pop_class).fadeIn();
88
28
  vm.jx3_element.type = type;
89
- return type;
90
- };
91
-
92
- const showPop = ($dataTarget, point = {}, $targetForRect = null) => {
93
- clearTimeout(outer);
94
- clearTimeout(inner);
95
-
96
- const type = syncElementData($dataTarget, $targetForRect);
97
- if (!type) return;
98
-
99
- const fallbackRect = $targetForRect && $targetForRect.length ? $targetForRect[0].getBoundingClientRect() : null;
100
- const fallbackX = fallbackRect ? fallbackRect.left + fallbackRect.width / 2 : 0;
101
- const fallbackY = fallbackRect ? fallbackRect.top + fallbackRect.height / 2 : 0;
102
- const clientX = Number(point.clientX ?? fallbackX ?? 0);
103
- const clientY = Number(point.clientY ?? fallbackY ?? 0);
104
-
105
- vm.jx3_element.style.display = "block";
106
- vm.jx3_element.style.position = "fixed";
107
- vm.jx3_element.style.zIndex = "99999";
108
- $pop.stop(true, true).fadeIn(120);
109
29
 
110
- const selfHeight = $pop.height();
111
- const winHeight = window.innerHeight;
112
- const currentY = clientY;
113
- let willStayY = clientY + 10;
30
+ // 计算浮层位置
31
+ let self_height = $(pop_class).height();
32
+ let win_height = window.innerHeight;
33
+ let current_y = e.clientY;
34
+ let will_stay_y = e.clientY + 10;
114
35
 
115
- if (selfHeight && winHeight - currentY < selfHeight) {
116
- willStayY = currentY - (selfHeight - (winHeight - currentY)) - 100;
36
+ if (self_height && win_height - current_y < self_height) {
37
+ will_stay_y =
38
+ current_y - (self_height - (win_height - current_y)) - 100;
117
39
  }
118
-
119
- const maxLeft = Math.max(0, window.innerWidth - ($pop.outerWidth() || 0) - 12);
120
- vm.jx3_element.style.left = Math.max(0, Math.min(clientX + 10, maxLeft)) + "px";
121
- vm.jx3_element.style.top = Math.max(0, willStayY) + "px";
122
-
123
- if (debugPop && isMobile()) {
124
- vm.jx3_element.style.left = "50%";
125
- vm.jx3_element.style.top = "52%";
126
- vm.jx3_element.style.transform = "translate(-50%, -50%)";
127
- vm.jx3_element.style.zIndex = "99999";
128
- vm.jx3_element.style.background = "rgba(0,0,0,0.88)";
129
- vm.jx3_element.style.outline = "2px solid #00e5ff";
130
- vm.jx3_element.style.maxHeight = "72vh";
131
- vm.jx3_element.style.overflow = "auto";
132
- } else {
133
- vm.jx3_element.style.transform = "";
134
- vm.jx3_element.style.background = "";
135
- vm.jx3_element.style.outline = "";
136
- vm.jx3_element.style.maxHeight = "";
137
- vm.jx3_element.style.overflow = "";
138
- }
139
- };
140
-
141
- const hidePop = () => {
142
- vm.jx3_element.style.display = "none";
143
- $pop.stop(true, true).fadeOut(120);
144
- };
145
-
146
- // 触发时
147
- $scope.off(ns);
148
- $pop.off(ns);
149
- $(document).off(ns);
150
-
151
- $scope.on(`mouseenter${ns}`, selector, function (e) {
152
- if (isMobile()) return;
153
- const $target = getCurrentTarget(this, e);
154
- const $dataTarget = getDataTarget($target, e);
155
- showPop($dataTarget, e, $target);
40
+ vm.jx3_element.style.left = e.clientX + 10 + "px";
41
+ vm.jx3_element.style.top = will_stay_y + "px";
156
42
  });
157
43
 
158
44
  // 移除时
159
- $scope.on(`mouseleave${ns}`, selector, function () {
160
- if (isMobile()) return;
45
+ $(selector).on("mouseleave", function (e) {
161
46
  outer = setTimeout(() => {
162
- hidePop();
47
+ $(pop_class).fadeOut();
163
48
  }, 380);
164
49
  });
165
50
 
166
- $scope.on(`click${ns}`, selector, function (e) {
167
- if (!isMobile()) return;
168
-
169
- const $target = getCurrentTarget(this, e);
170
- const $dataTarget = getDataTarget($target, e);
171
- if (!$dataTarget.length) return;
172
-
173
- const $hrefTarget = getHrefTarget($target);
174
- const href = String($hrefTarget.attr("href") || "");
175
- const touch = e.originalEvent?.touches?.[0] || e.originalEvent?.changedTouches?.[0];
176
- const point = touch || e;
177
- const tappedElement = $target.get(0);
178
-
179
- if (href && lastTappedElement === tappedElement) {
180
- lastTappedElement = null;
181
- hidePop();
182
- return;
183
- }
184
-
185
- e.preventDefault();
186
- lastTappedElement = tappedElement;
187
- showPop($dataTarget, point, $target);
188
- });
189
-
190
51
  // POP内停留
191
- $pop.on(`mouseenter${ns}`, function () {
192
- if (isMobile()) return;
52
+ $(pop_class).on("mouseenter", function (e) {
193
53
  clearTimeout(outer);
194
- vm.jx3_element.style.display = "block";
195
- $pop.stop(true, true).fadeIn(120);
54
+ $(pop_class).fadeIn();
196
55
  });
197
- $pop.on(`mouseleave${ns}`, function () {
198
- if (isMobile()) return;
56
+ $(pop_class).on("mouseleave", function (e) {
199
57
  clearTimeout(inner);
200
58
  inner = setTimeout(() => {
201
- hidePop();
59
+ $(pop_class).fadeOut();
202
60
  }, 280);
203
61
  });
204
-
205
- $(document).on(`click${ns}`, function (e) {
206
- if (!isMobile()) return;
207
- const $target = $(e.target);
208
- const $trigger = $target.closest(selector);
209
- const isCurrentTrigger = $trigger.length && ($trigger[0] === scopeEl || $scope.has($trigger[0]).length);
210
-
211
- if (isCurrentTrigger || $target.closest(pop_class).length) return;
212
-
213
- lastTappedElement = null;
214
- hidePop();
215
- });
216
62
  }
217
63
 
218
64
  export default renderItem;
@@ -2,6 +2,181 @@ import $ from 'jquery';
2
2
  import katex from 'katex';
3
3
  import 'katex/dist/katex.min.css';
4
4
 
5
+ function isEscaped(text, index) {
6
+ let count = 0;
7
+ for (let i = index - 1; i >= 0 && text[i] === '\\'; i--) {
8
+ count++;
9
+ }
10
+ return count % 2 === 1;
11
+ }
12
+
13
+ function findUnescaped(text, token, start) {
14
+ let index = start;
15
+ while (index < text.length) {
16
+ const found = text.indexOf(token, index);
17
+ if (found === -1) return -1;
18
+ if (!isEscaped(text, found)) return found;
19
+ index = found + token.length;
20
+ }
21
+ return -1;
22
+ }
23
+
24
+ function getTextNodes(container, shouldAccept) {
25
+ const walker = document.createTreeWalker(
26
+ container,
27
+ NodeFilter.SHOW_TEXT,
28
+ {
29
+ acceptNode: function (node) {
30
+ // 跳过已渲染的节点
31
+ if (
32
+ node.parentNode &&
33
+ (node.parentNode.classList?.contains('katex') ||
34
+ node.parentNode.closest("pre, code, .katex"))
35
+ ) {
36
+ return NodeFilter.FILTER_REJECT;
37
+ }
38
+
39
+ return shouldAccept(node.nodeValue || '') ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
40
+ },
41
+ }
42
+ );
43
+
44
+ const nodesToReplace = [];
45
+ while (walker.nextNode()) {
46
+ nodesToReplace.push(walker.currentNode);
47
+ }
48
+ return nodesToReplace;
49
+ }
50
+
51
+ function collectInlineMatches(text) {
52
+ const matches = [];
53
+ let index = 0;
54
+
55
+ while (index < text.length) {
56
+ const parenStart = text.indexOf('\\(', index);
57
+ const dollarStart = text.indexOf('$', index);
58
+ const candidates = [parenStart, dollarStart].filter((value) => value !== -1 && !isEscaped(text, value));
59
+ const start = candidates.length ? Math.min(...candidates) : -1;
60
+ if (start === -1) break;
61
+
62
+ if (text.slice(start, start + 2) === '\\(') {
63
+ const end = findUnescaped(text, '\\)', start + 2);
64
+ if (end !== -1) {
65
+ const raw = text.slice(start + 2, end);
66
+ if (raw && !raw.includes('\n')) {
67
+ matches.push({
68
+ start,
69
+ end: end + 2,
70
+ raw,
71
+ full: text.slice(start, end + 2),
72
+ });
73
+ }
74
+ index = end + 2;
75
+ continue;
76
+ }
77
+ } else if (text[start] === '$' && text[start + 1] !== '$') {
78
+ const end = findUnescaped(text, '$', start + 1);
79
+ if (end !== -1 && text[end + 1] !== '$') {
80
+ const raw = text.slice(start + 1, end);
81
+ if (raw && !raw.includes('\n')) {
82
+ matches.push({
83
+ start,
84
+ end: end + 1,
85
+ raw,
86
+ full: text.slice(start, end + 1),
87
+ });
88
+ }
89
+ index = end + 1;
90
+ continue;
91
+ }
92
+ }
93
+
94
+ index = start + 1;
95
+ }
96
+
97
+ return matches;
98
+ }
99
+
100
+ function collectBlockMatches(text) {
101
+ const matches = [];
102
+ let index = 0;
103
+
104
+ while (index < text.length) {
105
+ const dollarStart = text.indexOf('$$', index);
106
+ const bracketStart = text.indexOf('\\[', index);
107
+ const candidates = [dollarStart, bracketStart].filter((value) => value !== -1 && !isEscaped(text, value));
108
+ const start = candidates.length ? Math.min(...candidates) : -1;
109
+ if (start === -1) break;
110
+
111
+ if (text.slice(start, start + 2) === '$$') {
112
+ const end = findUnescaped(text, '$$', start + 2);
113
+ if (end !== -1) {
114
+ const raw = text.slice(start + 2, end).trim();
115
+ if (raw) {
116
+ matches.push({
117
+ start,
118
+ end: end + 2,
119
+ raw,
120
+ full: text.slice(start, end + 2),
121
+ });
122
+ }
123
+ index = end + 2;
124
+ continue;
125
+ }
126
+ } else if (text.slice(start, start + 2) === '\\[') {
127
+ const end = findUnescaped(text, '\\]', start + 2);
128
+ if (end !== -1) {
129
+ const raw = text.slice(start + 2, end).trim();
130
+ if (raw) {
131
+ matches.push({
132
+ start,
133
+ end: end + 2,
134
+ raw,
135
+ full: text.slice(start, end + 2),
136
+ });
137
+ }
138
+ index = end + 2;
139
+ continue;
140
+ }
141
+ }
142
+
143
+ index = start + 1;
144
+ }
145
+
146
+ return matches;
147
+ }
148
+
149
+ function replaceTextNode(node, matches, renderMatch, logPrefix) {
150
+ if (!matches.length) return;
151
+
152
+ const text = node.nodeValue || '';
153
+ const frag = document.createDocumentFragment();
154
+ let lastIndex = 0;
155
+
156
+ matches.forEach((match) => {
157
+ if (match.start > lastIndex) {
158
+ frag.appendChild(document.createTextNode(text.slice(lastIndex, match.start)));
159
+ }
160
+
161
+ try {
162
+ frag.appendChild(renderMatch(match.raw));
163
+ } catch (e) {
164
+ frag.appendChild(document.createTextNode(match.full));
165
+ console.error(logPrefix, match.raw, e.message);
166
+ }
167
+
168
+ lastIndex = match.end;
169
+ });
170
+
171
+ if (lastIndex < text.length) {
172
+ frag.appendChild(document.createTextNode(text.slice(lastIndex)));
173
+ }
174
+
175
+ if (frag.hasChildNodes()) {
176
+ node.parentNode.replaceChild(frag, node);
177
+ }
178
+ }
179
+
5
180
  function renderKatexBlock(selector = ".w-latex") {
6
181
  try {
7
182
  $(selector).each(function() {
@@ -39,60 +214,11 @@ function renderKatexBlock(selector = ".w-latex") {
39
214
  }
40
215
 
41
216
  function renderKatexInline(container = document.body) {
42
- // 改进的正则:不匹配换行符,支持转义
43
- const inlineRegex = /(?<!\\)(\\\((.+?)\\\)|(?<!\\)\$([^\n$]+?)(?<!\\)\$)/g;
44
-
45
- const walker = document.createTreeWalker(
46
- container,
47
- NodeFilter.SHOW_TEXT,
48
- {
49
- acceptNode: function (node) {
50
- // 跳过已渲染的节点
51
- if (
52
- node.parentNode &&
53
- (node.parentNode.classList?.contains('katex') ||
54
- node.parentNode.closest("pre, code, .katex"))
55
- ) {
56
- return NodeFilter.FILTER_REJECT;
57
- }
58
-
59
- const value = node.nodeValue || '';
60
- if (value.includes("\\(") || value.includes("$")) {
61
- return NodeFilter.FILTER_ACCEPT;
62
- }
63
- return NodeFilter.FILTER_REJECT;
64
- },
65
- }
66
- );
67
-
68
- const nodesToReplace = [];
69
- while (walker.nextNode()) {
70
- nodesToReplace.push(walker.currentNode);
71
- }
72
-
73
- nodesToReplace.forEach((node) => {
74
- const text = node.nodeValue;
75
- const frag = document.createDocumentFragment();
76
- let lastIndex = 0;
77
-
78
- // 重置正则状态
79
- inlineRegex.lastIndex = 0;
80
-
81
- const matches = [...text.matchAll(inlineRegex)];
82
-
83
- matches.forEach((match) => {
84
- const fullMatch = match[0];
85
- const parenContent = match[2];
86
- const dollarContent = match[3];
87
- const raw = parenContent || dollarContent;
88
- const matchStart = match.index;
89
-
90
- // 添加匹配前的文本
91
- if (matchStart > lastIndex) {
92
- frag.appendChild(document.createTextNode(text.slice(lastIndex, matchStart)));
93
- }
94
-
95
- try {
217
+ getTextNodes(container, (value) => value.includes("\\(") || value.includes("$")).forEach((node) => {
218
+ replaceTextNode(
219
+ node,
220
+ collectInlineMatches(node.nodeValue || ''),
221
+ (raw) => {
96
222
  const span = document.createElement("span");
97
223
  span.className = "katex-inline";
98
224
  span.innerHTML = katex.renderToString(raw, {
@@ -101,81 +227,19 @@ function renderKatexInline(container = document.body) {
101
227
  strict: false,
102
228
  trust: true
103
229
  });
104
- frag.appendChild(span);
105
- } catch (e) {
106
- frag.appendChild(document.createTextNode(fullMatch));
107
- console.error("Inline render error:", raw, e.message);
108
- }
109
-
110
- lastIndex = matchStart + fullMatch.length;
111
- });
112
-
113
- // 添加剩余文本
114
- if (lastIndex < text.length) {
115
- frag.appendChild(document.createTextNode(text.slice(lastIndex)));
116
- }
117
-
118
- if (frag.hasChildNodes()) {
119
- node.parentNode.replaceChild(frag, node);
120
- }
230
+ return span;
231
+ },
232
+ "Inline render error:"
233
+ );
121
234
  });
122
235
  }
123
236
 
124
237
  function renderKatexDisplayBlock(container = document.body) {
125
- // 使用非贪婪匹配,允许多行但不跨过多段落
126
- const blockRegex = /(?<!\\)(\$\$([\s\S]+?)\$\$|(?<!\\)\\\[([\s\S]+?)\\\])/g;
127
-
128
- const walker = document.createTreeWalker(
129
- container,
130
- NodeFilter.SHOW_TEXT,
131
- {
132
- acceptNode: function (node) {
133
- // 跳过已渲染的节点
134
- if (
135
- node.parentNode &&
136
- (node.parentNode.classList?.contains('katex') ||
137
- node.parentNode.closest("pre, code, .katex"))
138
- ) {
139
- return NodeFilter.FILTER_REJECT;
140
- }
141
-
142
- const value = node.nodeValue || '';
143
- if (value.includes("$$") || value.includes("\\[")) {
144
- return NodeFilter.FILTER_ACCEPT;
145
- }
146
- return NodeFilter.FILTER_REJECT;
147
- },
148
- }
149
- );
150
-
151
- const nodesToReplace = [];
152
- while (walker.nextNode()) {
153
- nodesToReplace.push(walker.currentNode);
154
- }
155
-
156
- nodesToReplace.forEach((node) => {
157
- const text = node.nodeValue;
158
- const frag = document.createDocumentFragment();
159
- let lastIndex = 0;
160
-
161
- // 重置正则状态
162
- blockRegex.lastIndex = 0;
163
-
164
- const matches = [...text.matchAll(blockRegex)];
165
-
166
- matches.forEach((match) => {
167
- const fullMatch = match[0];
168
- const dollarContent = match[2];
169
- const bracketContent = match[3];
170
- const raw = (dollarContent || bracketContent).trim();
171
- const matchStart = match.index;
172
-
173
- // 添加匹配前的文本
174
- if (matchStart > lastIndex) {
175
- frag.appendChild(document.createTextNode(text.slice(lastIndex, matchStart)));
176
- }
177
-
178
- try {
238
+ getTextNodes(container, (value) => value.includes("$$") || value.includes("\\[")).forEach((node) => {
239
+ replaceTextNode(
240
+ node,
241
+ collectBlockMatches(node.nodeValue || ''),
242
+ (raw) => {
179
243
  const div = document.createElement("div");
180
244
  div.className = "katex-block";
181
245
  div.innerHTML = katex.renderToString(raw, {
@@ -184,23 +248,10 @@ function renderKatexDisplayBlock(container = document.body) {
184
248
  strict: false,
185
249
  trust: true
186
250
  });
187
- frag.appendChild(div);
188
- } catch (e) {
189
- frag.appendChild(document.createTextNode(fullMatch));
190
- console.error("Block render error:", raw, e.message);
191
- }
192
-
193
- lastIndex = matchStart + fullMatch.length;
194
- });
195
-
196
- // 添加剩余文本
197
- if (lastIndex < text.length) {
198
- frag.appendChild(document.createTextNode(text.slice(lastIndex)));
199
- }
200
-
201
- if (frag.hasChildNodes()) {
202
- node.parentNode.replaceChild(frag, node);
203
- }
251
+ return div;
252
+ },
253
+ "Block render error:"
254
+ );
204
255
  });
205
256
  }
206
257
 
@@ -1,23 +1,23 @@
1
1
  import $ from "jquery";
2
- function buildIframe(str) {
2
+ function buildIframe(str){
3
3
  let _str = new URLSearchParams(str);
4
- let mode = _str.get("mode");
4
+ let mode = _str.get('mode')
5
5
 
6
- if (mode == "vertical") {
7
- return `<div class="w-pz-iframe-wrap" style="width:100%;overflow:auto;"><iframe class="w-pz-iframe" src="${str}" scrolling="no" width="750" height="3468" style="border:none;background:none;max-width:none;"></iframe></div>`;
8
- } else {
9
- return `<div class="w-pz-iframe-wrap" style="width:100%;overflow:auto;"><iframe class="w-pz-iframe" src="${str}" scrolling="no" width="1280" height="720" style="border:none;background:none;max-width:none;"></iframe></div>`;
6
+ if(mode == 'vertical'){
7
+ return `<iframe class="w-pz-iframe" src="${str}" scrolling="no" width="750" height="3468" style="border:none;background:none;max-width:100%;overflow:hidden;"></iframe>`
8
+ }else{
9
+ return `<iframe class="w-pz-iframe" src="${str}" scrolling="no" width="1280" height="720" style="border:none;background:none;max-width:100%;overflow:hidden;"></iframe>`
10
10
  }
11
11
  }
12
12
 
13
- function renderPzIframe(selector = ".e-pz-iframe") {
13
+ function renderPzIframe(selector = ".e-pz-iframe"){
14
14
  try {
15
- $(selector).each(function (i, ele) {
15
+ $(selector).each(function(i, ele) {
16
16
  // 获取嵌入源地址
17
- let url = $(this).text();
17
+ let url = $(this).text();
18
18
 
19
19
  // 构建嵌入源码
20
- let code = buildIframe(url);
20
+ let code = buildIframe(url)
21
21
 
22
22
  // 挂载点
23
23
  $(this).after(code);
@@ -27,4 +27,4 @@ function renderPzIframe(selector = ".e-pz-iframe") {
27
27
  }
28
28
  }
29
29
 
30
- export default renderPzIframe;
30
+ export default renderPzIframe
@@ -70,8 +70,8 @@
70
70
 
71
71
  <script>
72
72
  import { authorLink, getLink, getMedalLink, getThumbnail } from "@jx3box/jx3box-common/js/utils";
73
- import { getUserInfo, getUserMedals, getUserPublicTeams } from "../service/author.js";
74
- import { getDecoration, getDecorationJson } from "../service/cms.js";
73
+ import { getUserInfo, getUserMedals, getUserPublicTeams } from "../service/author";
74
+ import { getDecoration, getDecorationJson } from "../service/cms";
75
75
  import User from "@jx3box/jx3box-common/js/user";
76
76
  import JX3BOX from "@jx3box/jx3box-common/data/jx3box.json";
77
77
  import Avatar from "./Avatar.vue";
@@ -154,7 +154,7 @@ import { h } from "vue";
154
154
  import { ElIcon } from "element-plus";
155
155
  import { Check, Close } from "@element-plus/icons-vue";
156
156
  import { iconLink } from "@jx3box/jx3box-common/js/utils";
157
- import { getSkill } from "../service/resource.js";
157
+ import { getSkill } from "../service/resource";
158
158
  import SkillMartial from "./SkillMartial.vue";
159
159
 
160
160
  import Sortable from "sortablejs";
@@ -27,7 +27,7 @@
27
27
 
28
28
  <script>
29
29
  import { authorLink } from "@jx3box/jx3box-common/js/utils";
30
- import { getEmotion } from "../service/author.js";
30
+ import { getEmotion } from "../service/author";
31
31
  import JX3BOX from "@jx3box/jx3box-common/data/jx3box.json";
32
32
  import dayjs from "dayjs";
33
33
  import Avatar from "./Avatar.vue";
@@ -178,7 +178,7 @@ import {
178
178
  getSkills,
179
179
  getTalents,
180
180
  getMobileForceSkillList,
181
- } from "../service/node.js";
181
+ } from "../service/node";
182
182
  import kungfumap_std from "@jx3box/jx3box-data/data/martial/kungfu_std.json";
183
183
  import kungfumap_origin from "@jx3box/jx3box-data/data/martial/kungfu_origin.json";
184
184
  import { flattenDeep, uniqBy } from "lodash";