@2kog/pkg-editor 0.0.1

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.
@@ -0,0 +1,192 @@
1
+ import $ from 'jquery';
2
+ import katex from 'katex';
3
+ import 'katex/dist/katex.min.css';
4
+
5
+ function renderKatexBlock(selector = ".w-latex") {
6
+ try {
7
+ // eslint-disable-next-line no-unused-vars
8
+ $(selector).each(function(i, ele) {
9
+ let $katex = $(this);
10
+
11
+ // 获取原始HTML内容
12
+ let raw = $katex.html();
13
+
14
+ // 处理各种换行组合:
15
+ // 1. \\<br /> 或 \\<br> -> \\
16
+ raw = raw.replace(/\\\\\s*<br\s*\/?>/gi, '\\\\');
17
+ // 2. \<br /> 或 \<br> -> \\
18
+ raw = raw.replace(/\\\s*<br\s*\/?>/gi, '\\\\');
19
+ // 3. 单独的 <br /> -> \\
20
+ raw = raw.replace(/<br\s*\/?>/gi, '\\\\');
21
+
22
+ // 移除其他HTML标签但保留内容
23
+ raw = raw.replace(/<[^>]+>/g, '');
24
+
25
+ // 解码HTML实体(如 &nbsp; -> 空格)
26
+ raw = $('<div>').html(raw).text();
27
+
28
+ // 清理多余的空白字符
29
+ raw = raw.trim();
30
+
31
+ console.log('Original HTML:', $katex.html());
32
+ console.log('Processed LaTeX:', raw);
33
+
34
+ katex.render(raw, $katex.get(0), { displayMode: true });
35
+ });
36
+ } catch (e) {
37
+ console.error('KaTeX render error:', e);
38
+ console.error('Failed content:', $(this).html());
39
+ }
40
+ }
41
+
42
+ function renderKatexInline(container = document.body) {
43
+ // 支持 \(...\) 和 $...$ 两种行内语法
44
+ // 改进正则表达式,更好地匹配单美元符号
45
+ const inlineRegex = /(\\\((.+?)\\\)|\$([^$]+?)\$)/g;
46
+
47
+ const walker = document.createTreeWalker(
48
+ container,
49
+ NodeFilter.SHOW_TEXT,
50
+ {
51
+ acceptNode: function (node) {
52
+ if (
53
+ node.parentNode &&
54
+ !node.parentNode.closest("pre") &&
55
+ (node.nodeValue.includes("\\(") || node.nodeValue.includes("$"))
56
+ ) {
57
+ return NodeFilter.FILTER_ACCEPT;
58
+ }
59
+ return NodeFilter.FILTER_REJECT;
60
+ },
61
+ }
62
+ );
63
+
64
+ const nodesToReplace = [];
65
+ while (walker.nextNode()) {
66
+ nodesToReplace.push(walker.currentNode);
67
+ }
68
+
69
+ console.log('Inline processing nodes:', nodesToReplace.length);
70
+
71
+ nodesToReplace.forEach((node) => {
72
+ const text = node.nodeValue;
73
+ const frag = document.createDocumentFragment();
74
+ let lastIndex = 0;
75
+ let match;
76
+
77
+ console.log('Processing text:', text);
78
+
79
+ while ((match = inlineRegex.exec(text))) {
80
+ const fullMatch = match[0];
81
+ const parenContent = match[2]; // \(...\)的内容
82
+ const dollarContent = match[3]; // $...$的内容
83
+ const raw = parenContent || dollarContent;
84
+ const matchStart = match.index;
85
+
86
+ console.log('Found inline match:', fullMatch, 'Raw:', raw);
87
+
88
+ // 添加匹配前文本
89
+ frag.appendChild(document.createTextNode(text.slice(lastIndex, matchStart)));
90
+
91
+ try {
92
+ const span = document.createElement("span");
93
+ // 处理JavaScript字符串中的双反斜杠转义
94
+ const processedRaw = raw.replace(/\\\\/g, '\\');
95
+ console.log('Rendering inline:', processedRaw);
96
+ // 添加更多选项确保正确渲染
97
+ span.innerHTML = katex.renderToString(processedRaw, {
98
+ displayMode: false,
99
+ throwOnError: false,
100
+ strict: false,
101
+ trust: true
102
+ });
103
+ frag.appendChild(span);
104
+ } catch (e) {
105
+ frag.appendChild(document.createTextNode(fullMatch));
106
+ console.error("Inline render error:", raw, e);
107
+ }
108
+
109
+ lastIndex = inlineRegex.lastIndex;
110
+ }
111
+
112
+ // 剩余文本
113
+ if (lastIndex < text.length) {
114
+ frag.appendChild(document.createTextNode(text.slice(lastIndex)));
115
+ }
116
+
117
+ if (frag.hasChildNodes()) {
118
+ node.parentNode.replaceChild(frag, node);
119
+ }
120
+ });
121
+ }
122
+
123
+ function renderKatexDisplayBlock(container = document.body) {
124
+ // 支持 $$...$$ 和 \[...\] 两种块语法
125
+ const blockRegex = /(\$\$\s*([\s\S]+?)\s*\$\$|\\\[\s*([\s\S]+?)\s*\\\])/g;
126
+
127
+ const walker = document.createTreeWalker(
128
+ container,
129
+ NodeFilter.SHOW_TEXT,
130
+ {
131
+ acceptNode: function (node) {
132
+ if (
133
+ node.parentNode &&
134
+ !node.parentNode.closest("pre") &&
135
+ (node.nodeValue.includes("$$") || node.nodeValue.includes("\\["))
136
+ ) {
137
+ return NodeFilter.FILTER_ACCEPT;
138
+ }
139
+ return NodeFilter.FILTER_REJECT;
140
+ },
141
+ }
142
+ );
143
+
144
+ const nodesToReplace = [];
145
+ while (walker.nextNode()) {
146
+ nodesToReplace.push(walker.currentNode);
147
+ }
148
+
149
+ nodesToReplace.forEach((node) => {
150
+ const text = node.nodeValue;
151
+ const frag = document.createDocumentFragment();
152
+ let lastIndex = 0;
153
+ let match;
154
+
155
+ while ((match = blockRegex.exec(text))) {
156
+ const fullMatch = match[0];
157
+ const dollarContent = match[2]; // $$...$$的内容
158
+ const bracketContent = match[3]; // \[...\]的内容
159
+ const raw = dollarContent || bracketContent;
160
+ const matchStart = match.index;
161
+
162
+ // 添加匹配前文本
163
+ frag.appendChild(document.createTextNode(text.slice(lastIndex, matchStart)));
164
+
165
+ try {
166
+ const div = document.createElement("div");
167
+ // 处理JavaScript字符串中的双反斜杠转义
168
+ const processedRaw = raw.replace(/\\\\/g, '\\');
169
+ div.innerHTML = katex.renderToString(processedRaw, { displayMode: true });
170
+ frag.appendChild(div);
171
+ } catch (e) {
172
+ frag.appendChild(document.createTextNode(fullMatch));
173
+ console.error("Block render error:", raw, e);
174
+ }
175
+
176
+ lastIndex = blockRegex.lastIndex;
177
+ }
178
+
179
+ // 添加剩余文本
180
+ if (lastIndex < text.length) {
181
+ frag.appendChild(document.createTextNode(text.slice(lastIndex)));
182
+ }
183
+
184
+ node.parentNode.replaceChild(frag, node);
185
+ });
186
+ }
187
+
188
+ export default function renderKatexAll(container = document.body) {
189
+ renderKatexBlock(".w-latex");
190
+ renderKatexDisplayBlock(container);
191
+ renderKatexInline(container);
192
+ }
@@ -0,0 +1,4 @@
1
+ function splitPages(str) {
2
+ return (str && str.split("<!--nextpage-->")) || "";
3
+ }
4
+ export default splitPages;
@@ -0,0 +1,67 @@
1
+ import $ from "jquery";
2
+ import PhotoSwipe from "photoswipe";
3
+ import PhotoSwipeUI_Default from "photoswipe/dist/photoswipe-ui-default";
4
+ import "photoswipe/dist/photoswipe.css";
5
+ import "photoswipe/dist/default-skin/default-skin.css";
6
+ import tpl from "./pswp_template.js";
7
+ // https://photoswipe.com/documentation/options.html
8
+
9
+ class Gallery {
10
+ constructor(options) {
11
+ this._picbox = "";
12
+ this.options = options || {
13
+ bgOpacity: 0.8,
14
+ shareEl: false,
15
+ zoomEl: false,
16
+ closeOnScroll: false,
17
+ };
18
+ this.bucket = [];
19
+ this.items = [];
20
+ this.pswp = "";
21
+ }
22
+ init($root, $selector = "img") {
23
+ // 创建容器
24
+ let isExist = document.querySelectorAll(".pswp").length;
25
+ if (!isExist) $("body").append(tpl);
26
+ this._picbox = document.querySelectorAll(".pswp")[0];
27
+
28
+ //fix需要清空,可能替换内容重复渲染
29
+ this.bucket = [];
30
+ this.items = [];
31
+
32
+ // 缓存图片序列
33
+ $($root)
34
+ .find($selector + ":visible")
35
+ .each((i, $pic) => {
36
+ this.bucket.push($pic);
37
+ this.items.push({
38
+ $el: $pic,
39
+ src: $pic.src,
40
+ w: $pic.naturalWidth || $pic.width || 400,
41
+ h: $pic.naturalHeight || $pic.height || 400,
42
+ });
43
+ });
44
+
45
+ // 绑定事件
46
+ $($root)
47
+ .find($selector)
48
+ .on("click", (e) => {
49
+ this.open(e.target);
50
+ });
51
+ }
52
+ open(target) {
53
+ let i = this.bucket.indexOf(target);
54
+ //可能为0
55
+ if (i > -1) {
56
+ let _options = Object.assign(this.options, {
57
+ index: i,
58
+ });
59
+ // 需要在每次调用时重新初始化,因为关闭按钮会自动销毁实例
60
+ let pswp = new PhotoSwipe(this._picbox, PhotoSwipeUI_Default, this.items, _options);
61
+
62
+ pswp.init();
63
+ }
64
+ }
65
+ }
66
+
67
+ export default new Gallery();
@@ -0,0 +1,66 @@
1
+ export default `<!-- Root element of PhotoSwipe. Must have class pswp. -->
2
+ <div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">
3
+
4
+ <!-- Background of PhotoSwipe.
5
+ It's a separate element as animating opacity is faster than rgba(). -->
6
+ <div class="pswp__bg"></div>
7
+
8
+ <!-- Slides wrapper with overflow:hidden. -->
9
+ <div class="pswp__scroll-wrap">
10
+
11
+ <!-- Container that holds slides.
12
+ PhotoSwipe keeps only 3 of them in the DOM to save memory.
13
+ Don't modify these 3 pswp__item elements, data is added later on. -->
14
+ <div class="pswp__container">
15
+ <div class="pswp__item"></div>
16
+ <div class="pswp__item"></div>
17
+ <div class="pswp__item"></div>
18
+ </div>
19
+
20
+ <!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
21
+ <div class="pswp__ui pswp__ui--hidden">
22
+
23
+ <div class="pswp__top-bar">
24
+
25
+ <!-- Controls are self-explanatory. Order can be changed. -->
26
+
27
+ <div class="pswp__counter"></div>
28
+
29
+ <button class="pswp__button pswp__button--close" title="Close (Esc)"></button>
30
+
31
+ <button class="pswp__button pswp__button--share" title="Share"></button>
32
+
33
+ <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>
34
+
35
+ <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>
36
+
37
+ <!-- Preloader demo https://codepen.io/dimsemenov/pen/yyBWoR -->
38
+ <!-- element will get class pswp__preloader--active when preloader is running -->
39
+ <div class="pswp__preloader">
40
+ <div class="pswp__preloader__icn">
41
+ <div class="pswp__preloader__cut">
42
+ <div class="pswp__preloader__donut"></div>
43
+ </div>
44
+ </div>
45
+ </div>
46
+ </div>
47
+
48
+ <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
49
+ <div class="pswp__share-tooltip"></div>
50
+ </div>
51
+
52
+ <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
53
+ </button>
54
+
55
+ <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
56
+ </button>
57
+
58
+ <div class="pswp__caption">
59
+ <div class="pswp__caption__center"></div>
60
+ </div>
61
+
62
+ </div>
63
+
64
+ </div>
65
+
66
+ </div>`;
@@ -0,0 +1,18 @@
1
+ import $ from "jquery";
2
+ import "viewerjs/dist/viewer.css";
3
+ import Viewer from "viewerjs";
4
+
5
+ function renderImgPreview(selector = ".c-article img") {
6
+ // 获取src不为空的图片
7
+ let imgs = $(selector).filter(function () {
8
+ return $(this).attr("src") != "";
9
+ });
10
+ imgs.each((i, ele) => {
11
+ new Viewer(ele, {
12
+ toolbar: false,
13
+ navbar: false,
14
+ });
15
+ });
16
+ }
17
+
18
+ export default renderImgPreview;