• 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 Loop rendering
29    // <div v-for="list"></div>   =>    ${ list.map(function(item,index){ return '<div></div>' }).join('') }
30    const repeatEls = this.$fragment.content.querySelectorAll(`[\\${rule}for]`);
31    repeatEls.forEach((el: any) => {
32      const strFor = el.getAttribute(`${rule}for`);
33      const { isArray, items, params } = parseFor(strFor);
34      el.before(
35        '${Object.entries(' +
36          items +
37          ').map(function([' +
38          `${isArray ? '$index$' : params[1] || 'name'},${params[0] || (isArray ? 'item' : 'value')}],${
39            params[2] || 'index'
40          }` +
41          '){ return `'
42      );
43      el.removeAttribute(`${rule}for`);
44      el.after('`}).join("")}');
45    });
46
47    // v-if Conditional rendering
48    // <div v-if="if"></div>   =>    ${ if ? '<div></div>' : '' }
49    const ifEls = this.$fragment.content.querySelectorAll(`[\\${rule}if]`);
50    ifEls.forEach((el: any) => {
51      const ifs = el.getAttribute(`${rule}if`);
52      el.before('${' + ifs + '?`');
53      el.removeAttribute(`${rule}if`);
54      el.after('`:`<!--if:' + el.tagName + '-->`}');
55    });
56
57    // fragment   <fragment>aa</fragment>   =>  aa
58    const fragments = this.$fragment.content.querySelectorAll('fragment,block');
59    fragments.forEach((el: any) => {
60      el.after(el.innerHTML);
61      el.parentNode.removeChild(el);
62    });
63  }
64  this.fragment.innerHTML = this.$fragment.innerHTML.interpolate(data);
65
66  // props
67  const propsEls = this.fragment.content.querySelectorAll(`[${propsMap.join('],[')}]`);
68  propsEls.forEach((el: any) => {
69    propsMap.forEach((props: any) => {
70      // If these attribute values are false, they are removed directly
71      if (el.getAttribute(props) === 'false') {
72        el.removeAttribute(props);
73      }
74    });
75  });
76  return this.fragment;
77};
78
79function parseFor(strFor: String) {
80  // Whether it is an object
81  const isObject = strFor.includes(' of ');
82  const reg = /\s(?:in|of)\s/g;
83  const [keys, obj] = strFor.match(reg) ? strFor.split(reg) : ['item', strFor];
84  const items = Number(obj) > 0 ? `[${'null,'.repeat(Number(obj) - 1)}null]` : obj;
85  const params = keys.split(/[\(|\)|,\s?]/g).filter(Boolean);
86  return { isArray: !isObject, items, params };
87}
88
89// String to template string
90(String as any).prototype.interpolate = function (params: any) {
91  const names = Object.keys(params);
92  // @ts-ignore
93  const vals = Object.values(params);
94  const str = this.replace(/\{\{([^\}]+)\}\}/g, (all: any, s: any) => `\${${s}}`);
95  return new Function(...names, `return \`${escape2Html(str)}\`;`)(...vals);
96};
97
98// HTML Character inversion meaning   &lt;  =>  <
99function escape2Html(str: string) {
100  let arrEntities: any = { lt: '<', gt: '>', nbsp: ' ', amp: '&', quot: '"' };
101  return str.replace(/&(lt|gt|nbsp|amp|quot);/gi, function (all, t) {
102    return arrEntities[t];
103  });
104}
105