• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16const propsMap: string[] = ['disabled', 'hidden', 'checked', 'selected', 'required', 'open', 'readonly'];
17
18declare interface HTMLTemplateElement {
19    render(data: any): any
20}
21
22(HTMLTemplateElement as any).prototype.render = function (data: any) {
23    if (!this.$fragment) {
24        const rule = this.getAttribute("rule") || 'v-';
25        this.$fragment = this.cloneNode(true);
26        this.fragment = document.createElement('TEMPLATE');
27
28        // v-for
29        const repeatEls = this.$fragment.content.querySelectorAll(`[\\${rule}for]`);
30        repeatEls.forEach((el: any) => {
31            const strFor = el.getAttribute(`${rule}for`);
32            const {isArray, items, params} = parseFor(strFor);
33            el.before('${Object.entries(' + items + ').map(function([' + `${(isArray ? '$index$' : (params[1] || 'name'))},${params[0] || (isArray ? 'item' : 'value')}],${params[2] || 'index'}` + '){ return `');
34            el.removeAttribute(`${rule}for`);
35            el.after('`}).join("")}');
36        })
37
38        // v-if
39        const ifEls = this.$fragment.content.querySelectorAll(`[\\${rule}if]`);
40        ifEls.forEach((el: any) => {
41            const ifs = el.getAttribute(`${rule}if`);
42            el.before('${' + ifs + '?`');
43            el.removeAttribute(`${rule}if`);
44            el.after('`:`<!--if:' + el.tagName + '-->`}');
45        })
46
47        // fragment
48        const fragments = this.$fragment.content.querySelectorAll('fragment,block');
49        fragments.forEach((el: any) => {
50            el.after(el.innerHTML);
51            el.parentNode.removeChild(el);
52        })
53    }
54    this.fragment.innerHTML = this.$fragment.innerHTML.interpolate(data);
55
56    // props
57    const propsEls = this.fragment.content.querySelectorAll(`[${propsMap.join('],[')}]`);
58    propsEls.forEach((el: any) => {
59        propsMap.forEach((props: any) => {
60            if (el.getAttribute(props) === 'false') {
61                el.removeAttribute(props);
62            }
63        })
64    })
65    return this.fragment;
66}
67
68function parseFor(strFor: String) {
69    const isObject = strFor.includes(' of ');
70    const reg = /\s(?:in|of)\s/g;
71    const [keys, obj] = strFor.match(reg) ? strFor.split(reg) : ["item", strFor];
72    const items = Number(obj) > 0 ? `[${'null,'.repeat(Number(obj) - 1)}null]` : obj;
73    const params = keys.split(/[\(|\)|,\s?]/g).filter(Boolean);
74    return {isArray: !isObject, items, params}
75}
76
77(String as any).prototype.interpolate = function (params: any) {
78    const names = Object.keys(params);
79    const vals = Object.values(params);
80    const str = this.replace(/\{\{([^\}]+)\}\}/g, (all: any, s: any) => `\${${s}}`);
81    return new Function(...names, `return \`${escape2Html(str)}\`;`)(...vals);
82};
83
84function escape2Html(str: string) {
85    let arrEntities: any = {'lt': '<', 'gt': '>', 'nbsp': ' ', 'amp': '&', 'quot': '"'};
86    return str.replace(/&(lt|gt|nbsp|amp|quot);/ig, function (all, t) {
87        return arrEntities[t];
88    });
89}
90