@jx3box/jx3box-editor 1.4.12 → 1.5.2
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.
- package/assets/js/renderImgPreview.js +5 -1
- package/package.json +1 -1
- package/src/ArticleMarkdown.vue +12 -0
- package/src/GameText.vue +192 -158
- package/src/Item.vue +1 -1
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import $ from 'jquery'
|
|
2
2
|
|
|
3
3
|
function renderImgPreview(vm, selector='.c-article img'){
|
|
4
|
-
|
|
4
|
+
// 获取src不为空的图片
|
|
5
|
+
let imgs = $(selector).filter(function(){
|
|
6
|
+
return $(this).attr('src') != ''
|
|
7
|
+
})
|
|
8
|
+
imgs.each((i, ele) => {
|
|
5
9
|
// 加载全部src(lazyload)
|
|
6
10
|
vm.images.push($(ele).attr('src'))
|
|
7
11
|
// 绑定事件挂钩索引位置
|
package/package.json
CHANGED
package/src/ArticleMarkdown.vue
CHANGED
|
@@ -13,6 +13,10 @@
|
|
|
13
13
|
<script>
|
|
14
14
|
import markdownRender from '@jx3box/markdown/src/render.vue'
|
|
15
15
|
|
|
16
|
+
import Vue from "vue";
|
|
17
|
+
import hevueImgPreview from "hevue-img-preview";
|
|
18
|
+
Vue.use(hevueImgPreview);
|
|
19
|
+
|
|
16
20
|
// 基本文本
|
|
17
21
|
import execLazyload from "../assets/js/img";
|
|
18
22
|
import execFilterIframe from "../assets/js/iframe";
|
|
@@ -33,6 +37,7 @@ import Buff from "./Buff";
|
|
|
33
37
|
import Skill from "./Skill";
|
|
34
38
|
import Npc from "./Npc";
|
|
35
39
|
import renderJx3Element from "../assets/js/jx3_element";
|
|
40
|
+
import renderImgPreview from "../assets/js/renderImgPreview";
|
|
36
41
|
|
|
37
42
|
import {xssOptions} from '../assets/data/markdown_whitelist.json'
|
|
38
43
|
|
|
@@ -79,6 +84,7 @@ export default {
|
|
|
79
84
|
},
|
|
80
85
|
type: "",
|
|
81
86
|
},
|
|
87
|
+
images: [],
|
|
82
88
|
|
|
83
89
|
xssOptions
|
|
84
90
|
};
|
|
@@ -106,6 +112,8 @@ export default {
|
|
|
106
112
|
renderTalent2();
|
|
107
113
|
// Tatex
|
|
108
114
|
renderKatex();
|
|
115
|
+
// 画廊
|
|
116
|
+
renderImgPreview(this);
|
|
109
117
|
// 语法高亮
|
|
110
118
|
renderCode(`code[class=^'lang-']`)
|
|
111
119
|
// 物品
|
|
@@ -156,4 +164,8 @@ export default {
|
|
|
156
164
|
|
|
157
165
|
<style lang="less">
|
|
158
166
|
@import "../assets/css/article_markdown.less";
|
|
167
|
+
|
|
168
|
+
.v-note-img-wrapper {
|
|
169
|
+
display: none;
|
|
170
|
+
}
|
|
159
171
|
</style>
|
package/src/GameText.vue
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* @Description: 用于渲染游戏内Text标签的文本
|
|
7
7
|
-->
|
|
8
8
|
<template>
|
|
9
|
-
|
|
9
|
+
<span v-html="html"></span>
|
|
10
10
|
</template>
|
|
11
11
|
|
|
12
12
|
<script>
|
|
@@ -15,170 +15,204 @@ import { getResource } from "../service/resource";
|
|
|
15
15
|
import { escape } from "lodash";
|
|
16
16
|
|
|
17
17
|
export default {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
name: "GameText",
|
|
19
|
+
props: {
|
|
20
|
+
text: {
|
|
21
|
+
type: String,
|
|
22
|
+
default: "",
|
|
23
|
+
},
|
|
24
|
+
client: {
|
|
25
|
+
type: String,
|
|
26
|
+
default: "std",
|
|
27
|
+
},
|
|
23
28
|
},
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
29
|
+
data: function () {
|
|
30
|
+
return {
|
|
31
|
+
html: "",
|
|
32
|
+
};
|
|
27
33
|
},
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const fonts = require("../assets/data/game_font.json");
|
|
49
|
-
for (let color in fonts) {
|
|
50
|
-
if (fonts[color].includes(item.font)) {
|
|
51
|
-
style = `color: ${color};`;
|
|
52
|
-
break;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
if (item.name == "iteminfolink" && item.script) {
|
|
57
|
-
let item_type = item.script?.match(/this\.dwTabType=(\d+)/i)?.[1];
|
|
58
|
-
let item_index = item.script?.match(/this\.dwIndex=(\d+)/i)?.[1];
|
|
59
|
-
if (item_type && item_index) {
|
|
60
|
-
let item_id = `${item_type}_${item_index}`;
|
|
61
|
-
link = getLink("item", item_id);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
if (link) {
|
|
65
|
-
return `<a style="${style} text-decoration: none;" target="_blank" href="${link}">${content}</a>`;
|
|
66
|
-
} else {
|
|
67
|
-
return `<span style="${style}">${content}</span>`;
|
|
68
|
-
}
|
|
69
|
-
},
|
|
70
|
-
/**
|
|
71
|
-
* 将一段游戏内文本转换为Html
|
|
72
|
-
* @param {Object[]} texts 标签对象
|
|
73
|
-
*/
|
|
74
|
-
renderTextHtml: function (Text) {
|
|
75
|
-
let result = Text;
|
|
76
|
-
const matches = Text.match(/<Text>(.*?)<\/text>/gimsy);
|
|
77
|
-
if (!matches) return Text;
|
|
78
|
-
for (let match of matches) {
|
|
79
|
-
let text = extractTextContent(match);
|
|
80
|
-
let html = this.renderItemHtml(text[0]);
|
|
81
|
-
result = result.replace(match, html);
|
|
82
|
-
}
|
|
83
|
-
return result;
|
|
84
|
-
},
|
|
85
|
-
/**
|
|
86
|
-
* 获取形如<BUFF 110 1 desc>, <ENCHANT 100>的资源字段并转换
|
|
87
|
-
*/
|
|
88
|
-
renderBuffResource: function () {
|
|
89
|
-
const matches = this.html.match(/<BUFF (\d+) (\d+) (.*?)>/gim);
|
|
90
|
-
if (!matches) return;
|
|
91
|
-
let need_replaces = {};
|
|
92
|
-
//先统计需要的资源,减少请求数量
|
|
93
|
-
for (let match of matches) {
|
|
94
|
-
let [token, id, level, type] = match.match(/<BUFF (\d+) (\d+) (.*?)>/i);
|
|
95
|
-
let buff_token = `${id}_${level}`;
|
|
96
|
-
if (!need_replaces[buff_token]) {
|
|
97
|
-
need_replaces[buff_token] = [];
|
|
98
|
-
}
|
|
99
|
-
need_replaces[buff_token].push({
|
|
100
|
-
token,
|
|
101
|
-
type,
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
//对每一个需要的资源发起请求
|
|
105
|
-
for (let buff_token in need_replaces) {
|
|
106
|
-
let token_item = need_replaces[buff_token];
|
|
107
|
-
getResource(`buff.${buff_token}`, this.client)
|
|
108
|
-
.then((res) => {
|
|
109
|
-
let data = res.data;
|
|
110
|
-
for (let item of token_item) {
|
|
111
|
-
item.type = item.type.toLowerCase();
|
|
112
|
-
let type_map = {
|
|
113
|
-
desc: "Desc",
|
|
114
|
-
time: "Interval",
|
|
115
|
-
};
|
|
116
|
-
let attr = type_map[item.type] || item.type;
|
|
117
|
-
let value = data[attr];
|
|
118
|
-
if (typeof value == "number" && item.type == "time") {
|
|
119
|
-
let time = value / 16;
|
|
120
|
-
if (time > 60) {
|
|
121
|
-
time = `${Math.floor(time / 60)}分钟`;
|
|
122
|
-
} else {
|
|
123
|
-
time = `${time}秒`;
|
|
34
|
+
methods: {
|
|
35
|
+
/**
|
|
36
|
+
* 渲染某一个单独的Text标签成Span或链接
|
|
37
|
+
* @param {*} school_id
|
|
38
|
+
* @returns
|
|
39
|
+
*/
|
|
40
|
+
renderItemHtml: function (item) {
|
|
41
|
+
let content = item.text;
|
|
42
|
+
let style = ``;
|
|
43
|
+
let link = null;
|
|
44
|
+
content = content.replace(/\\n/g, "<br />").replace(/\\/g, "");
|
|
45
|
+
if ([item.r, item.g, item.b].every(v => v != undefined && v > 0)) {
|
|
46
|
+
style = `color: rgb(${item.r}, ${item.g}, ${item.b});`;
|
|
47
|
+
} else if (item.font != undefined && item.font != 100) {
|
|
48
|
+
const fonts = require("../assets/data/game_font.json");
|
|
49
|
+
for (let color in fonts) {
|
|
50
|
+
if (fonts[color].includes(item.font)) {
|
|
51
|
+
style = `color: ${color};`;
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
124
54
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
value = value.replace(_match, data[`BeginValue${i}A`]);
|
|
136
|
-
}
|
|
55
|
+
}
|
|
56
|
+
if (item.name == "iteminfolink" && item.script) {
|
|
57
|
+
let item_type = item.script?.match(
|
|
58
|
+
/this\.dwTabType=(\d+)/i
|
|
59
|
+
)?.[1];
|
|
60
|
+
let item_index =
|
|
61
|
+
item.script?.match(/this\.dwIndex=(\d+)/i)?.[1];
|
|
62
|
+
if (item_type && item_index) {
|
|
63
|
+
let item_id = `${item_type}_${item_index}`;
|
|
64
|
+
link = getLink("item", item_id);
|
|
137
65
|
}
|
|
138
|
-
}
|
|
139
|
-
this.html = this.html.replace(item.token, value);
|
|
140
66
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
let
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
67
|
+
if (link) {
|
|
68
|
+
return `<a style="${style} text-decoration: none;" target="_blank" href="${link}">${content}</a>`;
|
|
69
|
+
} else {
|
|
70
|
+
return `<span style="${style}">${content}</span>`;
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
/**
|
|
74
|
+
* 将image标签转换为HTML标签
|
|
75
|
+
*/
|
|
76
|
+
renderImageHtml: function (Text) {
|
|
77
|
+
// <image>path="fromiconid" frame=1241 w=29 h=29 </image>
|
|
78
|
+
let matches = Text.match(/<image>(.*?)<\/image>/gims);
|
|
79
|
+
if (!matches) return Text;
|
|
80
|
+
for (let match of matches) {
|
|
81
|
+
let icon_id = match.match(/frame=(\d+)/i)?.[1];
|
|
82
|
+
let w = parseInt(match.match(/w=(\d+)/i)?.[1]) / 1.12;
|
|
83
|
+
let h = parseInt(match.match(/h=(\d+)/i)?.[1]) / 1.12;
|
|
84
|
+
let src = `https://icon.jx3box.com/icon/${icon_id}.png`;
|
|
85
|
+
let html = `<img src="${src}" style="width: ${w}px; height: ${h}px; margin-bottom: -5px" />`;
|
|
86
|
+
Text = Text.replace(match, html);
|
|
87
|
+
}
|
|
88
|
+
return Text;
|
|
89
|
+
},
|
|
90
|
+
/**
|
|
91
|
+
* 将一段游戏内文本转换为Html
|
|
92
|
+
* @param {Object[]} texts 标签对象
|
|
93
|
+
*/
|
|
94
|
+
renderTextHtml: function (Text) {
|
|
95
|
+
let result = Text;
|
|
96
|
+
result = this.renderImageHtml(result);
|
|
97
|
+
const matches = Text.match(/<Text>(.*?)<\/text>/gims);
|
|
98
|
+
if (!matches) return Text;
|
|
99
|
+
for (let match of matches) {
|
|
100
|
+
let text = extractTextContent(match);
|
|
101
|
+
let html = this.renderItemHtml(text[0]);
|
|
102
|
+
result = result.replace(match, html);
|
|
103
|
+
}
|
|
104
|
+
return result;
|
|
105
|
+
},
|
|
106
|
+
/**
|
|
107
|
+
* 获取形如<BUFF 110 1 desc>, <ENCHANT 100>的资源字段并转换
|
|
108
|
+
*/
|
|
109
|
+
renderBuffResource: function () {
|
|
110
|
+
const matches = this.html.match(/<BUFF (\d+) (\d+) (.*?)>/gim);
|
|
111
|
+
if (!matches) return;
|
|
112
|
+
let need_replaces = {};
|
|
113
|
+
//先统计需要的资源,减少请求数量
|
|
114
|
+
for (let match of matches) {
|
|
115
|
+
let [token, id, level, type] = match.match(
|
|
116
|
+
/<BUFF (\d+) (\d+) (.*?)>/i
|
|
117
|
+
);
|
|
118
|
+
let buff_token = `${id}_${level}`;
|
|
119
|
+
if (!need_replaces[buff_token]) {
|
|
120
|
+
need_replaces[buff_token] = [];
|
|
121
|
+
}
|
|
122
|
+
need_replaces[buff_token].push({
|
|
123
|
+
token,
|
|
124
|
+
type,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
//对每一个需要的资源发起请求
|
|
128
|
+
for (let buff_token in need_replaces) {
|
|
129
|
+
let token_item = need_replaces[buff_token];
|
|
130
|
+
getResource(`buff.${buff_token}`, this.client)
|
|
131
|
+
.then(res => {
|
|
132
|
+
let data = res.data;
|
|
133
|
+
for (let item of token_item) {
|
|
134
|
+
item.type = item.type.toLowerCase();
|
|
135
|
+
let type_map = {
|
|
136
|
+
desc: "Desc",
|
|
137
|
+
time: "Interval",
|
|
138
|
+
};
|
|
139
|
+
let attr = type_map[item.type] || item.type;
|
|
140
|
+
let value = data[attr];
|
|
141
|
+
if (
|
|
142
|
+
typeof value == "number" &&
|
|
143
|
+
item.type == "time"
|
|
144
|
+
) {
|
|
145
|
+
let time = value / 16;
|
|
146
|
+
if (time > 60) {
|
|
147
|
+
time = `${Math.floor(time / 60)}分钟`;
|
|
148
|
+
} else {
|
|
149
|
+
time = `${time}秒`;
|
|
150
|
+
}
|
|
151
|
+
this.html = this.html.replace(item.token, time);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (!value) return;
|
|
155
|
+
let _matches = value.match(
|
|
156
|
+
/<BUFF ([0-9a-zA-Z]+)>/gi
|
|
157
|
+
);
|
|
158
|
+
if (!_matches)
|
|
159
|
+
this.html = this.html.replace(match, value);
|
|
160
|
+
for (let _match of _matches) {
|
|
161
|
+
let [, _attr] = _match.match(
|
|
162
|
+
/<BUFF ([0-9a-zA-Z]+)>/i
|
|
163
|
+
);
|
|
164
|
+
for (let i = 1; i < 15; i++) {
|
|
165
|
+
if (data[`BeginAttrib${i}`] == _attr) {
|
|
166
|
+
value = value.replace(
|
|
167
|
+
_match,
|
|
168
|
+
data[`BeginValue${i}A`]
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
this.html = this.html.replace(item.token, value);
|
|
174
|
+
}
|
|
175
|
+
})
|
|
176
|
+
.catch(err => {
|
|
177
|
+
console.log(err);
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
renderEnchantResource: function () {
|
|
182
|
+
const matches = this.html.match(/<ENCHANT (\d+)>/gim);
|
|
183
|
+
if (!matches) return;
|
|
184
|
+
for (let match of matches) {
|
|
185
|
+
let enchant_id = match.match(/<ENCHANT (\d+)>/i)[1];
|
|
186
|
+
getResource(`enchant.${enchant_id}`, this.client)
|
|
187
|
+
.then(res => {
|
|
188
|
+
let data = res.data;
|
|
189
|
+
let time = data.Time;
|
|
190
|
+
if (time) time = `,持续${parseInt(time) / 60}分钟。`;
|
|
191
|
+
let result = `${data.AttriName}${time ? time : ""}`;
|
|
192
|
+
this.html = this.html.replace(match, result);
|
|
193
|
+
})
|
|
194
|
+
.catch(err => {
|
|
195
|
+
this.html = this.html.replace(match, escape(match));
|
|
196
|
+
console.log(err);
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
renderResource: function () {
|
|
201
|
+
this.renderBuffResource();
|
|
202
|
+
this.renderEnchantResource();
|
|
203
|
+
},
|
|
169
204
|
},
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
205
|
+
watch: {
|
|
206
|
+
text: {
|
|
207
|
+
immediate: true,
|
|
208
|
+
handler: function (val) {
|
|
209
|
+
if (!val) return;
|
|
210
|
+
this.html = this.renderTextHtml(val);
|
|
211
|
+
this.renderResource();
|
|
212
|
+
},
|
|
213
|
+
},
|
|
178
214
|
},
|
|
179
|
-
},
|
|
180
215
|
};
|
|
181
216
|
</script>
|
|
182
217
|
|
|
183
|
-
<style>
|
|
184
|
-
</style>
|
|
218
|
+
<style></style>
|
package/src/Item.vue
CHANGED