@viewfly/platform-browser 0.3.1 → 0.4.0
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/bundles/create-app.d.ts +3 -3
- package/bundles/dom-renderer.d.ts +1 -1
- package/bundles/html-renderer.d.ts +52 -0
- package/bundles/index.esm.js +172 -11
- package/bundles/index.js +175 -10
- package/bundles/public-api.d.ts +1 -0
- package/package.json +3 -3
package/bundles/create-app.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { JSXNode, Application, Config } from '@viewfly/core';
|
|
1
|
+
import { JSXNode, Application, Config, NativeNode } from '@viewfly/core';
|
|
2
2
|
/**
|
|
3
3
|
* 创建一个 Viewfly 实例
|
|
4
4
|
* @param root 应用根节点
|
|
@@ -13,5 +13,5 @@ import { JSXNode, Application, Config } from '@viewfly/core';
|
|
|
13
13
|
* app.render() // 手动更新视图
|
|
14
14
|
* ```
|
|
15
15
|
*/
|
|
16
|
-
export declare function createApp(root: JSXNode, autoUpdate?: boolean): Application
|
|
17
|
-
export declare function createApp(root: JSXNode, config?: Omit<Config, '
|
|
16
|
+
export declare function createApp<T extends NativeNode>(root: JSXNode, autoUpdate?: boolean): Application<T>;
|
|
17
|
+
export declare function createApp<T extends NativeNode>(root: JSXNode, config?: Partial<Omit<Config, 'root'>>): Application<T>;
|
|
@@ -10,7 +10,6 @@ export declare class DomRenderer extends NativeRenderer<HTMLElement, Text> {
|
|
|
10
10
|
propMap: Record<string, Record<string, string>>;
|
|
11
11
|
createElement(name: string, isSvg: boolean): HTMLElement;
|
|
12
12
|
createTextNode(textContent: string): Text;
|
|
13
|
-
appendChild(parent: HTMLElement, newChild: any): void;
|
|
14
13
|
prependChild(parent: HTMLElement, newChild: HTMLElement | Text): void;
|
|
15
14
|
insertAfter(newNode: HTMLElement | Text, ref: HTMLElement | Text): void;
|
|
16
15
|
remove(node: HTMLElement | Text): void;
|
|
@@ -23,4 +22,5 @@ export declare class DomRenderer extends NativeRenderer<HTMLElement, Text> {
|
|
|
23
22
|
unListen(node: HTMLElement, type: string, callback: (ev: any) => any): void;
|
|
24
23
|
syncTextContent(target: Text, content: string): void;
|
|
25
24
|
private insertBefore;
|
|
25
|
+
private appendChild;
|
|
26
26
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { NativeRenderer } from '@viewfly/core';
|
|
2
|
+
export declare class VDOMElement {
|
|
3
|
+
name: string;
|
|
4
|
+
props: Map<string, any>;
|
|
5
|
+
children: Array<VDOMElement | VDomText>;
|
|
6
|
+
style: Map<string, any>;
|
|
7
|
+
className: string;
|
|
8
|
+
parent: VDOMElement | null;
|
|
9
|
+
constructor(name: string);
|
|
10
|
+
}
|
|
11
|
+
export declare class VDomText {
|
|
12
|
+
text: string;
|
|
13
|
+
parent: VDOMElement | null;
|
|
14
|
+
constructor(text: string);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 用于生成模拟轻量 DOM 节点的渲染器
|
|
18
|
+
*/
|
|
19
|
+
export declare class HTMLRenderer extends NativeRenderer<VDOMElement, VDomText> {
|
|
20
|
+
createElement(name: string): VDOMElement;
|
|
21
|
+
createTextNode(textContent: string): VDomText;
|
|
22
|
+
setProperty(node: VDOMElement, key: string, value: any): void;
|
|
23
|
+
prependChild(parent: VDOMElement, newChild: VDOMElement | VDomText): void;
|
|
24
|
+
removeProperty(node: VDOMElement, key: string): void;
|
|
25
|
+
setStyle(target: VDOMElement, key: string, value: any): void;
|
|
26
|
+
removeStyle(target: VDOMElement, key: string): void;
|
|
27
|
+
setClass(target: VDOMElement, value: string): void;
|
|
28
|
+
listen(): void;
|
|
29
|
+
unListen(): void;
|
|
30
|
+
remove(node: VDOMElement | VDomText): void;
|
|
31
|
+
syncTextContent(target: VDomText, content: string): void;
|
|
32
|
+
insertAfter(newNode: VDOMElement | VDomText, ref: VDOMElement | VDomText): void;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 轻量 DOM 转换为 HTML 字符串的转换器
|
|
36
|
+
*/
|
|
37
|
+
export declare class OutputTranslator {
|
|
38
|
+
static singleTags: string[];
|
|
39
|
+
static simpleXSSFilter: {
|
|
40
|
+
text(text: string): string;
|
|
41
|
+
attrName(text: string): string;
|
|
42
|
+
attrValue(text: string): string;
|
|
43
|
+
};
|
|
44
|
+
private singleTagTest;
|
|
45
|
+
/**
|
|
46
|
+
* 将虚拟 DOM 转换为 HTML 字符串的方法
|
|
47
|
+
* @param vDom 虚拟 DOM 节点
|
|
48
|
+
*/
|
|
49
|
+
transform(vDom: VDOMElement): string;
|
|
50
|
+
private vDomToHTMLString;
|
|
51
|
+
private replaceEmpty;
|
|
52
|
+
}
|
package/bundles/index.esm.js
CHANGED
|
@@ -12,12 +12,6 @@ class DomRenderer extends NativeRenderer {
|
|
|
12
12
|
}
|
|
13
13
|
};
|
|
14
14
|
}
|
|
15
|
-
// valueProps: Record<string, string[]> = {
|
|
16
|
-
// input: ['value'],
|
|
17
|
-
// option: ['value'],
|
|
18
|
-
// video: ['src'],
|
|
19
|
-
// audio: ['src']
|
|
20
|
-
// }
|
|
21
15
|
createElement(name, isSvg) {
|
|
22
16
|
if (isSvg) {
|
|
23
17
|
return document.createElementNS(DomRenderer.NAMESPACES.svg, name);
|
|
@@ -27,9 +21,6 @@ class DomRenderer extends NativeRenderer {
|
|
|
27
21
|
createTextNode(textContent) {
|
|
28
22
|
return document.createTextNode(textContent);
|
|
29
23
|
}
|
|
30
|
-
appendChild(parent, newChild) {
|
|
31
|
-
parent.appendChild(newChild);
|
|
32
|
-
}
|
|
33
24
|
prependChild(parent, newChild) {
|
|
34
25
|
parent.prepend(newChild);
|
|
35
26
|
}
|
|
@@ -105,6 +96,9 @@ class DomRenderer extends NativeRenderer {
|
|
|
105
96
|
insertBefore(newNode, ref) {
|
|
106
97
|
ref.parentNode.insertBefore(newNode, ref);
|
|
107
98
|
}
|
|
99
|
+
appendChild(parent, newChild) {
|
|
100
|
+
parent.appendChild(newChild);
|
|
101
|
+
}
|
|
108
102
|
}
|
|
109
103
|
DomRenderer.NAMESPACES = {
|
|
110
104
|
svg: 'http://www.w3.org/2000/svg',
|
|
@@ -122,7 +116,7 @@ function createApp(root, config = true) {
|
|
|
122
116
|
else if (typeof config === 'object') {
|
|
123
117
|
Object.assign(c, config);
|
|
124
118
|
}
|
|
125
|
-
return viewfly(Object.assign(Object.assign({}, c), { root, nativeRenderer: new DomRenderer() }));
|
|
119
|
+
return viewfly(Object.assign(Object.assign({}, c), { root, nativeRenderer: c.nativeRenderer || new DomRenderer() }));
|
|
126
120
|
}
|
|
127
121
|
|
|
128
122
|
const forkErrorFn = makeError('fork');
|
|
@@ -148,4 +142,171 @@ function fork(root, config = true) {
|
|
|
148
142
|
return app;
|
|
149
143
|
}
|
|
150
144
|
|
|
151
|
-
|
|
145
|
+
class VDOMElement {
|
|
146
|
+
constructor(name) {
|
|
147
|
+
this.name = name;
|
|
148
|
+
this.props = new Map();
|
|
149
|
+
this.children = [];
|
|
150
|
+
this.style = new Map();
|
|
151
|
+
this.className = '';
|
|
152
|
+
this.parent = null;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
class VDomText {
|
|
156
|
+
constructor(text) {
|
|
157
|
+
this.text = text;
|
|
158
|
+
this.parent = null;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* 用于生成模拟轻量 DOM 节点的渲染器
|
|
163
|
+
*/
|
|
164
|
+
class HTMLRenderer extends NativeRenderer {
|
|
165
|
+
createElement(name) {
|
|
166
|
+
return new VDOMElement(name);
|
|
167
|
+
}
|
|
168
|
+
createTextNode(textContent) {
|
|
169
|
+
return new VDomText(textContent);
|
|
170
|
+
}
|
|
171
|
+
setProperty(node, key, value) {
|
|
172
|
+
node.props.set(key, value);
|
|
173
|
+
}
|
|
174
|
+
prependChild(parent, newChild) {
|
|
175
|
+
parent.children.unshift(newChild);
|
|
176
|
+
newChild.parent = parent;
|
|
177
|
+
}
|
|
178
|
+
removeProperty(node, key) {
|
|
179
|
+
node.props.delete(key);
|
|
180
|
+
}
|
|
181
|
+
setStyle(target, key, value) {
|
|
182
|
+
target.style.set(key, value);
|
|
183
|
+
}
|
|
184
|
+
removeStyle(target, key) {
|
|
185
|
+
target.style.delete(key);
|
|
186
|
+
}
|
|
187
|
+
setClass(target, value) {
|
|
188
|
+
target.className = value;
|
|
189
|
+
}
|
|
190
|
+
listen() {
|
|
191
|
+
//
|
|
192
|
+
}
|
|
193
|
+
unListen() {
|
|
194
|
+
//
|
|
195
|
+
}
|
|
196
|
+
remove(node) {
|
|
197
|
+
if (node.parent) {
|
|
198
|
+
const i = node.parent.children.indexOf(node);
|
|
199
|
+
if (i > -1) {
|
|
200
|
+
node.parent.children.splice(i, 1);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
node.parent = null;
|
|
204
|
+
}
|
|
205
|
+
syncTextContent(target, content) {
|
|
206
|
+
target.text = content;
|
|
207
|
+
}
|
|
208
|
+
insertAfter(newNode, ref) {
|
|
209
|
+
const parent = ref.parent;
|
|
210
|
+
if (parent) {
|
|
211
|
+
const i = parent.children.indexOf(ref);
|
|
212
|
+
if (i > -1) {
|
|
213
|
+
newNode.parent = parent;
|
|
214
|
+
parent.children.splice(i + 1, 0, newNode);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* 轻量 DOM 转换为 HTML 字符串的转换器
|
|
221
|
+
*/
|
|
222
|
+
class OutputTranslator {
|
|
223
|
+
constructor() {
|
|
224
|
+
this.singleTagTest = new RegExp(`^(${OutputTranslator.singleTags.join('|')})$`, 'i');
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* 将虚拟 DOM 转换为 HTML 字符串的方法
|
|
228
|
+
* @param vDom 虚拟 DOM 节点
|
|
229
|
+
*/
|
|
230
|
+
transform(vDom) {
|
|
231
|
+
return vDom.children.map(child => {
|
|
232
|
+
return this.vDomToHTMLString(child);
|
|
233
|
+
}).join('');
|
|
234
|
+
}
|
|
235
|
+
vDomToHTMLString(vDom) {
|
|
236
|
+
const xssFilter = OutputTranslator.simpleXSSFilter;
|
|
237
|
+
if (vDom instanceof VDomText) {
|
|
238
|
+
return this.replaceEmpty(xssFilter.text(vDom.text), ' ');
|
|
239
|
+
}
|
|
240
|
+
const styles = Array.from(vDom.style.keys()).filter(key => {
|
|
241
|
+
const v = vDom.style.get(key);
|
|
242
|
+
return !(v === undefined || v === null || v === '');
|
|
243
|
+
}).map(key => {
|
|
244
|
+
const k = key.replace(/(?=[A-Z])/g, '-').toLowerCase();
|
|
245
|
+
return xssFilter.attrValue(`${k}:${vDom.style.get(key)}`);
|
|
246
|
+
}).join(';');
|
|
247
|
+
const attrs = Array.from(vDom.props.keys()).filter(key => key !== 'ref' && vDom.props.get(key) !== false).map(k => {
|
|
248
|
+
const key = xssFilter.attrName(k);
|
|
249
|
+
const value = vDom.props.get(k);
|
|
250
|
+
return (value === true ? `${key}` : `${key}="${xssFilter.attrValue(`${value}`)}"`);
|
|
251
|
+
});
|
|
252
|
+
if (styles) {
|
|
253
|
+
attrs.push(`style="${styles}"`);
|
|
254
|
+
}
|
|
255
|
+
if (vDom.className) {
|
|
256
|
+
attrs.push(`class="${xssFilter.attrValue(vDom.className)}"`);
|
|
257
|
+
}
|
|
258
|
+
let attrStr = attrs.join(' ');
|
|
259
|
+
attrStr = attrStr ? ' ' + attrStr : '';
|
|
260
|
+
if (this.singleTagTest.test(vDom.name)) {
|
|
261
|
+
return `<${vDom.name}${attrStr}>`;
|
|
262
|
+
}
|
|
263
|
+
const childHTML = vDom.children.map(child => {
|
|
264
|
+
return this.vDomToHTMLString(child);
|
|
265
|
+
}).join('');
|
|
266
|
+
return [
|
|
267
|
+
`<${vDom.name}${attrStr}>`,
|
|
268
|
+
childHTML,
|
|
269
|
+
`</${vDom.name}>`
|
|
270
|
+
].join('');
|
|
271
|
+
}
|
|
272
|
+
replaceEmpty(s, target) {
|
|
273
|
+
return s.replace(/\s\s+/g, str => {
|
|
274
|
+
return ' ' + Array.from({
|
|
275
|
+
length: str.length - 1
|
|
276
|
+
}).fill(target).join('');
|
|
277
|
+
}).replace(/^\s|\s$/g, target);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
OutputTranslator.singleTags = 'br,img,hr'.split(',');
|
|
281
|
+
OutputTranslator.simpleXSSFilter = {
|
|
282
|
+
text(text) {
|
|
283
|
+
return text.replace(/[><&]/g, str => {
|
|
284
|
+
return {
|
|
285
|
+
'<': '<',
|
|
286
|
+
'>': '>',
|
|
287
|
+
'&': '&'
|
|
288
|
+
}[str];
|
|
289
|
+
});
|
|
290
|
+
},
|
|
291
|
+
attrName(text) {
|
|
292
|
+
return text.replace(/[><"'&]/g, str => {
|
|
293
|
+
return {
|
|
294
|
+
'<': '<',
|
|
295
|
+
'>': '>',
|
|
296
|
+
'"': '"',
|
|
297
|
+
'\'': ''',
|
|
298
|
+
'&': '&'
|
|
299
|
+
}[str];
|
|
300
|
+
});
|
|
301
|
+
},
|
|
302
|
+
attrValue(text) {
|
|
303
|
+
return text.replace(/["']/g, str => {
|
|
304
|
+
return {
|
|
305
|
+
'"': '"',
|
|
306
|
+
'\'': '''
|
|
307
|
+
}[str];
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
export { DomRenderer, HTMLRenderer, OutputTranslator, VDOMElement, VDomText, createApp, fork };
|
package/bundles/index.js
CHANGED
|
@@ -14,12 +14,6 @@ class DomRenderer extends core.NativeRenderer {
|
|
|
14
14
|
}
|
|
15
15
|
};
|
|
16
16
|
}
|
|
17
|
-
// valueProps: Record<string, string[]> = {
|
|
18
|
-
// input: ['value'],
|
|
19
|
-
// option: ['value'],
|
|
20
|
-
// video: ['src'],
|
|
21
|
-
// audio: ['src']
|
|
22
|
-
// }
|
|
23
17
|
createElement(name, isSvg) {
|
|
24
18
|
if (isSvg) {
|
|
25
19
|
return document.createElementNS(DomRenderer.NAMESPACES.svg, name);
|
|
@@ -29,9 +23,6 @@ class DomRenderer extends core.NativeRenderer {
|
|
|
29
23
|
createTextNode(textContent) {
|
|
30
24
|
return document.createTextNode(textContent);
|
|
31
25
|
}
|
|
32
|
-
appendChild(parent, newChild) {
|
|
33
|
-
parent.appendChild(newChild);
|
|
34
|
-
}
|
|
35
26
|
prependChild(parent, newChild) {
|
|
36
27
|
parent.prepend(newChild);
|
|
37
28
|
}
|
|
@@ -107,6 +98,9 @@ class DomRenderer extends core.NativeRenderer {
|
|
|
107
98
|
insertBefore(newNode, ref) {
|
|
108
99
|
ref.parentNode.insertBefore(newNode, ref);
|
|
109
100
|
}
|
|
101
|
+
appendChild(parent, newChild) {
|
|
102
|
+
parent.appendChild(newChild);
|
|
103
|
+
}
|
|
110
104
|
}
|
|
111
105
|
DomRenderer.NAMESPACES = {
|
|
112
106
|
svg: 'http://www.w3.org/2000/svg',
|
|
@@ -124,7 +118,7 @@ function createApp(root, config = true) {
|
|
|
124
118
|
else if (typeof config === 'object') {
|
|
125
119
|
Object.assign(c, config);
|
|
126
120
|
}
|
|
127
|
-
return core.viewfly(Object.assign(Object.assign({}, c), { root, nativeRenderer: new DomRenderer() }));
|
|
121
|
+
return core.viewfly(Object.assign(Object.assign({}, c), { root, nativeRenderer: c.nativeRenderer || new DomRenderer() }));
|
|
128
122
|
}
|
|
129
123
|
|
|
130
124
|
const forkErrorFn = core.makeError('fork');
|
|
@@ -150,6 +144,177 @@ function fork(root, config = true) {
|
|
|
150
144
|
return app;
|
|
151
145
|
}
|
|
152
146
|
|
|
147
|
+
class VDOMElement {
|
|
148
|
+
constructor(name) {
|
|
149
|
+
this.name = name;
|
|
150
|
+
this.props = new Map();
|
|
151
|
+
this.children = [];
|
|
152
|
+
this.style = new Map();
|
|
153
|
+
this.className = '';
|
|
154
|
+
this.parent = null;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
class VDomText {
|
|
158
|
+
constructor(text) {
|
|
159
|
+
this.text = text;
|
|
160
|
+
this.parent = null;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* 用于生成模拟轻量 DOM 节点的渲染器
|
|
165
|
+
*/
|
|
166
|
+
class HTMLRenderer extends core.NativeRenderer {
|
|
167
|
+
createElement(name) {
|
|
168
|
+
return new VDOMElement(name);
|
|
169
|
+
}
|
|
170
|
+
createTextNode(textContent) {
|
|
171
|
+
return new VDomText(textContent);
|
|
172
|
+
}
|
|
173
|
+
setProperty(node, key, value) {
|
|
174
|
+
node.props.set(key, value);
|
|
175
|
+
}
|
|
176
|
+
prependChild(parent, newChild) {
|
|
177
|
+
parent.children.unshift(newChild);
|
|
178
|
+
newChild.parent = parent;
|
|
179
|
+
}
|
|
180
|
+
removeProperty(node, key) {
|
|
181
|
+
node.props.delete(key);
|
|
182
|
+
}
|
|
183
|
+
setStyle(target, key, value) {
|
|
184
|
+
target.style.set(key, value);
|
|
185
|
+
}
|
|
186
|
+
removeStyle(target, key) {
|
|
187
|
+
target.style.delete(key);
|
|
188
|
+
}
|
|
189
|
+
setClass(target, value) {
|
|
190
|
+
target.className = value;
|
|
191
|
+
}
|
|
192
|
+
listen() {
|
|
193
|
+
//
|
|
194
|
+
}
|
|
195
|
+
unListen() {
|
|
196
|
+
//
|
|
197
|
+
}
|
|
198
|
+
remove(node) {
|
|
199
|
+
if (node.parent) {
|
|
200
|
+
const i = node.parent.children.indexOf(node);
|
|
201
|
+
if (i > -1) {
|
|
202
|
+
node.parent.children.splice(i, 1);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
node.parent = null;
|
|
206
|
+
}
|
|
207
|
+
syncTextContent(target, content) {
|
|
208
|
+
target.text = content;
|
|
209
|
+
}
|
|
210
|
+
insertAfter(newNode, ref) {
|
|
211
|
+
const parent = ref.parent;
|
|
212
|
+
if (parent) {
|
|
213
|
+
const i = parent.children.indexOf(ref);
|
|
214
|
+
if (i > -1) {
|
|
215
|
+
newNode.parent = parent;
|
|
216
|
+
parent.children.splice(i + 1, 0, newNode);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* 轻量 DOM 转换为 HTML 字符串的转换器
|
|
223
|
+
*/
|
|
224
|
+
class OutputTranslator {
|
|
225
|
+
constructor() {
|
|
226
|
+
this.singleTagTest = new RegExp(`^(${OutputTranslator.singleTags.join('|')})$`, 'i');
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* 将虚拟 DOM 转换为 HTML 字符串的方法
|
|
230
|
+
* @param vDom 虚拟 DOM 节点
|
|
231
|
+
*/
|
|
232
|
+
transform(vDom) {
|
|
233
|
+
return vDom.children.map(child => {
|
|
234
|
+
return this.vDomToHTMLString(child);
|
|
235
|
+
}).join('');
|
|
236
|
+
}
|
|
237
|
+
vDomToHTMLString(vDom) {
|
|
238
|
+
const xssFilter = OutputTranslator.simpleXSSFilter;
|
|
239
|
+
if (vDom instanceof VDomText) {
|
|
240
|
+
return this.replaceEmpty(xssFilter.text(vDom.text), ' ');
|
|
241
|
+
}
|
|
242
|
+
const styles = Array.from(vDom.style.keys()).filter(key => {
|
|
243
|
+
const v = vDom.style.get(key);
|
|
244
|
+
return !(v === undefined || v === null || v === '');
|
|
245
|
+
}).map(key => {
|
|
246
|
+
const k = key.replace(/(?=[A-Z])/g, '-').toLowerCase();
|
|
247
|
+
return xssFilter.attrValue(`${k}:${vDom.style.get(key)}`);
|
|
248
|
+
}).join(';');
|
|
249
|
+
const attrs = Array.from(vDom.props.keys()).filter(key => key !== 'ref' && vDom.props.get(key) !== false).map(k => {
|
|
250
|
+
const key = xssFilter.attrName(k);
|
|
251
|
+
const value = vDom.props.get(k);
|
|
252
|
+
return (value === true ? `${key}` : `${key}="${xssFilter.attrValue(`${value}`)}"`);
|
|
253
|
+
});
|
|
254
|
+
if (styles) {
|
|
255
|
+
attrs.push(`style="${styles}"`);
|
|
256
|
+
}
|
|
257
|
+
if (vDom.className) {
|
|
258
|
+
attrs.push(`class="${xssFilter.attrValue(vDom.className)}"`);
|
|
259
|
+
}
|
|
260
|
+
let attrStr = attrs.join(' ');
|
|
261
|
+
attrStr = attrStr ? ' ' + attrStr : '';
|
|
262
|
+
if (this.singleTagTest.test(vDom.name)) {
|
|
263
|
+
return `<${vDom.name}${attrStr}>`;
|
|
264
|
+
}
|
|
265
|
+
const childHTML = vDom.children.map(child => {
|
|
266
|
+
return this.vDomToHTMLString(child);
|
|
267
|
+
}).join('');
|
|
268
|
+
return [
|
|
269
|
+
`<${vDom.name}${attrStr}>`,
|
|
270
|
+
childHTML,
|
|
271
|
+
`</${vDom.name}>`
|
|
272
|
+
].join('');
|
|
273
|
+
}
|
|
274
|
+
replaceEmpty(s, target) {
|
|
275
|
+
return s.replace(/\s\s+/g, str => {
|
|
276
|
+
return ' ' + Array.from({
|
|
277
|
+
length: str.length - 1
|
|
278
|
+
}).fill(target).join('');
|
|
279
|
+
}).replace(/^\s|\s$/g, target);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
OutputTranslator.singleTags = 'br,img,hr'.split(',');
|
|
283
|
+
OutputTranslator.simpleXSSFilter = {
|
|
284
|
+
text(text) {
|
|
285
|
+
return text.replace(/[><&]/g, str => {
|
|
286
|
+
return {
|
|
287
|
+
'<': '<',
|
|
288
|
+
'>': '>',
|
|
289
|
+
'&': '&'
|
|
290
|
+
}[str];
|
|
291
|
+
});
|
|
292
|
+
},
|
|
293
|
+
attrName(text) {
|
|
294
|
+
return text.replace(/[><"'&]/g, str => {
|
|
295
|
+
return {
|
|
296
|
+
'<': '<',
|
|
297
|
+
'>': '>',
|
|
298
|
+
'"': '"',
|
|
299
|
+
'\'': ''',
|
|
300
|
+
'&': '&'
|
|
301
|
+
}[str];
|
|
302
|
+
});
|
|
303
|
+
},
|
|
304
|
+
attrValue(text) {
|
|
305
|
+
return text.replace(/["']/g, str => {
|
|
306
|
+
return {
|
|
307
|
+
'"': '"',
|
|
308
|
+
'\'': '''
|
|
309
|
+
}[str];
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
|
|
153
314
|
exports.DomRenderer = DomRenderer;
|
|
315
|
+
exports.HTMLRenderer = HTMLRenderer;
|
|
316
|
+
exports.OutputTranslator = OutputTranslator;
|
|
317
|
+
exports.VDOMElement = VDOMElement;
|
|
318
|
+
exports.VDomText = VDomText;
|
|
154
319
|
exports.createApp = createApp;
|
|
155
320
|
exports.fork = fork;
|
package/bundles/public-api.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@viewfly/platform-browser",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "This project is used to enable the Viewfly framework to run in a browser.",
|
|
5
5
|
"main": "./bundles/index.js",
|
|
6
6
|
"module": "./bundles/index.esm.js",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"license": "MIT",
|
|
13
13
|
"keywords": [],
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@viewfly/core": "^0.
|
|
15
|
+
"@viewfly/core": "^0.4.0",
|
|
16
16
|
"csstype": "^3.1.2"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
@@ -33,5 +33,5 @@
|
|
|
33
33
|
"bugs": {
|
|
34
34
|
"url": "https://github.com/viewfly/viewfly.git/issues"
|
|
35
35
|
},
|
|
36
|
-
"gitHead": "
|
|
36
|
+
"gitHead": "d14b3cd0247a07f72519745933c3070f12adbfa1"
|
|
37
37
|
}
|