@pixui-dev/pixui-richtext-helper 0.2.12-dev.2 → 0.2.12

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.
@@ -12,6 +12,20 @@ export interface LinkClickParams {
12
12
  href: string;
13
13
  id: string;
14
14
  }
15
+ /** 单个阶段耗时 */
16
+ export interface ConvertDebugPhase {
17
+ name: string;
18
+ ms: number;
19
+ }
20
+ /** 转换调试统计 */
21
+ export interface ConvertDebugStats {
22
+ totalMs: number;
23
+ highLevel: ConvertDebugPhase[];
24
+ detail: ConvertDebugPhase[];
25
+ segmentsCount: number;
26
+ version: string;
27
+ timestamp: number;
28
+ }
15
29
  /*****************************************************
16
30
  * RichTextCore 主类
17
31
  *****************************************************/
@@ -20,6 +34,8 @@ export declare class RichTextCore {
20
34
  private static hrefIdCnt;
21
35
  /** 所有链接节点统一的 class 名 */
22
36
  private static readonly LINK_NODE_CLASS;
37
+ /** 上一次转换的调试统计(仅在 debug 模式下填充) */
38
+ static lastDebugStats: ConvertDebugStats | undefined;
23
39
  /**
24
40
  * 富文本转换为 PixUI innerHTML 兼容格式
25
41
  * @param str 原始富文本 HTML
@@ -32,6 +48,8 @@ export declare class RichTextCore {
32
48
  lineHeightScale?: number;
33
49
  convertPxToEm?: boolean;
34
50
  addCosUrlImageMogr2_w?: number;
51
+ debug?: boolean;
52
+ onDebugStats?: (stats: ConvertDebugStats) => void;
35
53
  }): string;
36
54
  /**
37
55
  * 绑定链接点击事件
@@ -207,29 +207,85 @@ var RichTextCore = /** @class */ (function () {
207
207
  * @param config.addCosUrlImageMogr2_w 添加cos url图片的mogr2_w参数,如果是cos的图片,可以使用这个配置设置图片宽度最大值。组件会增加参数为 xxx.jpg?imageMogr2/thumbnail/<width>x的参数。参数值取min(img节点样式宽度,addCosUrlImageMogr2_w)
208
208
  */
209
209
  RichTextCore.convertRichTextToPixuiStyle = function (str, config) {
210
+ var debug = !!(config === null || config === void 0 ? void 0 : config.debug);
211
+ var now = function () { return Date.now(); };
212
+ var highLevelPhases = [];
213
+ var detailTotals = {};
214
+ var measure = function (name, fn) {
215
+ if (!debug)
216
+ return fn();
217
+ var s = now();
218
+ var r = fn();
219
+ var e = now();
220
+ highLevelPhases.push({ name: name, ms: e - s });
221
+ return r;
222
+ };
210
223
  // 重置全局状态
211
224
  RichTextCore.linkNodes = [];
212
225
  RichTextCore.hrefIdCnt = 0;
213
226
  // href 属性先统一做 URI 编码
214
- var preEncodedStr = str.replace(/href=(['"])(.*?)\1/g, function (_m, quote, hrefVal) {
215
- return "href=".concat(quote).concat(encodeURIComponent(hrefVal)).concat(quote);
216
- });
217
- var $1 = cheerio.load(preEncodedStr, null, false);
227
+ var preEncodedStr = measure("preEncodeHref", function () { return str.replace(/href=(["'])(.*?)\1/g, function (_m, quote, hrefVal) { return "href=".concat(quote).concat(encodeURIComponent(hrefVal)).concat(quote); }); });
228
+ var $1 = measure("cheerioLoad", function () { return cheerio.load(preEncodedStr, null, false); });
218
229
  //检查html,如果有text节点,说明是转换过的,直接返回
219
230
  if ($1("text").length > 0) {
231
+ if (debug) {
232
+ var stats = {
233
+ totalMs: highLevelPhases.reduce(function (a, b) { return a + b.ms; }, 0),
234
+ highLevel: highLevelPhases,
235
+ detail: Object.entries(detailTotals).map(function (_a) {
236
+ var name = _a[0], ms = _a[1];
237
+ return ({ name: name, ms: ms });
238
+ }),
239
+ segmentsCount: 0,
240
+ version: version_1.LIB_VERSION,
241
+ timestamp: now(),
242
+ };
243
+ RichTextCore.lastDebugStats = stats;
244
+ (config === null || config === void 0 ? void 0 : config.onDebugStats) && config.onDebugStats(stats);
245
+ }
220
246
  return str;
221
247
  }
222
248
  var oriNodeCount = $1("*").length;
223
249
  console.log("pixui-richHelper转换---- 版本:" + " " + version_1.LIB_VERSION + " " + " 原始节点数:" + oriNodeCount);
224
250
  // ---------- 第 1 步:段落分割(基础实现:根节点切分) ----------
225
- var segments = RichTextCore.splitIntoSegments($1);
251
+ var segments = measure("splitIntoSegments", function () { return RichTextCore.splitIntoSegments($1); });
226
252
  // ---------- 第 2/3 步:遍历 + 展平 ----------
227
253
  // 为保证兼容性,我们直接对 HTML 进行逐段处理并在内部构建 PixUI 结构。
228
254
  // 这样既保持分段概念,又可复用旧逻辑的稳定性。
229
- var processedSegments = segments.map(function (seg) { return RichTextCore.processSegment(seg, config); });
255
+ var processedSegments = measure("processSegments", function () {
256
+ return segments.map(function (seg) {
257
+ return RichTextCore.processSegment(seg, {
258
+ lineHeightScale: config === null || config === void 0 ? void 0 : config.lineHeightScale,
259
+ convertPxToEm: config === null || config === void 0 ? void 0 : config.convertPxToEm,
260
+ addCosUrlImageMogr2_w: config === null || config === void 0 ? void 0 : config.addCosUrlImageMogr2_w,
261
+ debug: debug,
262
+ debugTotals: detailTotals,
263
+ });
264
+ });
265
+ });
230
266
  // ---------- 第 4 步:拼装 ----------
231
- var Result = processedSegments.join("");
232
- console.log(Result);
267
+ var Result = measure("joinSegments", function () { return processedSegments.join(""); });
268
+ if (debug)
269
+ console.log(Result);
270
+ if (debug) {
271
+ var detailList = Object.entries(detailTotals)
272
+ .map(function (_a) {
273
+ var name = _a[0], ms = _a[1];
274
+ return ({ name: name, ms: ms });
275
+ })
276
+ .sort(function (a, b) { return b.ms - a.ms; });
277
+ var totalMs = highLevelPhases.reduce(function (a, b) { return a + b.ms; }, 0);
278
+ var stats = {
279
+ totalMs: totalMs,
280
+ highLevel: highLevelPhases,
281
+ detail: detailList,
282
+ segmentsCount: segments.length,
283
+ version: version_1.LIB_VERSION,
284
+ timestamp: now(),
285
+ };
286
+ RichTextCore.lastDebugStats = stats;
287
+ (config === null || config === void 0 ? void 0 : config.onDebugStats) && config.onDebugStats(stats);
288
+ }
233
289
  return Result;
234
290
  };
235
291
  /**
@@ -382,58 +438,73 @@ var RichTextCore = /** @class */ (function () {
382
438
  * 处理单个段落片段,返回转换后的片段 HTML
383
439
  */
384
440
  RichTextCore.processSegment = function (segmentHtml, config) {
441
+ var _this = this;
442
+ var debug = !!(config === null || config === void 0 ? void 0 : config.debug);
443
+ var totals = config === null || config === void 0 ? void 0 : config.debugTotals;
444
+ var now = function () { return Date.now(); };
445
+ var time = function (name, fn) {
446
+ if (!debug)
447
+ return fn();
448
+ var s = now();
449
+ fn();
450
+ var e = now();
451
+ if (totals)
452
+ totals[name] = (totals[name] || 0) + (e - s);
453
+ };
385
454
  var $ = cheerio.load(segmentHtml, null, false);
386
455
  // 预处理:data-list → class、class → style、标题后补 <br>、margin→padding 合并
387
- this.preprocess($);
456
+ time("preprocess", function () { return _this.preprocess($); });
388
457
  // 规范图片尺寸单位:img 的 width/height 数字补 px
389
- this.fixImgSizeUnit($);
458
+ time("fixImgSizeUnit", function () { return _this.fixImgSizeUnit($); });
390
459
  // COS 图片缩略参数:按最小可用宽度收敛/追加 imageMogr2/thumbnail/<w>x
391
- this.handleCosImageMogr2($, config);
460
+ time("handleCosImageMogr2", function () { return _this.handleCosImageMogr2($, config); });
392
461
  // 合并img的width,height属性到 style,属性存在以 style 优先,移除 width/height 属性
393
- this.consolidateImgSizeStyle($);
462
+ time("consolidateImgSizeStyle", function () { return _this.consolidateImgSizeStyle($); });
394
463
  // 列表规范化:ol/ul/li 转三列布局(缩进/标号/文本),保留缩进与方向。节点结构:段落div(缩进key节点、标号key节点、text节点区域)
395
- this.handleLists($, (config === null || config === void 0 ? void 0 : config.lineHeightScale) || 1);
464
+ time("handleLists", function () { return _this.handleLists($, (config === null || config === void 0 ? void 0 : config.lineHeightScale) || 1); });
396
465
  // 换行处理:<br> → 透明占位 div,确保 PixUI 内正确换行
397
- this.replaceBrWithPlaceholder($);
466
+ time("replaceBrWithPlaceholder", function () { return _this.replaceBrWithPlaceholder($); });
398
467
  // 超链接:<a> → 可点击的 div,汇聚子样式并记录 data-link-*
399
- this.handleAnchorTag($);
468
+ time("handleAnchorTag", function () { return _this.handleAnchorTag($); });
400
469
  // 文本包装:将普通文本包入 <text>(跳过列表/链接/换行占位)
401
- this.wrapTextNodes($);
470
+ time("wrapTextNodes", function () { return _this.wrapTextNodes($); });
402
471
  // 样式标签:strong/em/u/s/span → 文本节点(列表文本列下改为 <key>)
403
- this.replaceStyleTags($);
472
+ time("replaceStyleTags", function () { return _this.replaceStyleTags($); });
404
473
  // 列表文本列规范化:裸文本统一包裹为 <key>,清理空白
405
- this.normalizeListItemPlainTextToKey($);
474
+ time("normalizeListItemPlainTextToKey", function () { return _this.normalizeListItemPlainTextToKey($); });
406
475
  // 段落:<p> → <div>,补 flex-shrink 与 width:100%
407
- this.replacePTag($);
476
+ time("replacePTag", function () { return _this.replacePTag($); });
408
477
  // 图片链接:img 的 href 转移至 data-link-href,并登记点击节点
409
- this.handleImgHref($);
478
+ time("handleImgHref", function () { return _this.handleImgHref($); });
410
479
  // 防收缩:常见块级元素补 flex-shrink:0(不作用于列表项)
411
- this.addFlexShrink($);
480
+ time("addFlexShrink", function () { return _this.addFlexShrink($); });
412
481
  // 扁平化:合并 text 样式并去掉嵌套的父 <text>
413
- this.flattenNestedText($);
482
+ time("flattenNestedText", function () { return _this.flattenNestedText($); });
414
483
  // 同级文本:拆分为 <key> 片段并统一包入父 <text>
415
- this.convertSiblingTextToDiv($);
484
+ time("convertSiblingTextToDiv", function () { return _this.convertSiblingTextToDiv($); });
416
485
  // 首行缩进:text-indent 转透明占位
417
- this.handleTextIndent($);
486
+ time("handleTextIndent", function () { return _this.handleTextIndent($); });
418
487
  // 行高与字间距:聚合到父 <text> 并按配置缩放 line-height
419
- this.adjustLineHeightAndLetterSpacing($, config);
488
+ time("adjustLineHeightAndLetterSpacing", function () { return _this.adjustLineHeightAndLetterSpacing($, config); });
420
489
  // 文本对齐与方向:从 div 下沉至子 <text>
421
- this.transferTextAlign($);
490
+ time("transferTextAlign", function () { return _this.transferTextAlign($); });
422
491
  // 清理空 <text>
423
- this.removeEmptyText($);
492
+ time("removeEmptyText", function () { return _this.removeEmptyText($); });
424
493
  // this.fixHeadingFontSize($);
425
494
  // 最后:修正 img 结束标签、nbsp
426
495
  var res = $.html();
427
- res = res
428
- .replaceAll(/<img([^>]+)>/g, "<img$1 />")
429
- .replaceAll(/&nbsp;/g, " ")
430
- .replaceAll(/&amp;/g, "&")
431
- .replaceAll(/&quot;/g, '"')
432
- .replaceAll("\"", "\"");
433
- // 统一进行px到em转换
434
- if (config === null || config === void 0 ? void 0 : config.convertPxToEm) {
435
- res = this.convertAllPxToEm(res);
436
- }
496
+ time("finalizeHtmlCleanup", function () {
497
+ res = res
498
+ .replaceAll(/<img([^>]+)>/g, "<img$1 />")
499
+ .replaceAll(/&nbsp;/g, " ")
500
+ .replaceAll(/&amp;/g, "&")
501
+ .replaceAll(/&quot;/g, '"')
502
+ .replaceAll("\"", '"');
503
+ // 统一进行px到em转换
504
+ if (config === null || config === void 0 ? void 0 : config.convertPxToEm) {
505
+ res = _this.convertAllPxToEm(res);
506
+ }
507
+ });
437
508
  return res;
438
509
  };
439
510
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixui-dev/pixui-richtext-helper",
3
- "version": "0.2.12-dev.2",
3
+ "version": "0.2.12",
4
4
  "description": "pixui richtext helper",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/readme.md CHANGED
@@ -140,3 +140,8 @@ componentDidMount() { // 在节点渲染后绑定点击事件
140
140
  1. 修复图片原始尺寸和样式尺寸不一样,某些pixui版本尺寸不对的问题
141
141
  2. 修复direction属性不生效的问题
142
142
  3. text节点下的文本节点从div标签改为pixui推荐的key标签
143
+
144
+ 0.2.12
145
+
146
+ 1. 适配阿语从右到左的布局
147
+ 2. 适配列表相关样式