@pixui-dev/pixui-richtext-helper 0.2.6-test.1 → 0.2.7
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/dist/richtext/RichTextCore.d.ts +6 -0
- package/dist/richtext/RichTextCore.js +105 -6
- package/package.json +1 -1
- package/readme.md +9 -1
|
@@ -24,10 +24,14 @@ export declare class RichTextCore {
|
|
|
24
24
|
* 富文本转换为 PixUI innerHTML 兼容格式
|
|
25
25
|
* @param str 原始富文本 HTML
|
|
26
26
|
* @param config 可选配置
|
|
27
|
+
* @param config.lineHeightScale 行高缩放比例
|
|
28
|
+
* @param config.convertPxToEm 是否转换px为em
|
|
29
|
+
* @param config.addCosUrlImageMogr2_w 添加cos url图片的mogr2_w参数,如果是cos的图片,可以使用这个配置设置图片宽度最大值。组件会增加参数为 xxx.jpg?imageMogr2/thumbnail/<width>x的参数。参数值取min(img节点样式宽度,addCosUrlImageMogr2_w)
|
|
27
30
|
*/
|
|
28
31
|
static convertRichTextToPixuiStyle(str: string, config?: {
|
|
29
32
|
lineHeightScale?: number;
|
|
30
33
|
convertPxToEm?: boolean;
|
|
34
|
+
addCosUrlImageMogr2_w?: number;
|
|
31
35
|
}): string;
|
|
32
36
|
/**
|
|
33
37
|
* 绑定链接点击事件
|
|
@@ -53,6 +57,8 @@ export declare class RichTextCore {
|
|
|
53
57
|
private static convertAllPxToEm;
|
|
54
58
|
private static preprocess;
|
|
55
59
|
private static fixImgSizeUnit;
|
|
60
|
+
/** 给 COS 图片自动追加 imageMogr2/thumbnail 参数 */
|
|
61
|
+
private static handleCosImageMogr2;
|
|
56
62
|
/** 列表处理(将 ol/ul/li 替换为 div 结构) */
|
|
57
63
|
private static handleLists;
|
|
58
64
|
/** 将连续 <br> 替换为透明占位文字,确保 PixUI 换行 */
|
|
@@ -143,12 +143,18 @@ var RichTextCore = /** @class */ (function () {
|
|
|
143
143
|
* 富文本转换为 PixUI innerHTML 兼容格式
|
|
144
144
|
* @param str 原始富文本 HTML
|
|
145
145
|
* @param config 可选配置
|
|
146
|
+
* @param config.lineHeightScale 行高缩放比例
|
|
147
|
+
* @param config.convertPxToEm 是否转换px为em
|
|
148
|
+
* @param config.addCosUrlImageMogr2_w 添加cos url图片的mogr2_w参数,如果是cos的图片,可以使用这个配置设置图片宽度最大值。组件会增加参数为 xxx.jpg?imageMogr2/thumbnail/<width>x的参数。参数值取min(img节点样式宽度,addCosUrlImageMogr2_w)
|
|
146
149
|
*/
|
|
147
150
|
RichTextCore.convertRichTextToPixuiStyle = function (str, config) {
|
|
148
151
|
// 重置全局状态
|
|
149
152
|
RichTextCore.linkNodes = [];
|
|
150
153
|
RichTextCore.hrefIdCnt = 0;
|
|
151
|
-
var
|
|
154
|
+
var preEncodedStr = str.replace(/href="([^"]*?)"/g, function (_match, hrefVal) {
|
|
155
|
+
return "href=\"".concat(encodeURIComponent(hrefVal), "\"");
|
|
156
|
+
});
|
|
157
|
+
var $1 = cheerio.load(preEncodedStr, null, false);
|
|
152
158
|
//检查html,如果有text节点,说明是转换过的,直接返回
|
|
153
159
|
if ($1("text").length > 0) {
|
|
154
160
|
return str;
|
|
@@ -171,9 +177,38 @@ var RichTextCore = /** @class */ (function () {
|
|
|
171
177
|
// 直接查询统一的 class
|
|
172
178
|
setTimeout(function () {
|
|
173
179
|
var elements = Array.from(document.querySelectorAll(".".concat(RichTextCore.LINK_NODE_CLASS)));
|
|
180
|
+
// HTML 实体解码工具函数(纯算法实现,避免依赖 textarea 节点)
|
|
181
|
+
var decodeHtmlEntities = function (str) {
|
|
182
|
+
if (!str)
|
|
183
|
+
return str;
|
|
184
|
+
var named = {
|
|
185
|
+
quot: '"',
|
|
186
|
+
amp: "&",
|
|
187
|
+
lt: "<",
|
|
188
|
+
gt: ">",
|
|
189
|
+
apos: "'",
|
|
190
|
+
};
|
|
191
|
+
return str.replace(/&(#(?:x[0-9a-fA-F]+|\d+)|[a-zA-Z]+);/g, function (_, ent) {
|
|
192
|
+
if (ent[0] === "#") {
|
|
193
|
+
// 数字实体
|
|
194
|
+
var isHex = ent[1].toLowerCase() === "x";
|
|
195
|
+
var numStr = isHex ? ent.slice(2) : ent.slice(1);
|
|
196
|
+
var codePoint = parseInt(numStr, isHex ? 16 : 10);
|
|
197
|
+
if (!isNaN(codePoint)) {
|
|
198
|
+
return String.fromCodePoint(codePoint);
|
|
199
|
+
}
|
|
200
|
+
return _; // 解析失败,原样返回
|
|
201
|
+
}
|
|
202
|
+
// 命名实体
|
|
203
|
+
if (named.hasOwnProperty(ent))
|
|
204
|
+
return named[ent];
|
|
205
|
+
return _; // 未知实体,原样返回
|
|
206
|
+
});
|
|
207
|
+
};
|
|
174
208
|
elements.forEach(function (el) {
|
|
175
209
|
var hrefEncoded = el.getAttribute("data-link-href") || "";
|
|
176
|
-
|
|
210
|
+
// 先 URI 解码,再做 HTML 实体解码
|
|
211
|
+
var href = decodeHtmlEntities(decodeURIComponent(hrefEncoded));
|
|
177
212
|
var typeStr = el.getAttribute("data-link-type");
|
|
178
213
|
var type = typeStr === LinkNodeType.IMG ? LinkNodeType.IMG : LinkNodeType.DIV;
|
|
179
214
|
// 避免重复绑定
|
|
@@ -257,8 +292,12 @@ var RichTextCore = /** @class */ (function () {
|
|
|
257
292
|
if (tagName === "div" || tagName === "text") {
|
|
258
293
|
return []; // 丢弃空 div / text
|
|
259
294
|
}
|
|
295
|
+
else if (tagName === "img") {
|
|
296
|
+
// img标签直接返回,不包装在div中
|
|
297
|
+
return [$.html(node)];
|
|
298
|
+
}
|
|
260
299
|
else {
|
|
261
|
-
//
|
|
300
|
+
// 其它空标签保留
|
|
262
301
|
return [wrapNode($elem, "")];
|
|
263
302
|
}
|
|
264
303
|
}
|
|
@@ -285,6 +324,7 @@ var RichTextCore = /** @class */ (function () {
|
|
|
285
324
|
// 按旧实现顺序进行处理,但重构为独立函数划分
|
|
286
325
|
this.preprocess($);
|
|
287
326
|
this.fixImgSizeUnit($);
|
|
327
|
+
this.handleCosImageMogr2($, config);
|
|
288
328
|
this.handleLists($, (config === null || config === void 0 ? void 0 : config.lineHeightScale) || 1);
|
|
289
329
|
this.replaceBrWithPlaceholder($);
|
|
290
330
|
this.handleAnchorTag($);
|
|
@@ -410,6 +450,64 @@ var RichTextCore = /** @class */ (function () {
|
|
|
410
450
|
}
|
|
411
451
|
});
|
|
412
452
|
};
|
|
453
|
+
/** 给 COS 图片自动追加 imageMogr2/thumbnail 参数 */
|
|
454
|
+
RichTextCore.handleCosImageMogr2 = function ($, config) {
|
|
455
|
+
var maxW = config === null || config === void 0 ? void 0 : config.addCosUrlImageMogr2_w;
|
|
456
|
+
if (!maxW)
|
|
457
|
+
return;
|
|
458
|
+
var extractNumber = function (str) {
|
|
459
|
+
if (!str)
|
|
460
|
+
return undefined;
|
|
461
|
+
var m = str.match(/(\d+(?:\.\d+)?)/);
|
|
462
|
+
if (m) {
|
|
463
|
+
var num = parseInt(m[1]);
|
|
464
|
+
if (!isNaN(num))
|
|
465
|
+
return num;
|
|
466
|
+
}
|
|
467
|
+
return undefined;
|
|
468
|
+
};
|
|
469
|
+
$("img").each(function () {
|
|
470
|
+
var src = $(this).attr("src") || "";
|
|
471
|
+
if (!src)
|
|
472
|
+
return;
|
|
473
|
+
// 已有 thumbnail 宽度
|
|
474
|
+
var thumbMatch = src.match(/imageMogr2\/thumbnail\/(\d+)x/i);
|
|
475
|
+
var existingThumbW = thumbMatch ? parseInt(thumbMatch[1]) : undefined;
|
|
476
|
+
// width 属性
|
|
477
|
+
var widthAttrW = extractNumber($(this).attr("width"));
|
|
478
|
+
// style width
|
|
479
|
+
var styleObj = parseStyleString($(this).attr("style") || "");
|
|
480
|
+
var styleWidthW = extractNumber(styleObj["width"]);
|
|
481
|
+
// 计算最小宽度
|
|
482
|
+
var candidates = [existingThumbW, widthAttrW, styleWidthW, maxW].filter(function (v) { return v !== undefined && v > 0; });
|
|
483
|
+
if (candidates.length === 0)
|
|
484
|
+
return; // 无可用宽度
|
|
485
|
+
var finalW = Math.min.apply(Math, candidates);
|
|
486
|
+
// 如果已存在 thumbnail 参数且宽度一致,无需处理
|
|
487
|
+
if (existingThumbW !== undefined) {
|
|
488
|
+
if (existingThumbW === finalW)
|
|
489
|
+
return;
|
|
490
|
+
// 替换为更小的宽度
|
|
491
|
+
src = src.replace(/imageMogr2\/thumbnail\/(\d+)x/i, "imageMogr2/thumbnail/".concat(finalW, "x"));
|
|
492
|
+
}
|
|
493
|
+
else {
|
|
494
|
+
// 未存在 thumbnail 参数,需要追加
|
|
495
|
+
var appendedParam = "imageMogr2/thumbnail/".concat(finalW, "x");
|
|
496
|
+
if (src.includes("?")) {
|
|
497
|
+
// 已有查询部分,使用 | 追加
|
|
498
|
+
if (!src.endsWith("|") && !src.endsWith("&") && !src.endsWith("?")) {
|
|
499
|
+
src += "|";
|
|
500
|
+
}
|
|
501
|
+
src += appendedParam;
|
|
502
|
+
}
|
|
503
|
+
else {
|
|
504
|
+
// 无查询部分,直接添加
|
|
505
|
+
src += "?".concat(appendedParam);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
$(this).attr("src", src);
|
|
509
|
+
});
|
|
510
|
+
};
|
|
413
511
|
/** 列表处理(将 ol/ul/li 替换为 div 结构) */
|
|
414
512
|
RichTextCore.handleLists = function ($, lineHeightScale) {
|
|
415
513
|
if (lineHeightScale === void 0) { lineHeightScale = 1; }
|
|
@@ -523,7 +621,7 @@ var RichTextCore = /** @class */ (function () {
|
|
|
523
621
|
mergedStyles.push(innerStyle);
|
|
524
622
|
});
|
|
525
623
|
var finalStyle = mergeStyles.apply(void 0, __spreadArray([originalStyle], mergedStyles, false));
|
|
526
|
-
var encodedHref = href
|
|
624
|
+
var encodedHref = href || ""; // 已在预处理阶段编码,避免二次编码
|
|
527
625
|
if (href) {
|
|
528
626
|
self.linkNodes.push({ type: LinkNodeType.DIV, href: href, id: id });
|
|
529
627
|
}
|
|
@@ -610,7 +708,7 @@ var RichTextCore = /** @class */ (function () {
|
|
|
610
708
|
self.linkNodes.push({ type: LinkNodeType.IMG, href: href, id: id });
|
|
611
709
|
}
|
|
612
710
|
// 将链接信息以转义形式保存在 data- 属性中,避免默认跳转
|
|
613
|
-
var encodedHref = href
|
|
711
|
+
var encodedHref = href || ""; // 已在预处理阶段编码,避免二次编码
|
|
614
712
|
$(this).attr("data-link-type", "img");
|
|
615
713
|
$(this).attr("data-link-href", encodedHref);
|
|
616
714
|
$(this).attr("href", "");
|
|
@@ -698,7 +796,8 @@ var RichTextCore = /** @class */ (function () {
|
|
|
698
796
|
var attribs = ($(node).get(0) || {}).attribs || {};
|
|
699
797
|
for (var _i = 0, _a = Object.entries(attribs); _i < _a.length; _i++) {
|
|
700
798
|
var _b = _a[_i], k = _b[0], v = _b[1];
|
|
701
|
-
|
|
799
|
+
// 跳过style、id和href属性,避免重复处理或错误处理
|
|
800
|
+
if (k !== "style" && k !== "id" && k !== "href") {
|
|
702
801
|
customAttrs += " ".concat(k, "=\"").concat(v, "\"");
|
|
703
802
|
}
|
|
704
803
|
}
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -95,4 +95,12 @@ componentDidMount() { // 在节点渲染后绑定点击事件
|
|
|
95
95
|
2. 修复在嵌套节点中加br不会被拆成不同段落的问题
|
|
96
96
|
|
|
97
97
|
0.2.5
|
|
98
|
-
1. 修复img节点丢失的问题
|
|
98
|
+
1. 修复img节点丢失的问题
|
|
99
|
+
|
|
100
|
+
0.2.6
|
|
101
|
+
1. 修复在超链接中添加转义符导致跳转信息不完整的问题
|
|
102
|
+
2. 修复带超链接的img节点中出现一些多余的属性
|
|
103
|
+
3. 增加将富文本中的px单位的属性统一替换为em单位的选项
|
|
104
|
+
|
|
105
|
+
0.2.7
|
|
106
|
+
1. 增加addCosUrlImageMogr2_w参数
|