flex-html-render 1.1.1 → 1.1.3
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.
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const Q=require("htmlparser2"),E={ELEMENT:"element",TEXT:"text"},e={CAROUSEL:"carousel",BUBBLE:"bubble",HEADER:"header",HERO:"hero",BODY:"body",FOOTER:"footer",BOX:"box",TEXT:"text",SPAN:"span",IMAGE:"image",VIDEO:"video",ICON:"icon",SEPARATOR:"separator",BUTTON:"button",FILLER:"filler",SPACE:"space",STRONG:"strong",BASELINE:"baseline",ROW:"row",VERTICAL:"vertical",DIV:"div",ARTICLE:"article",ACTION:"action",BACKGROUND:"background",STYLE:"style"},D=[e.HEADER,e.HERO,e.BODY,e.FOOTER],k=[e.BOX,e.VERTICAL,e.ROW,e.BASELINE,e.DIV,e.ARTICLE],Z=[e.TEXT,e.STRONG];function tt(t,r){if(new Set(["flex","maxLines"]).has(t)){const i=Number(r);return isNaN(i)?r:i}return r}function et(t,r){return r==="true"?!0:r==="false"?!1:r}function rt(t,r){return[tt,et].reduce((i,o)=>o(t,i),r)}function at(t){const r={type:"root",children:[]},n=[r],i=new Q.Parser({onopentag(o,s){const a={type:E.ELEMENT,tagName:o,attributes:Object.fromEntries(Object.entries(s).map(([c,b])=>[c,rt(c,b)])),children:[]};n[n.length-1].children.push(a),n.push(a)},ontext(o){const s=n[n.length-1];if(s.tagName==="span"){s.children.push({type:E.TEXT,content:o});return}o.trim()&&s.children.push({type:E.TEXT,content:o.replace(/\n/g,"").trim()})},onclosetag(){n.pop()},onerror(o){console.error("解析錯誤:",o)}},{xmlMode:!0,lowerCaseTags:!1,lowerCaseAttributeNames:!1});return i.write(t),i.end(),r.children}const m=t=>{throw Error(`[Flex Html Render]: ${t}`)},l={carousel:t=>({type:"carousel",contents:t}),bubble:(t={})=>({type:"bubble",...t}),box:(t,r={})=>({type:"box",contents:t,...r}),text:(t,r={})=>({type:"text",...typeof t=="string"?{text:t}:{contents:t},...r}),span:(t,r={})=>({type:"span",text:t,...r}),image:(t={})=>({type:"image",...t}),video:(t={})=>({type:"video",...t}),icon:(t={})=>({type:"icon",...t}),button:(t={})=>({type:"button",...t}),separator:(t={color:"#E0E3EA"})=>({type:"separator",...t}),filler:(t={})=>({type:"filler",...t}),uri:(t={})=>({type:"uri",altUri:t.altUri?{desktop:t.altUri}:void 0,...t}),postback:(t={})=>({type:"postback",...t}),message:(t={})=>({type:"message",...t}),datetimepicker:(t={})=>({type:"datetimepicker",...t}),camera:(t={})=>({type:"camera",...t}),cameraRoll:(t={})=>({type:"cameraRoll",...t}),location:(t={})=>({type:"location",...t}),richmenuswitch:(t={})=>({type:"richmenuswitch",...t}),clipboard:(t={})=>({type:"clipboard",...t})};function nt(t){if(t.tagName!==e.BACKGROUND&&t.children&&t.children.length>0){const r=t.children.filter(n=>n.tagName===e.BACKGROUND);return r.length>1&&m("A box node can only allowed with one background node inside"),t.children=t.children.filter(n=>n.tagName!==e.BACKGROUND),r[0]}return null}function it(t){if(t.tagName!==e.ACTION&&t.children&&t.children.length>0){const r=t.children.filter(n=>n.tagName===e.ACTION);return r.length>1&&m("A node can only allowed with one action node inside"),t.children=t.children.filter(n=>n.tagName!==e.ACTION),r[0]}return null}function st(t){![...Z,e.SPAN].includes(t.tagName)&&t.children?.some(a=>a.type===E.TEXT)&&m("Span component only allowed inside Text component"),t.tagName===e.VIDEO&&t.children?.some(a=>![e.BOX,e.IMAGE].includes(a.tagName))&&m("Video component only allowed Box or Image as altContent child"),!k.includes(t.tagName)&&t.children?.some(a=>a.tagName===e.BACKGROUND)&&m("Only Box component allowed to have Background child"),!k.includes(t.tagName)&&Object.keys(t.attributes||{}).some(a=>a.startsWith("padding"))&&m(`Padding property is not supported in ${t.tagName} component`),!D.includes(t.tagName)&&t.children?.filter(a=>a.tagName===e.STYLE).length>=1&&m("Only top-level section(header, hero, body, footer) can have Style child")}function d(t){if(t){const r=t.children.find(n=>n.tagName===e.STYLE);if(r)return t.children=t.children.filter(n=>n.tagName!==e.STYLE),r.attributes}}function u(t){t.attributes=t.attributes||{},st(t);const r=it(t);r&&(t.attributes.action=u(r));const n=nt(t);if(n&&(t.attributes.background=u(n)),t.type===E.TEXT)return l.span(t.content,t.attributes);if(t.tagName===e.BUBBLE){const i=t.children.find(c=>c.tagName===e.HEADER),o=t.children.find(c=>c.tagName===e.HERO),s=t.children.find(c=>c.tagName===e.BODY),a=t.children.find(c=>c.tagName===e.FOOTER),p={header:d(i),hero:d(o),body:d(s),footer:d(a)};return l.bubble({...t.attributes,header:i?u(i):void 0,hero:o?u(o):void 0,body:s?u(s):void 0,footer:a?u(a):void 0,styles:Object.values(p).some(c=>c!==void 0)?p:void 0})}if(t.tagName===e.CAROUSEL)return t.children.some(i=>i.tagName!==e.BUBBLE)&&m("Carousel can only have Bubble as children"),t.children.length>12&&m("Carousel can have maximum 12 bubbles"),l.carousel(t.children.map(u));if(D.includes(t.tagName))return t.children.length!==1&&m(`${t.tagName} should have exactly one child node`),u(t.children[0]);if(t.tagName===e.BUTTON)return t.attributes.action||m("Button component should contain an action node"),l.button(t.attributes);if(t.tagName===e.SPAN){t.children.length>1&&m("Span component can only have one text child");const i=t.children[0];if(i&&i.type===E.TEXT)return l.span(i.content,t.attributes);m(i?"Span component only allowed text child":"Span component can not be empty")}if(t.tagName===e.TEXT)return l.text(t.children.map(u),t.attributes);if(t.tagName===e.SEPARATOR)return l.separator(t.attributes);if(t.tagName===e.IMAGE)return l.image(t.attributes);if(t.tagName===e.VIDEO)return t.children.length!==1&&m("Video component should only has one Box or Image as altContent"),t.attributes.altContent=u(t.children[0]),l.video(t.attributes);if(t.tagName===e.ICON)return l.icon(t.attributes);if(t.tagName===e.FILLER)return l.filler(t.attributes);if(t.tagName===e.BOX||t.tagName===e.DIV||t.tagName===e.ARTICLE)return t.attributes.layout||(t.attributes.layout="vertical"),l.box(t.children.map(u),t.attributes);if(t.tagName===e.SPACE)return l.span(" ".repeat(t.attributes.size||1));if(t.tagName===e.STRONG)return t.tagName=e.TEXT,t.attributes.weight="bold",u(t);if(t.tagName===e.BASELINE)return t.tagName=e.BOX,t.attributes.layout="baseline",u(t);if(t.tagName===e.ROW)return t.tagName=e.BOX,t.attributes.layout="horizontal",u(t);if(t.tagName===e.VERTICAL)return t.tagName=e.BOX,t.attributes.layout="vertical",u(t);if(t.tagName===e.ACTION){const i=t.attributes.type;switch(i){case"uri":return l.uri(t.attributes);case"postback":return l.postback(t.attributes);case"message":return l.message(t.attributes);case"datetimepicker":return l.datetimepicker(t.attributes);case"camera":return l.camera(t.attributes);case"cameraRoll":return l.cameraRoll(t.attributes);case"location":return l.location(t.attributes);case"richmenuswitch":return l.richmenuswitch(t.attributes);case"clipboard":return l.clipboard(t.attributes);default:m(`Unsupported action type: ${i}`)}}if(t.tagName===e.BACKGROUND)return t.attributes}const h={createElement:(t,r={},n=[],i=0)=>{const s=Object.entries(r).filter(([p,c])=>c!=null).map(([p,c])=>typeof c=="object"?`${p}="${JSON.stringify(c).replace(/"/g,""")}"`:`${p}="${c}"`).join(" "),a=s?` ${s}`:"";if(n.length===0)return` <${t}${a} />`;{const p=n.map(c=>typeof c=="string"?c.split(`
|
|
2
2
|
`).map(b=>b?" "+b:"").join(`
|
|
3
|
-
`):
|
|
4
|
-
`);return` <${t}${
|
|
3
|
+
`):c).join(`
|
|
4
|
+
`);return` <${t}${a}>
|
|
5
5
|
${p}
|
|
6
|
-
</${t}>`}},createText:t=>t},
|
|
6
|
+
</${t}>`}},createText:t=>t},O=(t,r,n,i)=>{const o=[f(r,i+1)];return n&&Object.keys(n).length>0&&o.unshift(f(X("style",n),i+1)),h.createElement(t,{},o,i)},X=(t,r)=>({...r,type:t});function f(t,r=0){if(!t||typeof t!="object")return"";const{type:n,...i}=t,{action:o,...s}=i,a=o?f(o,r+1):"";switch(n){case"carousel":const{contents:p,...c}=s,b=p.map(N=>f(N,r+1));return a&&b.unshift(a),h.createElement(e.CAROUSEL,c,b,r);case"bubble":const{header:R,hero:B,body:S,footer:x,styles:y={},...$}=s,g=[];return a&&g.push(a),R&&g.push(O(e.HEADER,R,y.header,r+1)),B&&g.push(O(e.HERO,B,y.hero,r+1)),S&&g.push(O(e.BODY,S,y.body,r+1)),x&&g.push(O(e.FOOTER,x,y.footer,r+1)),h.createElement(e.BUBBLE,$,g,r);case"box":const{contents:P,background:v,...A}=s;A.layout||(A.layout="vertical");const T=[];return a&&T.push(a),v&&T.push(f(X("background",v),r+1)),T.push(...(P||[]).map(N=>f(N,r+1))),h.createElement(e.BOX,A,T,r);case"text":const{text:H,contents:C,...G}=s,I=C&&C.length>0?C.map(N=>f(N,r+1)):[H||""];return a&&I.unshift(a),h.createElement(e.TEXT,G,I,r);case"span":const{text:M,...F}=s,L=[M||""];return a&&L.unshift(a),h.createElement(e.SPAN,F,L,r);case"image":const{...V}=s,j=a?[a]:[];return h.createElement(e.IMAGE,V,j,r);case"video":const{altContent:w,...K}=s,U=w?[f(w,r+1)]:[];return a&&U.unshift(a),h.createElement(e.VIDEO,K,U,r);case"icon":const{...Y}=s,W=a?[a]:[];return h.createElement(e.ICON,Y,W,r);case"button":const{...J}=s,q=a?[a]:[];return h.createElement(e.BUTTON,J,q,r);case"separator":const z=a?[a]:[];return h.createElement(e.SEPARATOR,s,z,r);case"filler":const _=a?[a]:[];return h.createElement(e.FILLER,s,_,r);case"uri":case"message":case"postback":case"datetimepicker":case"camera":case"cameraRoll":case"location":case"richmenuswitch":case"clipboard":return h.createElement(e.ACTION,{type:n,...s},[],r);case"background":return h.createElement(e.BACKGROUND,s,[],r);case"style":return h.createElement(e.STYLE,s,[],r);default:return""}}function ct(t){try{return at(t).map(u)}catch(r){throw console.error("Error converting HTML to Flex Message:",r),r}}exports.convertJsonToHtml=f;exports.default=ct;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Parser as
|
|
1
|
+
import { Parser as Z } from "htmlparser2";
|
|
2
2
|
const E = {
|
|
3
3
|
ELEMENT: "element",
|
|
4
4
|
TEXT: "text"
|
|
@@ -34,12 +34,12 @@ const E = {
|
|
|
34
34
|
ACTION: "action",
|
|
35
35
|
BACKGROUND: "background",
|
|
36
36
|
STYLE: "style"
|
|
37
|
-
},
|
|
37
|
+
}, D = [
|
|
38
38
|
e.HEADER,
|
|
39
39
|
e.HERO,
|
|
40
40
|
e.BODY,
|
|
41
41
|
e.FOOTER
|
|
42
|
-
],
|
|
42
|
+
], k = [
|
|
43
43
|
e.BOX,
|
|
44
44
|
e.VERTICAL,
|
|
45
45
|
e.ROW,
|
|
@@ -50,52 +50,55 @@ const E = {
|
|
|
50
50
|
e.TEXT,
|
|
51
51
|
e.STRONG
|
|
52
52
|
];
|
|
53
|
-
function tt(t) {
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
function tt(t, r) {
|
|
54
|
+
if ((/* @__PURE__ */ new Set(["flex", "maxLines"])).has(t)) {
|
|
55
|
+
const i = Number(r);
|
|
56
|
+
return isNaN(i) ? r : i;
|
|
57
|
+
}
|
|
58
|
+
return r;
|
|
56
59
|
}
|
|
57
|
-
function et(t) {
|
|
58
|
-
return
|
|
60
|
+
function et(t, r) {
|
|
61
|
+
return r === "true" ? !0 : r === "false" ? !1 : r;
|
|
59
62
|
}
|
|
60
|
-
function rt(t) {
|
|
63
|
+
function rt(t, r) {
|
|
61
64
|
return [
|
|
62
65
|
tt,
|
|
63
66
|
et
|
|
64
|
-
].reduce((
|
|
67
|
+
].reduce((i, o) => o(t, i), r);
|
|
65
68
|
}
|
|
66
69
|
function at(t) {
|
|
67
|
-
const r = { type: "root", children: [] },
|
|
70
|
+
const r = { type: "root", children: [] }, n = [r], i = new Z(
|
|
68
71
|
{
|
|
69
|
-
onopentag(
|
|
70
|
-
const
|
|
72
|
+
onopentag(o, c) {
|
|
73
|
+
const a = {
|
|
71
74
|
type: E.ELEMENT,
|
|
72
|
-
tagName:
|
|
75
|
+
tagName: o,
|
|
73
76
|
attributes: Object.fromEntries(
|
|
74
|
-
Object.entries(
|
|
77
|
+
Object.entries(c).map(([s, b]) => [s, rt(s, b)])
|
|
75
78
|
),
|
|
76
79
|
children: []
|
|
77
80
|
};
|
|
78
|
-
|
|
81
|
+
n[n.length - 1].children.push(a), n.push(a);
|
|
79
82
|
},
|
|
80
|
-
ontext(
|
|
81
|
-
const
|
|
82
|
-
if (
|
|
83
|
-
|
|
83
|
+
ontext(o) {
|
|
84
|
+
const c = n[n.length - 1];
|
|
85
|
+
if (c.tagName === "span") {
|
|
86
|
+
c.children.push({
|
|
84
87
|
type: E.TEXT,
|
|
85
|
-
content:
|
|
88
|
+
content: o
|
|
86
89
|
});
|
|
87
90
|
return;
|
|
88
91
|
}
|
|
89
|
-
|
|
92
|
+
o.trim() && c.children.push({
|
|
90
93
|
type: E.TEXT,
|
|
91
|
-
content:
|
|
94
|
+
content: o.replace(/\n/g, "").trim()
|
|
92
95
|
});
|
|
93
96
|
},
|
|
94
97
|
onclosetag() {
|
|
95
|
-
|
|
98
|
+
n.pop();
|
|
96
99
|
},
|
|
97
|
-
onerror(
|
|
98
|
-
console.error("解析錯誤:",
|
|
100
|
+
onerror(o) {
|
|
101
|
+
console.error("解析錯誤:", o);
|
|
99
102
|
}
|
|
100
103
|
},
|
|
101
104
|
{
|
|
@@ -106,11 +109,11 @@ function at(t) {
|
|
|
106
109
|
lowerCaseAttributeNames: !1
|
|
107
110
|
}
|
|
108
111
|
);
|
|
109
|
-
return
|
|
112
|
+
return i.write(t), i.end(), r.children;
|
|
110
113
|
}
|
|
111
|
-
const
|
|
114
|
+
const m = (t) => {
|
|
112
115
|
throw Error(`[Flex Html Render]: ${t}`);
|
|
113
|
-
},
|
|
116
|
+
}, l = {
|
|
114
117
|
carousel: (t) => ({
|
|
115
118
|
type: "carousel",
|
|
116
119
|
contents: t
|
|
@@ -202,91 +205,91 @@ const h = (t) => {
|
|
|
202
205
|
};
|
|
203
206
|
function nt(t) {
|
|
204
207
|
if (t.tagName !== e.BACKGROUND && t.children && t.children.length > 0) {
|
|
205
|
-
const r = t.children.filter((
|
|
206
|
-
return r.length > 1 &&
|
|
208
|
+
const r = t.children.filter((n) => n.tagName === e.BACKGROUND);
|
|
209
|
+
return r.length > 1 && m("A box node can only allowed with one background node inside"), t.children = t.children.filter((n) => n.tagName !== e.BACKGROUND), r[0];
|
|
207
210
|
}
|
|
208
211
|
return null;
|
|
209
212
|
}
|
|
210
213
|
function it(t) {
|
|
211
214
|
if (t.tagName !== e.ACTION && t.children && t.children.length > 0) {
|
|
212
|
-
const r = t.children.filter((
|
|
213
|
-
return r.length > 1 &&
|
|
215
|
+
const r = t.children.filter((n) => n.tagName === e.ACTION);
|
|
216
|
+
return r.length > 1 && m("A node can only allowed with one action node inside"), t.children = t.children.filter((n) => n.tagName !== e.ACTION), r[0];
|
|
214
217
|
}
|
|
215
218
|
return null;
|
|
216
219
|
}
|
|
217
220
|
function ct(t) {
|
|
218
|
-
![..._, e.SPAN].includes(t.tagName) && t.children?.some((
|
|
221
|
+
![..._, e.SPAN].includes(t.tagName) && t.children?.some((a) => a.type === E.TEXT) && m("Span component only allowed inside Text component"), t.tagName === e.VIDEO && t.children?.some((a) => ![e.BOX, e.IMAGE].includes(a.tagName)) && m("Video component only allowed Box or Image as altContent child"), !k.includes(t.tagName) && t.children?.some((a) => a.tagName === e.BACKGROUND) && m("Only Box component allowed to have Background child"), !k.includes(t.tagName) && Object.keys(t.attributes || {}).some((a) => a.startsWith("padding")) && m(`Padding property is not supported in ${t.tagName} component`), !D.includes(t.tagName) && t.children?.filter((a) => a.tagName === e.STYLE).length >= 1 && m("Only top-level section(header, hero, body, footer) can have Style child");
|
|
219
222
|
}
|
|
220
|
-
function
|
|
223
|
+
function d(t) {
|
|
221
224
|
if (t) {
|
|
222
|
-
const r = t.children.find((
|
|
225
|
+
const r = t.children.find((n) => n.tagName === e.STYLE);
|
|
223
226
|
if (r)
|
|
224
|
-
return t.children = t.children.filter((
|
|
227
|
+
return t.children = t.children.filter((n) => n.tagName !== e.STYLE), r.attributes;
|
|
225
228
|
}
|
|
226
229
|
}
|
|
227
230
|
function u(t) {
|
|
228
231
|
t.attributes = t.attributes || {}, ct(t);
|
|
229
232
|
const r = it(t);
|
|
230
233
|
r && (t.attributes.action = u(r));
|
|
231
|
-
const
|
|
232
|
-
if (
|
|
233
|
-
return
|
|
234
|
+
const n = nt(t);
|
|
235
|
+
if (n && (t.attributes.background = u(n)), t.type === E.TEXT)
|
|
236
|
+
return l.span(t.content, t.attributes);
|
|
234
237
|
if (t.tagName === e.BUBBLE) {
|
|
235
|
-
const
|
|
236
|
-
header:
|
|
237
|
-
hero:
|
|
238
|
-
body:
|
|
239
|
-
footer:
|
|
238
|
+
const i = t.children.find((s) => s.tagName === e.HEADER), o = t.children.find((s) => s.tagName === e.HERO), c = t.children.find((s) => s.tagName === e.BODY), a = t.children.find((s) => s.tagName === e.FOOTER), p = {
|
|
239
|
+
header: d(i),
|
|
240
|
+
hero: d(o),
|
|
241
|
+
body: d(c),
|
|
242
|
+
footer: d(a)
|
|
240
243
|
};
|
|
241
|
-
return
|
|
244
|
+
return l.bubble({
|
|
242
245
|
...t.attributes,
|
|
243
|
-
header:
|
|
244
|
-
hero:
|
|
245
|
-
body:
|
|
246
|
-
footer:
|
|
247
|
-
styles: Object.values(p).some((
|
|
246
|
+
header: i ? u(i) : void 0,
|
|
247
|
+
hero: o ? u(o) : void 0,
|
|
248
|
+
body: c ? u(c) : void 0,
|
|
249
|
+
footer: a ? u(a) : void 0,
|
|
250
|
+
styles: Object.values(p).some((s) => s !== void 0) ? p : void 0
|
|
248
251
|
});
|
|
249
252
|
}
|
|
250
253
|
if (t.tagName === e.CAROUSEL)
|
|
251
|
-
return t.children.some((
|
|
254
|
+
return t.children.some((i) => i.tagName !== e.BUBBLE) && m("Carousel can only have Bubble as children"), t.children.length > 12 && m("Carousel can have maximum 12 bubbles"), l.carousel(
|
|
252
255
|
t.children.map(u)
|
|
253
256
|
);
|
|
254
|
-
if (
|
|
255
|
-
return t.children.length !== 1 &&
|
|
257
|
+
if (D.includes(t.tagName))
|
|
258
|
+
return t.children.length !== 1 && m(`${t.tagName} should have exactly one child node`), u(t.children[0]);
|
|
256
259
|
if (t.tagName === e.BUTTON)
|
|
257
|
-
return t.attributes.action ||
|
|
260
|
+
return t.attributes.action || m("Button component should contain an action node"), l.button(t.attributes);
|
|
258
261
|
if (t.tagName === e.SPAN) {
|
|
259
|
-
t.children.length > 1 &&
|
|
260
|
-
const
|
|
261
|
-
if (
|
|
262
|
-
return
|
|
263
|
-
|
|
262
|
+
t.children.length > 1 && m("Span component can only have one text child");
|
|
263
|
+
const i = t.children[0];
|
|
264
|
+
if (i && i.type === E.TEXT)
|
|
265
|
+
return l.span(
|
|
266
|
+
i.content,
|
|
264
267
|
t.attributes
|
|
265
268
|
);
|
|
266
|
-
|
|
269
|
+
m(i ? "Span component only allowed text child" : "Span component can not be empty");
|
|
267
270
|
}
|
|
268
271
|
if (t.tagName === e.TEXT)
|
|
269
|
-
return
|
|
272
|
+
return l.text(
|
|
270
273
|
t.children.map(u),
|
|
271
274
|
t.attributes
|
|
272
275
|
);
|
|
273
276
|
if (t.tagName === e.SEPARATOR)
|
|
274
|
-
return
|
|
277
|
+
return l.separator(t.attributes);
|
|
275
278
|
if (t.tagName === e.IMAGE)
|
|
276
|
-
return
|
|
279
|
+
return l.image(t.attributes);
|
|
277
280
|
if (t.tagName === e.VIDEO)
|
|
278
|
-
return t.children.length !== 1 &&
|
|
281
|
+
return t.children.length !== 1 && m("Video component should only has one Box or Image as altContent"), t.attributes.altContent = u(t.children[0]), l.video(t.attributes);
|
|
279
282
|
if (t.tagName === e.ICON)
|
|
280
|
-
return
|
|
283
|
+
return l.icon(t.attributes);
|
|
281
284
|
if (t.tagName === e.FILLER)
|
|
282
|
-
return
|
|
285
|
+
return l.filler(t.attributes);
|
|
283
286
|
if (t.tagName === e.BOX || t.tagName === e.DIV || t.tagName === e.ARTICLE)
|
|
284
|
-
return t.attributes.layout || (t.attributes.layout = "vertical"),
|
|
287
|
+
return t.attributes.layout || (t.attributes.layout = "vertical"), l.box(
|
|
285
288
|
t.children.map(u),
|
|
286
289
|
t.attributes
|
|
287
290
|
);
|
|
288
291
|
if (t.tagName === e.SPACE)
|
|
289
|
-
return
|
|
292
|
+
return l.span(" ".repeat(t.attributes.size || 1));
|
|
290
293
|
if (t.tagName === e.STRONG)
|
|
291
294
|
return t.tagName = e.TEXT, t.attributes.weight = "bold", u(t);
|
|
292
295
|
if (t.tagName === e.BASELINE)
|
|
@@ -296,93 +299,93 @@ function u(t) {
|
|
|
296
299
|
if (t.tagName === e.VERTICAL)
|
|
297
300
|
return t.tagName = e.BOX, t.attributes.layout = "vertical", u(t);
|
|
298
301
|
if (t.tagName === e.ACTION) {
|
|
299
|
-
const
|
|
300
|
-
switch (
|
|
302
|
+
const i = t.attributes.type;
|
|
303
|
+
switch (i) {
|
|
301
304
|
case "uri":
|
|
302
|
-
return
|
|
305
|
+
return l.uri(t.attributes);
|
|
303
306
|
case "postback":
|
|
304
|
-
return
|
|
307
|
+
return l.postback(t.attributes);
|
|
305
308
|
case "message":
|
|
306
|
-
return
|
|
309
|
+
return l.message(t.attributes);
|
|
307
310
|
case "datetimepicker":
|
|
308
|
-
return
|
|
311
|
+
return l.datetimepicker(t.attributes);
|
|
309
312
|
case "camera":
|
|
310
|
-
return
|
|
313
|
+
return l.camera(t.attributes);
|
|
311
314
|
case "cameraRoll":
|
|
312
|
-
return
|
|
315
|
+
return l.cameraRoll(t.attributes);
|
|
313
316
|
case "location":
|
|
314
|
-
return
|
|
317
|
+
return l.location(t.attributes);
|
|
315
318
|
case "richmenuswitch":
|
|
316
|
-
return
|
|
319
|
+
return l.richmenuswitch(t.attributes);
|
|
317
320
|
case "clipboard":
|
|
318
|
-
return
|
|
321
|
+
return l.clipboard(t.attributes);
|
|
319
322
|
default:
|
|
320
|
-
|
|
323
|
+
m(`Unsupported action type: ${i}`);
|
|
321
324
|
}
|
|
322
325
|
}
|
|
323
326
|
if (t.tagName === e.BACKGROUND)
|
|
324
327
|
return t.attributes;
|
|
325
328
|
}
|
|
326
|
-
const
|
|
327
|
-
createElement: (t, r = {},
|
|
328
|
-
const
|
|
329
|
-
if (
|
|
330
|
-
return ` <${t}${
|
|
329
|
+
const h = {
|
|
330
|
+
createElement: (t, r = {}, n = [], i = 0) => {
|
|
331
|
+
const c = Object.entries(r).filter(([p, s]) => s != null).map(([p, s]) => typeof s == "object" ? `${p}="${JSON.stringify(s).replace(/"/g, """)}"` : `${p}="${s}"`).join(" "), a = c ? ` ${c}` : "";
|
|
332
|
+
if (n.length === 0)
|
|
333
|
+
return ` <${t}${a} />`;
|
|
331
334
|
{
|
|
332
|
-
const p =
|
|
335
|
+
const p = n.map((s) => typeof s == "string" ? s.split(`
|
|
333
336
|
`).map((b) => b ? " " + b : "").join(`
|
|
334
|
-
`) :
|
|
337
|
+
`) : s).join(`
|
|
335
338
|
`);
|
|
336
|
-
return ` <${t}${
|
|
339
|
+
return ` <${t}${a}>
|
|
337
340
|
${p}
|
|
338
341
|
</${t}>`;
|
|
339
342
|
}
|
|
340
343
|
},
|
|
341
344
|
createText: (t) => t
|
|
342
|
-
},
|
|
343
|
-
const
|
|
344
|
-
return
|
|
345
|
-
},
|
|
345
|
+
}, O = (t, r, n, i) => {
|
|
346
|
+
const o = [f(r, i + 1)];
|
|
347
|
+
return n && Object.keys(n).length > 0 && o.unshift(f(X("style", n), i + 1)), h.createElement(t, {}, o, i);
|
|
348
|
+
}, X = (t, r) => ({ ...r, type: t });
|
|
346
349
|
function f(t, r = 0) {
|
|
347
350
|
if (!t || typeof t != "object")
|
|
348
351
|
return "";
|
|
349
|
-
const { type:
|
|
350
|
-
switch (
|
|
352
|
+
const { type: n, ...i } = t, { action: o, ...c } = i, a = o ? f(o, r + 1) : "";
|
|
353
|
+
switch (n) {
|
|
351
354
|
case "carousel":
|
|
352
|
-
const { contents: p, ...
|
|
353
|
-
return
|
|
355
|
+
const { contents: p, ...s } = c, b = p.map((N) => f(N, r + 1));
|
|
356
|
+
return a && b.unshift(a), h.createElement(e.CAROUSEL, s, b, r);
|
|
354
357
|
case "bubble":
|
|
355
|
-
const { header: R, hero: B, body:
|
|
356
|
-
return
|
|
358
|
+
const { header: R, hero: B, body: S, footer: x, styles: y = {}, ...$ } = c, g = [];
|
|
359
|
+
return a && g.push(a), R && g.push(O(e.HEADER, R, y.header, r + 1)), B && g.push(O(e.HERO, B, y.hero, r + 1)), S && g.push(O(e.BODY, S, y.body, r + 1)), x && g.push(O(e.FOOTER, x, y.footer, r + 1)), h.createElement(e.BUBBLE, $, g, r);
|
|
357
360
|
case "box":
|
|
358
|
-
const { contents:
|
|
359
|
-
|
|
360
|
-
const
|
|
361
|
-
return
|
|
361
|
+
const { contents: P, background: I, ...A } = c;
|
|
362
|
+
A.layout || (A.layout = "vertical");
|
|
363
|
+
const T = [];
|
|
364
|
+
return a && T.push(a), I && T.push(f(X("background", I), r + 1)), T.push(...(P || []).map((N) => f(N, r + 1))), h.createElement(e.BOX, A, T, r);
|
|
362
365
|
case "text":
|
|
363
|
-
const { text:
|
|
364
|
-
return
|
|
366
|
+
const { text: G, contents: C, ...H } = c, v = C && C.length > 0 ? C.map((N) => f(N, r + 1)) : [G || ""];
|
|
367
|
+
return a && v.unshift(a), h.createElement(e.TEXT, H, v, r);
|
|
365
368
|
case "span":
|
|
366
|
-
const { text:
|
|
367
|
-
return
|
|
369
|
+
const { text: F, ...V } = c, L = [F || ""];
|
|
370
|
+
return a && L.unshift(a), h.createElement(e.SPAN, V, L, r);
|
|
368
371
|
case "image":
|
|
369
|
-
const { ...
|
|
370
|
-
return
|
|
372
|
+
const { ...M } = c, j = a ? [a] : [];
|
|
373
|
+
return h.createElement(e.IMAGE, M, j, r);
|
|
371
374
|
case "video":
|
|
372
|
-
const { altContent: w, ...
|
|
373
|
-
return
|
|
375
|
+
const { altContent: w, ...K } = c, U = w ? [f(w, r + 1)] : [];
|
|
376
|
+
return a && U.unshift(a), h.createElement(e.VIDEO, K, U, r);
|
|
374
377
|
case "icon":
|
|
375
|
-
const { ...
|
|
376
|
-
return
|
|
378
|
+
const { ...Y } = c, W = a ? [a] : [];
|
|
379
|
+
return h.createElement(e.ICON, Y, W, r);
|
|
377
380
|
case "button":
|
|
378
|
-
const { ...
|
|
379
|
-
return
|
|
381
|
+
const { ...J } = c, z = a ? [a] : [];
|
|
382
|
+
return h.createElement(e.BUTTON, J, z, r);
|
|
380
383
|
case "separator":
|
|
381
|
-
const
|
|
382
|
-
return
|
|
384
|
+
const q = a ? [a] : [];
|
|
385
|
+
return h.createElement(e.SEPARATOR, c, q, r);
|
|
383
386
|
case "filler":
|
|
384
|
-
const
|
|
385
|
-
return
|
|
387
|
+
const Q = a ? [a] : [];
|
|
388
|
+
return h.createElement(e.FILLER, c, Q, r);
|
|
386
389
|
// Action types
|
|
387
390
|
case "uri":
|
|
388
391
|
case "message":
|
|
@@ -393,11 +396,11 @@ function f(t, r = 0) {
|
|
|
393
396
|
case "location":
|
|
394
397
|
case "richmenuswitch":
|
|
395
398
|
case "clipboard":
|
|
396
|
-
return
|
|
399
|
+
return h.createElement(e.ACTION, { type: n, ...c }, [], r);
|
|
397
400
|
case "background":
|
|
398
|
-
return
|
|
401
|
+
return h.createElement(e.BACKGROUND, c, [], r);
|
|
399
402
|
case "style":
|
|
400
|
-
return
|
|
403
|
+
return h.createElement(e.STYLE, c, [], r);
|
|
401
404
|
default:
|
|
402
405
|
return "";
|
|
403
406
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
(function(b,
|
|
1
|
+
(function(b,y){typeof exports=="object"&&typeof module<"u"?y(exports,require("htmlparser2")):typeof define=="function"&&define.amd?define(["exports","htmlparser2"],y):(b=typeof globalThis<"u"?globalThis:b||self,y(b.FlexHtmlRender={},b.htmlparser2))})(this,(function(b,y){"use strict";const E={ELEMENT:"element",TEXT:"text"},e={CAROUSEL:"carousel",BUBBLE:"bubble",HEADER:"header",HERO:"hero",BODY:"body",FOOTER:"footer",BOX:"box",TEXT:"text",SPAN:"span",IMAGE:"image",VIDEO:"video",ICON:"icon",SEPARATOR:"separator",BUTTON:"button",FILLER:"filler",SPACE:"space",STRONG:"strong",BASELINE:"baseline",ROW:"row",VERTICAL:"vertical",DIV:"div",ARTICLE:"article",ACTION:"action",BACKGROUND:"background",STYLE:"style"},S=[e.HEADER,e.HERO,e.BODY,e.FOOTER],x=[e.BOX,e.VERTICAL,e.ROW,e.BASELINE,e.DIV,e.ARTICLE],H=[e.TEXT,e.STRONG];function G(t,r){if(new Set(["flex","maxLines"]).has(t)){const i=Number(r);return isNaN(i)?r:i}return r}function F(t,r){return r==="true"?!0:r==="false"?!1:r}function M(t,r){return[G,F].reduce((i,o)=>o(t,i),r)}function V(t){const r={type:"root",children:[]},n=[r],i=new y.Parser({onopentag(o,s){const a={type:E.ELEMENT,tagName:o,attributes:Object.fromEntries(Object.entries(s).map(([c,g])=>[c,M(c,g)])),children:[]};n[n.length-1].children.push(a),n.push(a)},ontext(o){const s=n[n.length-1];if(s.tagName==="span"){s.children.push({type:E.TEXT,content:o});return}o.trim()&&s.children.push({type:E.TEXT,content:o.replace(/\n/g,"").trim()})},onclosetag(){n.pop()},onerror(o){console.error("解析錯誤:",o)}},{xmlMode:!0,lowerCaseTags:!1,lowerCaseAttributeNames:!1});return i.write(t),i.end(),r.children}const u=t=>{throw Error(`[Flex Html Render]: ${t}`)},l={carousel:t=>({type:"carousel",contents:t}),bubble:(t={})=>({type:"bubble",...t}),box:(t,r={})=>({type:"box",contents:t,...r}),text:(t,r={})=>({type:"text",...typeof t=="string"?{text:t}:{contents:t},...r}),span:(t,r={})=>({type:"span",text:t,...r}),image:(t={})=>({type:"image",...t}),video:(t={})=>({type:"video",...t}),icon:(t={})=>({type:"icon",...t}),button:(t={})=>({type:"button",...t}),separator:(t={color:"#E0E3EA"})=>({type:"separator",...t}),filler:(t={})=>({type:"filler",...t}),uri:(t={})=>({type:"uri",altUri:t.altUri?{desktop:t.altUri}:void 0,...t}),postback:(t={})=>({type:"postback",...t}),message:(t={})=>({type:"message",...t}),datetimepicker:(t={})=>({type:"datetimepicker",...t}),camera:(t={})=>({type:"camera",...t}),cameraRoll:(t={})=>({type:"cameraRoll",...t}),location:(t={})=>({type:"location",...t}),richmenuswitch:(t={})=>({type:"richmenuswitch",...t}),clipboard:(t={})=>({type:"clipboard",...t})};function j(t){if(t.tagName!==e.BACKGROUND&&t.children&&t.children.length>0){const r=t.children.filter(n=>n.tagName===e.BACKGROUND);return r.length>1&&u("A box node can only allowed with one background node inside"),t.children=t.children.filter(n=>n.tagName!==e.BACKGROUND),r[0]}return null}function K(t){if(t.tagName!==e.ACTION&&t.children&&t.children.length>0){const r=t.children.filter(n=>n.tagName===e.ACTION);return r.length>1&&u("A node can only allowed with one action node inside"),t.children=t.children.filter(n=>n.tagName!==e.ACTION),r[0]}return null}function Y(t){![...H,e.SPAN].includes(t.tagName)&&t.children?.some(a=>a.type===E.TEXT)&&u("Span component only allowed inside Text component"),t.tagName===e.VIDEO&&t.children?.some(a=>![e.BOX,e.IMAGE].includes(a.tagName))&&u("Video component only allowed Box or Image as altContent child"),!x.includes(t.tagName)&&t.children?.some(a=>a.tagName===e.BACKGROUND)&&u("Only Box component allowed to have Background child"),!x.includes(t.tagName)&&Object.keys(t.attributes||{}).some(a=>a.startsWith("padding"))&&u(`Padding property is not supported in ${t.tagName} component`),!S.includes(t.tagName)&&t.children?.filter(a=>a.tagName===e.STYLE).length>=1&&u("Only top-level section(header, hero, body, footer) can have Style child")}function T(t){if(t){const r=t.children.find(n=>n.tagName===e.STYLE);if(r)return t.children=t.children.filter(n=>n.tagName!==e.STYLE),r.attributes}}function m(t){t.attributes=t.attributes||{},Y(t);const r=K(t);r&&(t.attributes.action=m(r));const n=j(t);if(n&&(t.attributes.background=m(n)),t.type===E.TEXT)return l.span(t.content,t.attributes);if(t.tagName===e.BUBBLE){const i=t.children.find(c=>c.tagName===e.HEADER),o=t.children.find(c=>c.tagName===e.HERO),s=t.children.find(c=>c.tagName===e.BODY),a=t.children.find(c=>c.tagName===e.FOOTER),p={header:T(i),hero:T(o),body:T(s),footer:T(a)};return l.bubble({...t.attributes,header:i?m(i):void 0,hero:o?m(o):void 0,body:s?m(s):void 0,footer:a?m(a):void 0,styles:Object.values(p).some(c=>c!==void 0)?p:void 0})}if(t.tagName===e.CAROUSEL)return t.children.some(i=>i.tagName!==e.BUBBLE)&&u("Carousel can only have Bubble as children"),t.children.length>12&&u("Carousel can have maximum 12 bubbles"),l.carousel(t.children.map(m));if(S.includes(t.tagName))return t.children.length!==1&&u(`${t.tagName} should have exactly one child node`),m(t.children[0]);if(t.tagName===e.BUTTON)return t.attributes.action||u("Button component should contain an action node"),l.button(t.attributes);if(t.tagName===e.SPAN){t.children.length>1&&u("Span component can only have one text child");const i=t.children[0];if(i&&i.type===E.TEXT)return l.span(i.content,t.attributes);u(i?"Span component only allowed text child":"Span component can not be empty")}if(t.tagName===e.TEXT)return l.text(t.children.map(m),t.attributes);if(t.tagName===e.SEPARATOR)return l.separator(t.attributes);if(t.tagName===e.IMAGE)return l.image(t.attributes);if(t.tagName===e.VIDEO)return t.children.length!==1&&u("Video component should only has one Box or Image as altContent"),t.attributes.altContent=m(t.children[0]),l.video(t.attributes);if(t.tagName===e.ICON)return l.icon(t.attributes);if(t.tagName===e.FILLER)return l.filler(t.attributes);if(t.tagName===e.BOX||t.tagName===e.DIV||t.tagName===e.ARTICLE)return t.attributes.layout||(t.attributes.layout="vertical"),l.box(t.children.map(m),t.attributes);if(t.tagName===e.SPACE)return l.span(" ".repeat(t.attributes.size||1));if(t.tagName===e.STRONG)return t.tagName=e.TEXT,t.attributes.weight="bold",m(t);if(t.tagName===e.BASELINE)return t.tagName=e.BOX,t.attributes.layout="baseline",m(t);if(t.tagName===e.ROW)return t.tagName=e.BOX,t.attributes.layout="horizontal",m(t);if(t.tagName===e.VERTICAL)return t.tagName=e.BOX,t.attributes.layout="vertical",m(t);if(t.tagName===e.ACTION){const i=t.attributes.type;switch(i){case"uri":return l.uri(t.attributes);case"postback":return l.postback(t.attributes);case"message":return l.message(t.attributes);case"datetimepicker":return l.datetimepicker(t.attributes);case"camera":return l.camera(t.attributes);case"cameraRoll":return l.cameraRoll(t.attributes);case"location":return l.location(t.attributes);case"richmenuswitch":return l.richmenuswitch(t.attributes);case"clipboard":return l.clipboard(t.attributes);default:u(`Unsupported action type: ${i}`)}}if(t.tagName===e.BACKGROUND)return t.attributes}const h={createElement:(t,r={},n=[],i=0)=>{const s=Object.entries(r).filter(([p,c])=>c!=null).map(([p,c])=>typeof c=="object"?`${p}="${JSON.stringify(c).replace(/"/g,""")}"`:`${p}="${c}"`).join(" "),a=s?` ${s}`:"";if(n.length===0)return` <${t}${a} />`;{const p=n.map(c=>typeof c=="string"?c.split(`
|
|
2
2
|
`).map(g=>g?" "+g:"").join(`
|
|
3
|
-
`):
|
|
4
|
-
`);return` <${t}${
|
|
3
|
+
`):c).join(`
|
|
4
|
+
`);return` <${t}${a}>
|
|
5
5
|
${p}
|
|
6
|
-
</${t}>`}},createText:t=>t},O=(t,r,
|
|
6
|
+
</${t}>`}},createText:t=>t},O=(t,r,n,i)=>{const o=[f(r,i+1)];return n&&Object.keys(n).length>0&&o.unshift(f(v("style",n),i+1)),h.createElement(t,{},o,i)},v=(t,r)=>({...r,type:t});function f(t,r=0){if(!t||typeof t!="object")return"";const{type:n,...i}=t,{action:o,...s}=i,a=o?f(o,r+1):"";switch(n){case"carousel":const{contents:p,...c}=s,g=p.map(d=>f(d,r+1));return a&&g.unshift(a),h.createElement(e.CAROUSEL,c,g,r);case"bubble":const{header:I,hero:L,body:w,footer:U,styles:A={},...J}=s,N=[];return a&&N.push(a),I&&N.push(O(e.HEADER,I,A.header,r+1)),L&&N.push(O(e.HERO,L,A.hero,r+1)),w&&N.push(O(e.BODY,w,A.body,r+1)),U&&N.push(O(e.FOOTER,U,A.footer,r+1)),h.createElement(e.BUBBLE,J,N,r);case"box":const{contents:q,background:k,...R}=s;R.layout||(R.layout="vertical");const C=[];return a&&C.push(a),k&&C.push(f(v("background",k),r+1)),C.push(...(q||[]).map(d=>f(d,r+1))),h.createElement(e.BOX,R,C,r);case"text":const{text:z,contents:B,..._}=s,D=B&&B.length>0?B.map(d=>f(d,r+1)):[z||""];return a&&D.unshift(a),h.createElement(e.TEXT,_,D,r);case"span":const{text:Q,...Z}=s,X=[Q||""];return a&&X.unshift(a),h.createElement(e.SPAN,Z,X,r);case"image":const{...tt}=s,et=a?[a]:[];return h.createElement(e.IMAGE,tt,et,r);case"video":const{altContent:$,...rt}=s,P=$?[f($,r+1)]:[];return a&&P.unshift(a),h.createElement(e.VIDEO,rt,P,r);case"icon":const{...at}=s,nt=a?[a]:[];return h.createElement(e.ICON,at,nt,r);case"button":const{...it}=s,st=a?[a]:[];return h.createElement(e.BUTTON,it,st,r);case"separator":const ct=a?[a]:[];return h.createElement(e.SEPARATOR,s,ct,r);case"filler":const lt=a?[a]:[];return h.createElement(e.FILLER,s,lt,r);case"uri":case"message":case"postback":case"datetimepicker":case"camera":case"cameraRoll":case"location":case"richmenuswitch":case"clipboard":return h.createElement(e.ACTION,{type:n,...s},[],r);case"background":return h.createElement(e.BACKGROUND,s,[],r);case"style":return h.createElement(e.STYLE,s,[],r);default:return""}}function W(t){try{return V(t).map(m)}catch(r){throw console.error("Error converting HTML to Flex Message:",r),r}}b.convertJsonToHtml=f,b.default=W,Object.defineProperties(b,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
|