parser.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989
  1. "use strict";
  2. const common_vendor = require("../../../../common/vendor.js");
  3. const config = {
  4. // 信任的标签(保持标签名不变)
  5. trustTags: makeMap("a,abbr,ad,audio,b,blockquote,br,code,col,colgroup,dd,del,dl,dt,div,em,fieldset,h1,h2,h3,h4,h5,h6,hr,i,img,ins,label,legend,li,ol,p,q,ruby,rt,source,span,strong,sub,sup,table,tbody,td,tfoot,th,thead,tr,title,ul,video"),
  6. // 块级标签(转为 div,其他的非信任标签转为 span)
  7. blockTags: makeMap("address,article,aside,body,caption,center,cite,footer,header,html,nav,pre,section"),
  8. // 行内标签
  9. inlineTags: makeMap("abbr,b,big,code,del,em,i,ins,label,q,small,span,strong,sub,sup"),
  10. // 要移除的标签
  11. ignoreTags: makeMap("area,base,canvas,embed,frame,head,iframe,input,link,map,meta,param,rp,script,source,style,textarea,title,track,wbr"),
  12. // 自闭合的标签
  13. voidTags: makeMap("area,base,br,col,circle,ellipse,embed,frame,hr,img,input,line,link,meta,param,path,polygon,rect,source,track,use,wbr"),
  14. // html 实体
  15. entities: {
  16. lt: "<",
  17. gt: ">",
  18. quot: '"',
  19. apos: "'",
  20. ensp: " ",
  21. emsp: " ",
  22. nbsp: " ",
  23. semi: ";",
  24. ndash: "–",
  25. mdash: "—",
  26. middot: "·",
  27. lsquo: "‘",
  28. rsquo: "’",
  29. ldquo: "“",
  30. rdquo: "”",
  31. bull: "•",
  32. hellip: "…",
  33. larr: "←",
  34. uarr: "↑",
  35. rarr: "→",
  36. darr: "↓"
  37. },
  38. // 默认的标签样式
  39. tagStyle: {
  40. address: "font-style:italic",
  41. big: "display:inline;font-size:1.2em",
  42. caption: "display:table-caption;text-align:center",
  43. center: "text-align:center",
  44. cite: "font-style:italic",
  45. dd: "margin-left:40px",
  46. mark: "background-color:yellow",
  47. pre: "font-family:monospace;white-space:pre",
  48. s: "text-decoration:line-through",
  49. small: "display:inline;font-size:0.8em",
  50. strike: "text-decoration:line-through",
  51. u: "text-decoration:underline"
  52. },
  53. // svg 大小写对照表
  54. svgDict: {
  55. animatetransform: "animateTransform",
  56. lineargradient: "linearGradient",
  57. viewbox: "viewBox",
  58. attributename: "attributeName",
  59. repeatcount: "repeatCount",
  60. repeatdur: "repeatDur"
  61. }
  62. };
  63. const tagSelector = {};
  64. const {
  65. windowWidth,
  66. system
  67. } = common_vendor.index.getSystemInfoSync();
  68. const blankChar = makeMap(" ,\r,\n, ,\f");
  69. let idIndex = 0;
  70. function makeMap(str) {
  71. const map = /* @__PURE__ */ Object.create(null);
  72. const list = str.split(",");
  73. for (let i = list.length; i--; ) {
  74. map[list[i]] = true;
  75. }
  76. return map;
  77. }
  78. function decodeEntity(str, amp) {
  79. let i = str.indexOf("&");
  80. while (i !== -1) {
  81. const j = str.indexOf(";", i + 3);
  82. let code;
  83. if (j === -1)
  84. break;
  85. if (str[i + 1] === "#") {
  86. code = parseInt((str[i + 2] === "x" ? "0" : "") + str.substring(i + 2, j));
  87. if (!isNaN(code)) {
  88. str = str.substr(0, i) + String.fromCharCode(code) + str.substr(j + 1);
  89. }
  90. } else {
  91. code = str.substring(i + 1, j);
  92. if (config.entities[code] || code === "amp" && amp) {
  93. str = str.substr(0, i) + (config.entities[code] || "&") + str.substr(j + 1);
  94. }
  95. }
  96. i = str.indexOf("&", i + 1);
  97. }
  98. return str;
  99. }
  100. function mergeNodes(nodes) {
  101. let i = nodes.length - 1;
  102. for (let j = i; j >= -1; j--) {
  103. if (j === -1 || nodes[j].c || !nodes[j].name || nodes[j].name !== "div" && nodes[j].name !== "p" && nodes[j].name[0] !== "h" || (nodes[j].attrs.style || "").includes("inline")) {
  104. if (i - j >= 5) {
  105. nodes.splice(j + 1, i - j, {
  106. name: "div",
  107. attrs: {},
  108. children: nodes.slice(j + 1, i + 1)
  109. });
  110. }
  111. i = j - 1;
  112. }
  113. }
  114. }
  115. function Parser(vm) {
  116. this.options = vm || {};
  117. this.tagStyle = Object.assign({}, config.tagStyle, this.options.tagStyle);
  118. this.imgList = vm.imgList || [];
  119. this.imgList._unloadimgs = 0;
  120. this.plugins = vm.plugins || [];
  121. this.attrs = /* @__PURE__ */ Object.create(null);
  122. this.stack = [];
  123. this.nodes = [];
  124. this.pre = (this.options.containerStyle || "").includes("white-space") && this.options.containerStyle.includes("pre") ? 2 : 0;
  125. }
  126. Parser.prototype.parse = function(content) {
  127. for (let i = this.plugins.length; i--; ) {
  128. if (this.plugins[i].onUpdate) {
  129. content = this.plugins[i].onUpdate(content, config) || content;
  130. }
  131. }
  132. new Lexer(this).parse(content);
  133. while (this.stack.length) {
  134. this.popNode();
  135. }
  136. if (this.nodes.length > 50) {
  137. mergeNodes(this.nodes);
  138. }
  139. return this.nodes;
  140. };
  141. Parser.prototype.expose = function() {
  142. for (let i = this.stack.length; i--; ) {
  143. const item = this.stack[i];
  144. if (item.c || item.name === "a" || item.name === "video" || item.name === "audio")
  145. return;
  146. item.c = 1;
  147. }
  148. };
  149. Parser.prototype.hook = function(node) {
  150. for (let i = this.plugins.length; i--; ) {
  151. if (this.plugins[i].onParse && this.plugins[i].onParse(node, this) === false) {
  152. return false;
  153. }
  154. }
  155. return true;
  156. };
  157. Parser.prototype.getUrl = function(url) {
  158. const domain = this.options.domain;
  159. if (url[0] === "/") {
  160. if (url[1] === "/") {
  161. url = (domain ? domain.split("://")[0] : "http") + ":" + url;
  162. } else if (domain) {
  163. url = domain + url;
  164. }
  165. } else if (!url.includes("data:") && !url.includes("://")) {
  166. if (domain) {
  167. url = domain + "/" + url;
  168. }
  169. }
  170. return url;
  171. };
  172. Parser.prototype.parseStyle = function(node) {
  173. const attrs = node.attrs;
  174. const list = (this.tagStyle[node.name] || "").split(";").concat((attrs.style || "").split(";"));
  175. const styleObj = {};
  176. let tmp = "";
  177. if (attrs.id && !this.xml) {
  178. if (this.options.useAnchor) {
  179. this.expose();
  180. } else if (node.name !== "img" && node.name !== "a" && node.name !== "video" && node.name !== "audio") {
  181. attrs.id = void 0;
  182. }
  183. }
  184. if (attrs.width) {
  185. styleObj.width = parseFloat(attrs.width) + (attrs.width.includes("%") ? "%" : "px");
  186. attrs.width = void 0;
  187. }
  188. if (attrs.height) {
  189. styleObj.height = parseFloat(attrs.height) + (attrs.height.includes("%") ? "%" : "px");
  190. attrs.height = void 0;
  191. }
  192. for (let i = 0, len = list.length; i < len; i++) {
  193. const info = list[i].split(":");
  194. if (info.length < 2)
  195. continue;
  196. const key = info.shift().trim().toLowerCase();
  197. let value = info.join(":").trim();
  198. if (value[0] === "-" && value.lastIndexOf("-") > 0 || value.includes("safe")) {
  199. tmp += `;${key}:${value}`;
  200. } else if (!styleObj[key] || value.includes("import") || !styleObj[key].includes("import")) {
  201. if (value.includes("url")) {
  202. let j = value.indexOf("(") + 1;
  203. if (j) {
  204. while (value[j] === '"' || value[j] === "'" || blankChar[value[j]]) {
  205. j++;
  206. }
  207. value = value.substr(0, j) + this.getUrl(value.substr(j));
  208. }
  209. } else if (value.includes("rpx")) {
  210. value = value.replace(/[0-9.]+\s*rpx/g, ($) => parseFloat($) * windowWidth / 750 + "px");
  211. }
  212. styleObj[key] = value;
  213. }
  214. }
  215. node.attrs.style = tmp;
  216. return styleObj;
  217. };
  218. Parser.prototype.onTagName = function(name) {
  219. this.tagName = this.xml ? name : name.toLowerCase();
  220. if (this.tagName === "svg") {
  221. this.xml = (this.xml || 0) + 1;
  222. }
  223. };
  224. Parser.prototype.onAttrName = function(name) {
  225. name = this.xml ? name : name.toLowerCase();
  226. if (name.substr(0, 5) === "data-") {
  227. if (name === "data-src" && !this.attrs.src) {
  228. this.attrName = "src";
  229. } else if (this.tagName === "img" || this.tagName === "a") {
  230. this.attrName = name;
  231. } else {
  232. this.attrName = void 0;
  233. }
  234. } else {
  235. this.attrName = name;
  236. this.attrs[name] = "T";
  237. }
  238. };
  239. Parser.prototype.onAttrVal = function(val) {
  240. const name = this.attrName || "";
  241. if (name === "style" || name === "href") {
  242. this.attrs[name] = decodeEntity(val, true);
  243. } else if (name.includes("src")) {
  244. this.attrs[name] = this.getUrl(decodeEntity(val, true));
  245. } else if (name) {
  246. this.attrs[name] = val;
  247. }
  248. };
  249. Parser.prototype.onOpenTag = function(selfClose) {
  250. const node = /* @__PURE__ */ Object.create(null);
  251. node.name = this.tagName;
  252. node.attrs = this.attrs;
  253. if (this.options.nodes.length) {
  254. node.type = "node";
  255. }
  256. this.attrs = /* @__PURE__ */ Object.create(null);
  257. const attrs = node.attrs;
  258. const parent = this.stack[this.stack.length - 1];
  259. const siblings = parent ? parent.children : this.nodes;
  260. const close = this.xml ? selfClose : config.voidTags[node.name];
  261. if (tagSelector[node.name]) {
  262. attrs.class = tagSelector[node.name] + (attrs.class ? " " + attrs.class : "");
  263. }
  264. if (node.name === "embed") {
  265. const src = attrs.src || "";
  266. if (src.includes(".mp4") || src.includes(".3gp") || src.includes(".m3u8") || (attrs.type || "").includes("video")) {
  267. node.name = "video";
  268. } else if (src.includes(".mp3") || src.includes(".wav") || src.includes(".aac") || src.includes(".m4a") || (attrs.type || "").includes("audio")) {
  269. node.name = "audio";
  270. }
  271. if (attrs.autostart) {
  272. attrs.autoplay = "T";
  273. }
  274. attrs.controls = "T";
  275. }
  276. if (node.name === "video" || node.name === "audio") {
  277. if (node.name === "video" && !attrs.id) {
  278. attrs.id = "v" + idIndex++;
  279. }
  280. if (!attrs.controls && !attrs.autoplay) {
  281. attrs.controls = "T";
  282. }
  283. node.src = [];
  284. if (attrs.src) {
  285. node.src.push(attrs.src);
  286. attrs.src = void 0;
  287. }
  288. this.expose();
  289. }
  290. if (close) {
  291. if (!this.hook(node) || config.ignoreTags[node.name]) {
  292. if (node.name === "base" && !this.options.domain) {
  293. this.options.domain = attrs.href;
  294. } else if (node.name === "source" && parent && (parent.name === "video" || parent.name === "audio") && attrs.src) {
  295. parent.src.push(attrs.src);
  296. }
  297. return;
  298. }
  299. const styleObj = this.parseStyle(node);
  300. if (node.name === "img") {
  301. if (attrs.src) {
  302. if (attrs.src.includes("webp")) {
  303. node.webp = "T";
  304. }
  305. if (attrs.src.includes("data:") && !attrs["original-src"]) {
  306. attrs.ignore = "T";
  307. }
  308. if (!attrs.ignore || node.webp || attrs.src.includes("cloud://")) {
  309. for (let i = this.stack.length; i--; ) {
  310. const item = this.stack[i];
  311. if (item.name === "a") {
  312. node.a = item.attrs;
  313. }
  314. if (item.name === "table" && !node.webp && !attrs.src.includes("cloud://")) {
  315. if (!styleObj.display || styleObj.display.includes("inline")) {
  316. node.t = "inline-block";
  317. } else {
  318. node.t = styleObj.display;
  319. }
  320. styleObj.display = void 0;
  321. }
  322. const style = item.attrs.style || "";
  323. if (style.includes("flex:") && !style.includes("flex:0") && !style.includes("flex: 0") && (!styleObj.width || parseInt(styleObj.width) > 100)) {
  324. styleObj.width = "100% !important";
  325. styleObj.height = "";
  326. for (let j = i + 1; j < this.stack.length; j++) {
  327. this.stack[j].attrs.style = (this.stack[j].attrs.style || "").replace("inline-", "");
  328. }
  329. } else if (style.includes("flex") && styleObj.width === "100%") {
  330. for (let j = i + 1; j < this.stack.length; j++) {
  331. const style2 = this.stack[j].attrs.style || "";
  332. if (!style2.includes(";width") && !style2.includes(" width") && style2.indexOf("width") !== 0) {
  333. styleObj.width = "";
  334. break;
  335. }
  336. }
  337. } else if (style.includes("inline-block")) {
  338. if (styleObj.width && styleObj.width[styleObj.width.length - 1] === "%") {
  339. item.attrs.style += ";max-width:" + styleObj.width;
  340. styleObj.width = "";
  341. } else {
  342. item.attrs.style += ";max-width:100%";
  343. }
  344. }
  345. item.c = 1;
  346. }
  347. attrs.i = this.imgList.length.toString();
  348. let src = attrs["original-src"] || attrs.src;
  349. if (this.imgList.includes(src)) {
  350. let i = src.indexOf("://");
  351. if (i !== -1) {
  352. i += 3;
  353. let newSrc = src.substr(0, i);
  354. for (; i < src.length; i++) {
  355. if (src[i] === "/")
  356. break;
  357. newSrc += Math.random() > 0.5 ? src[i].toUpperCase() : src[i];
  358. }
  359. newSrc += src.substr(i);
  360. src = newSrc;
  361. }
  362. }
  363. this.imgList.push(src);
  364. if (!node.t) {
  365. this.imgList._unloadimgs += 1;
  366. }
  367. }
  368. }
  369. if (styleObj.display === "inline") {
  370. styleObj.display = "";
  371. }
  372. if (attrs.ignore) {
  373. styleObj["max-width"] = styleObj["max-width"] || "100%";
  374. attrs.style += ";-webkit-touch-callout:none";
  375. }
  376. if (parseInt(styleObj.width) > windowWidth) {
  377. styleObj.height = void 0;
  378. }
  379. if (!isNaN(parseInt(styleObj.width))) {
  380. node.w = "T";
  381. }
  382. if (!isNaN(parseInt(styleObj.height)) && (!styleObj.height.includes("%") || parent && (parent.attrs.style || "").includes("height"))) {
  383. node.h = "T";
  384. }
  385. } else if (node.name === "svg") {
  386. siblings.push(node);
  387. this.stack.push(node);
  388. this.popNode();
  389. return;
  390. }
  391. for (const key in styleObj) {
  392. if (styleObj[key]) {
  393. attrs.style += `;${key}:${styleObj[key].replace(" !important", "")}`;
  394. }
  395. }
  396. attrs.style = attrs.style.substr(1) || void 0;
  397. if (!attrs.style) {
  398. delete attrs.style;
  399. }
  400. } else {
  401. if ((node.name === "pre" || (attrs.style || "").includes("white-space") && attrs.style.includes("pre")) && this.pre !== 2) {
  402. this.pre = node.pre = 1;
  403. }
  404. node.children = [];
  405. this.stack.push(node);
  406. }
  407. siblings.push(node);
  408. };
  409. Parser.prototype.onCloseTag = function(name) {
  410. name = this.xml ? name : name.toLowerCase();
  411. let i;
  412. for (i = this.stack.length; i--; ) {
  413. if (this.stack[i].name === name)
  414. break;
  415. }
  416. if (i !== -1) {
  417. while (this.stack.length > i) {
  418. this.popNode();
  419. }
  420. } else if (name === "p" || name === "br") {
  421. const siblings = this.stack.length ? this.stack[this.stack.length - 1].children : this.nodes;
  422. siblings.push({
  423. name,
  424. attrs: {
  425. class: tagSelector[name] || "",
  426. style: this.tagStyle[name] || ""
  427. }
  428. });
  429. }
  430. };
  431. Parser.prototype.popNode = function() {
  432. const node = this.stack.pop();
  433. let attrs = node.attrs;
  434. const children = node.children;
  435. const parent = this.stack[this.stack.length - 1];
  436. const siblings = parent ? parent.children : this.nodes;
  437. if (!this.hook(node) || config.ignoreTags[node.name]) {
  438. if (node.name === "title" && children.length && children[0].type === "text" && this.options.setTitle) {
  439. common_vendor.index.setNavigationBarTitle({
  440. title: children[0].text
  441. });
  442. }
  443. siblings.pop();
  444. return;
  445. }
  446. if (node.pre && this.pre !== 2) {
  447. this.pre = node.pre = void 0;
  448. for (let i = this.stack.length; i--; ) {
  449. if (this.stack[i].pre) {
  450. this.pre = 1;
  451. }
  452. }
  453. }
  454. const styleObj = {};
  455. if (node.name === "svg") {
  456. if (this.xml > 1) {
  457. this.xml--;
  458. return;
  459. }
  460. let src = "";
  461. const style = attrs.style;
  462. attrs.style = "";
  463. attrs.xmlns = "http://www.w3.org/2000/svg";
  464. (function traversal(node2) {
  465. if (node2.type === "text") {
  466. src += node2.text;
  467. return;
  468. }
  469. const name = config.svgDict[node2.name] || node2.name;
  470. src += "<" + name;
  471. for (const item in node2.attrs) {
  472. const val = node2.attrs[item];
  473. if (val) {
  474. src += ` ${config.svgDict[item] || item}="${val}"`;
  475. }
  476. }
  477. if (!node2.children) {
  478. src += "/>";
  479. } else {
  480. src += ">";
  481. for (let i = 0; i < node2.children.length; i++) {
  482. traversal(node2.children[i]);
  483. }
  484. src += "</" + name + ">";
  485. }
  486. })(node);
  487. node.name = "img";
  488. node.attrs = {
  489. src: "data:image/svg+xml;utf8," + src.replace(/#/g, "%23"),
  490. style,
  491. ignore: "T"
  492. };
  493. node.children = void 0;
  494. this.xml = false;
  495. return;
  496. }
  497. if (attrs.align) {
  498. if (node.name === "table") {
  499. if (attrs.align === "center") {
  500. styleObj["margin-inline-start"] = styleObj["margin-inline-end"] = "auto";
  501. } else {
  502. styleObj.float = attrs.align;
  503. }
  504. } else {
  505. styleObj["text-align"] = attrs.align;
  506. }
  507. attrs.align = void 0;
  508. }
  509. if (attrs.dir) {
  510. styleObj.direction = attrs.dir;
  511. attrs.dir = void 0;
  512. }
  513. if (node.name === "font") {
  514. if (attrs.color) {
  515. styleObj.color = attrs.color;
  516. attrs.color = void 0;
  517. }
  518. if (attrs.face) {
  519. styleObj["font-family"] = attrs.face;
  520. attrs.face = void 0;
  521. }
  522. if (attrs.size) {
  523. let size = parseInt(attrs.size);
  524. if (!isNaN(size)) {
  525. if (size < 1) {
  526. size = 1;
  527. } else if (size > 7) {
  528. size = 7;
  529. }
  530. styleObj["font-size"] = ["x-small", "small", "medium", "large", "x-large", "xx-large", "xxx-large"][size - 1];
  531. }
  532. attrs.size = void 0;
  533. }
  534. }
  535. if ((attrs.class || "").includes("align-center")) {
  536. styleObj["text-align"] = "center";
  537. }
  538. Object.assign(styleObj, this.parseStyle(node));
  539. if (node.name !== "table" && parseInt(styleObj.width) > windowWidth) {
  540. styleObj["max-width"] = "100%";
  541. styleObj["box-sizing"] = "border-box";
  542. }
  543. if (config.blockTags[node.name]) {
  544. node.name = "div";
  545. } else if (!config.trustTags[node.name] && !this.xml) {
  546. node.name = "span";
  547. }
  548. if (node.name === "a" || node.name === "ad") {
  549. this.expose();
  550. } else if (node.name === "video") {
  551. if ((styleObj.height || "").includes("auto")) {
  552. styleObj.height = void 0;
  553. }
  554. } else if ((node.name === "ul" || node.name === "ol") && node.c) {
  555. const types = {
  556. a: "lower-alpha",
  557. A: "upper-alpha",
  558. i: "lower-roman",
  559. I: "upper-roman"
  560. };
  561. if (types[attrs.type]) {
  562. attrs.style += ";list-style-type:" + types[attrs.type];
  563. attrs.type = void 0;
  564. }
  565. for (let i = children.length; i--; ) {
  566. if (children[i].name === "li") {
  567. children[i].c = 1;
  568. }
  569. }
  570. } else if (node.name === "table") {
  571. let padding = parseFloat(attrs.cellpadding);
  572. let spacing = parseFloat(attrs.cellspacing);
  573. const border = parseFloat(attrs.border);
  574. const bordercolor = styleObj["border-color"];
  575. const borderstyle = styleObj["border-style"];
  576. if (node.c) {
  577. if (isNaN(padding)) {
  578. padding = 2;
  579. }
  580. if (isNaN(spacing)) {
  581. spacing = 2;
  582. }
  583. }
  584. if (border) {
  585. attrs.style += `;border:${border}px ${borderstyle || "solid"} ${bordercolor || "gray"}`;
  586. }
  587. if (node.flag && node.c) {
  588. styleObj.display = "grid";
  589. if (spacing) {
  590. styleObj["grid-gap"] = spacing + "px";
  591. styleObj.padding = spacing + "px";
  592. } else if (border) {
  593. attrs.style += ";border-left:0;border-top:0";
  594. }
  595. const width = [];
  596. const trList = [];
  597. const cells = [];
  598. const map = {};
  599. (function traversal(nodes) {
  600. for (let i = 0; i < nodes.length; i++) {
  601. if (nodes[i].name === "tr") {
  602. trList.push(nodes[i]);
  603. } else {
  604. traversal(nodes[i].children || []);
  605. }
  606. }
  607. })(children);
  608. for (let row = 1; row <= trList.length; row++) {
  609. let col = 1;
  610. for (let j = 0; j < trList[row - 1].children.length; j++) {
  611. const td = trList[row - 1].children[j];
  612. if (td.name === "td" || td.name === "th") {
  613. while (map[row + "." + col]) {
  614. col++;
  615. }
  616. let style = td.attrs.style || "";
  617. let start = style.indexOf("width") ? style.indexOf(";width") : 0;
  618. if (start !== -1) {
  619. let end = style.indexOf(";", start + 6);
  620. if (end === -1) {
  621. end = style.length;
  622. }
  623. if (!td.attrs.colspan) {
  624. width[col] = style.substring(start ? start + 7 : 6, end);
  625. }
  626. style = style.substr(0, start) + style.substr(end);
  627. }
  628. style += ";display:flex";
  629. start = style.indexOf("vertical-align");
  630. if (start !== -1) {
  631. const val = style.substr(start + 15, 10);
  632. if (val.includes("middle")) {
  633. style += ";align-items:center";
  634. } else if (val.includes("bottom")) {
  635. style += ";align-items:flex-end";
  636. }
  637. } else {
  638. style += ";align-items:center";
  639. }
  640. start = style.indexOf("text-align");
  641. if (start !== -1) {
  642. const val = style.substr(start + 11, 10);
  643. if (val.includes("center")) {
  644. style += ";justify-content: center";
  645. } else if (val.includes("right")) {
  646. style += ";justify-content: right";
  647. }
  648. }
  649. style = (border ? `;border:${border}px ${borderstyle || "solid"} ${bordercolor || "gray"}` + (spacing ? "" : ";border-right:0;border-bottom:0") : "") + (padding ? `;padding:${padding}px` : "") + ";" + style;
  650. if (td.attrs.colspan) {
  651. style += `;grid-column-start:${col};grid-column-end:${col + parseInt(td.attrs.colspan)}`;
  652. if (!td.attrs.rowspan) {
  653. style += `;grid-row-start:${row};grid-row-end:${row + 1}`;
  654. }
  655. col += parseInt(td.attrs.colspan) - 1;
  656. }
  657. if (td.attrs.rowspan) {
  658. style += `;grid-row-start:${row};grid-row-end:${row + parseInt(td.attrs.rowspan)}`;
  659. if (!td.attrs.colspan) {
  660. style += `;grid-column-start:${col};grid-column-end:${col + 1}`;
  661. }
  662. for (let rowspan = 1; rowspan < td.attrs.rowspan; rowspan++) {
  663. for (let colspan = 0; colspan < (td.attrs.colspan || 1); colspan++) {
  664. map[row + rowspan + "." + (col - colspan)] = 1;
  665. }
  666. }
  667. }
  668. if (style) {
  669. td.attrs.style = style;
  670. }
  671. cells.push(td);
  672. col++;
  673. }
  674. }
  675. if (row === 1) {
  676. let temp = "";
  677. for (let i = 1; i < col; i++) {
  678. temp += (width[i] ? width[i] : "auto") + " ";
  679. }
  680. styleObj["grid-template-columns"] = temp;
  681. }
  682. }
  683. node.children = cells;
  684. } else {
  685. if (node.c) {
  686. styleObj.display = "table";
  687. }
  688. if (!isNaN(spacing)) {
  689. styleObj["border-spacing"] = spacing + "px";
  690. }
  691. if (border || padding) {
  692. (function traversal(nodes) {
  693. for (let i = 0; i < nodes.length; i++) {
  694. const td = nodes[i];
  695. if (td.name === "th" || td.name === "td") {
  696. if (border) {
  697. td.attrs.style = `border:${border}px ${borderstyle || "solid"} ${bordercolor || "gray"};${td.attrs.style || ""}`;
  698. }
  699. if (padding) {
  700. td.attrs.style = `padding:${padding}px;${td.attrs.style || ""}`;
  701. }
  702. } else if (td.children) {
  703. traversal(td.children);
  704. }
  705. }
  706. })(children);
  707. }
  708. }
  709. if (this.options.scrollTable && !(attrs.style || "").includes("inline")) {
  710. const table = Object.assign({}, node);
  711. node.name = "div";
  712. node.attrs = {
  713. style: "overflow:auto"
  714. };
  715. node.children = [table];
  716. attrs = table.attrs;
  717. }
  718. } else if ((node.name === "td" || node.name === "th") && (attrs.colspan || attrs.rowspan)) {
  719. for (let i = this.stack.length; i--; ) {
  720. if (this.stack[i].name === "table") {
  721. this.stack[i].flag = 1;
  722. break;
  723. }
  724. }
  725. } else if (node.name === "ruby") {
  726. node.name = "span";
  727. for (let i = 0; i < children.length - 1; i++) {
  728. if (children[i].type === "text" && children[i + 1].name === "rt") {
  729. children[i] = {
  730. name: "div",
  731. attrs: {
  732. style: "display:inline-block;text-align:center"
  733. },
  734. children: [{
  735. name: "div",
  736. attrs: {
  737. style: "font-size:50%;" + (children[i + 1].attrs.style || "")
  738. },
  739. children: children[i + 1].children
  740. }, children[i]]
  741. };
  742. children.splice(i + 1, 1);
  743. }
  744. }
  745. } else if (node.c) {
  746. (function traversal(node2) {
  747. node2.c = 2;
  748. for (let i = node2.children.length; i--; ) {
  749. const child = node2.children[i];
  750. if (child.name && (config.inlineTags[child.name] || (child.attrs.style || "").includes("inline") && child.children) && !child.c) {
  751. traversal(child);
  752. }
  753. if (!child.c || child.name === "table") {
  754. node2.c = 1;
  755. }
  756. }
  757. })(node);
  758. }
  759. if ((styleObj.display || "").includes("flex") && !node.c) {
  760. for (let i = children.length; i--; ) {
  761. const item = children[i];
  762. if (item.f) {
  763. item.attrs.style = (item.attrs.style || "") + item.f;
  764. item.f = void 0;
  765. }
  766. }
  767. }
  768. const flex = parent && ((parent.attrs.style || "").includes("flex") || (parent.attrs.style || "").includes("grid")) && !(node.c && common_vendor.wx$1.getNFCAdapter);
  769. if (flex) {
  770. node.f = ";max-width:100%";
  771. }
  772. if (children.length >= 50 && node.c && !(styleObj.display || "").includes("flex")) {
  773. mergeNodes(children);
  774. }
  775. for (const key in styleObj) {
  776. if (styleObj[key]) {
  777. const val = `;${key}:${styleObj[key].replace(" !important", "")}`;
  778. if (flex && (key.includes("flex") && key !== "flex-direction" || key === "align-self" || key.includes("grid") || styleObj[key][0] === "-" || key.includes("width") && val.includes("%"))) {
  779. node.f += val;
  780. if (key === "width") {
  781. attrs.style += ";width:100%";
  782. }
  783. } else {
  784. attrs.style += val;
  785. }
  786. }
  787. }
  788. attrs.style = attrs.style.substr(1) || void 0;
  789. for (const key in attrs) {
  790. if (!attrs[key]) {
  791. delete attrs[key];
  792. }
  793. }
  794. };
  795. Parser.prototype.onText = function(text) {
  796. if (!this.pre) {
  797. let trim = "";
  798. let flag;
  799. for (let i = 0, len = text.length; i < len; i++) {
  800. if (!blankChar[text[i]]) {
  801. trim += text[i];
  802. } else {
  803. if (trim[trim.length - 1] !== " ") {
  804. trim += " ";
  805. }
  806. if (text[i] === "\n" && !flag) {
  807. flag = true;
  808. }
  809. }
  810. }
  811. if (trim === " ") {
  812. if (flag)
  813. return;
  814. else {
  815. const parent = this.stack[this.stack.length - 1];
  816. if (parent && parent.name[0] === "t")
  817. return;
  818. }
  819. }
  820. text = trim;
  821. }
  822. const node = /* @__PURE__ */ Object.create(null);
  823. node.type = "text";
  824. node.text = decodeEntity(text);
  825. if (this.hook(node)) {
  826. if (this.options.selectable === "force" && system.includes("iOS") && !common_vendor.index.canIUse("rich-text.user-select")) {
  827. this.expose();
  828. }
  829. const siblings = this.stack.length ? this.stack[this.stack.length - 1].children : this.nodes;
  830. siblings.push(node);
  831. }
  832. };
  833. function Lexer(handler) {
  834. this.handler = handler;
  835. }
  836. Lexer.prototype.parse = function(content) {
  837. this.content = content || "";
  838. this.i = 0;
  839. this.start = 0;
  840. this.state = this.text;
  841. for (let len = this.content.length; this.i !== -1 && this.i < len; ) {
  842. this.state();
  843. }
  844. };
  845. Lexer.prototype.checkClose = function(method) {
  846. const selfClose = this.content[this.i] === "/";
  847. if (this.content[this.i] === ">" || selfClose && this.content[this.i + 1] === ">") {
  848. if (method) {
  849. this.handler[method](this.content.substring(this.start, this.i));
  850. }
  851. this.i += selfClose ? 2 : 1;
  852. this.start = this.i;
  853. this.handler.onOpenTag(selfClose);
  854. if (this.handler.tagName === "script") {
  855. this.i = this.content.indexOf("</", this.i);
  856. if (this.i !== -1) {
  857. this.i += 2;
  858. this.start = this.i;
  859. }
  860. this.state = this.endTag;
  861. } else {
  862. this.state = this.text;
  863. }
  864. return true;
  865. }
  866. return false;
  867. };
  868. Lexer.prototype.text = function() {
  869. this.i = this.content.indexOf("<", this.i);
  870. if (this.i === -1) {
  871. if (this.start < this.content.length) {
  872. this.handler.onText(this.content.substring(this.start, this.content.length));
  873. }
  874. return;
  875. }
  876. const c = this.content[this.i + 1];
  877. if (c >= "a" && c <= "z" || c >= "A" && c <= "Z") {
  878. if (this.start !== this.i) {
  879. this.handler.onText(this.content.substring(this.start, this.i));
  880. }
  881. this.start = ++this.i;
  882. this.state = this.tagName;
  883. } else if (c === "/" || c === "!" || c === "?") {
  884. if (this.start !== this.i) {
  885. this.handler.onText(this.content.substring(this.start, this.i));
  886. }
  887. const next = this.content[this.i + 2];
  888. if (c === "/" && (next >= "a" && next <= "z" || next >= "A" && next <= "Z")) {
  889. this.i += 2;
  890. this.start = this.i;
  891. this.state = this.endTag;
  892. return;
  893. }
  894. let end = "-->";
  895. if (c !== "!" || this.content[this.i + 2] !== "-" || this.content[this.i + 3] !== "-") {
  896. end = ">";
  897. }
  898. this.i = this.content.indexOf(end, this.i);
  899. if (this.i !== -1) {
  900. this.i += end.length;
  901. this.start = this.i;
  902. }
  903. } else {
  904. this.i++;
  905. }
  906. };
  907. Lexer.prototype.tagName = function() {
  908. if (blankChar[this.content[this.i]]) {
  909. this.handler.onTagName(this.content.substring(this.start, this.i));
  910. while (blankChar[this.content[++this.i]])
  911. ;
  912. if (this.i < this.content.length && !this.checkClose()) {
  913. this.start = this.i;
  914. this.state = this.attrName;
  915. }
  916. } else if (!this.checkClose("onTagName")) {
  917. this.i++;
  918. }
  919. };
  920. Lexer.prototype.attrName = function() {
  921. let c = this.content[this.i];
  922. if (blankChar[c] || c === "=") {
  923. this.handler.onAttrName(this.content.substring(this.start, this.i));
  924. let needVal = c === "=";
  925. const len = this.content.length;
  926. while (++this.i < len) {
  927. c = this.content[this.i];
  928. if (!blankChar[c]) {
  929. if (this.checkClose())
  930. return;
  931. if (needVal) {
  932. this.start = this.i;
  933. this.state = this.attrVal;
  934. return;
  935. }
  936. if (this.content[this.i] === "=") {
  937. needVal = true;
  938. } else {
  939. this.start = this.i;
  940. this.state = this.attrName;
  941. return;
  942. }
  943. }
  944. }
  945. } else if (!this.checkClose("onAttrName")) {
  946. this.i++;
  947. }
  948. };
  949. Lexer.prototype.attrVal = function() {
  950. const c = this.content[this.i];
  951. const len = this.content.length;
  952. if (c === '"' || c === "'") {
  953. this.start = ++this.i;
  954. this.i = this.content.indexOf(c, this.i);
  955. if (this.i === -1)
  956. return;
  957. this.handler.onAttrVal(this.content.substring(this.start, this.i));
  958. } else {
  959. for (; this.i < len; this.i++) {
  960. if (blankChar[this.content[this.i]]) {
  961. this.handler.onAttrVal(this.content.substring(this.start, this.i));
  962. break;
  963. } else if (this.checkClose("onAttrVal"))
  964. return;
  965. }
  966. }
  967. while (blankChar[this.content[++this.i]])
  968. ;
  969. if (this.i < len && !this.checkClose()) {
  970. this.start = this.i;
  971. this.state = this.attrName;
  972. }
  973. };
  974. Lexer.prototype.endTag = function() {
  975. const c = this.content[this.i];
  976. if (blankChar[c] || c === ">" || c === "/") {
  977. this.handler.onCloseTag(this.content.substring(this.start, this.i));
  978. if (c !== ">") {
  979. this.i = this.content.indexOf(">", this.i);
  980. if (this.i === -1)
  981. return;
  982. }
  983. this.start = ++this.i;
  984. this.state = this.text;
  985. } else {
  986. this.i++;
  987. }
  988. };
  989. exports.Parser = Parser;