1 | // @ts-check
|
2 | /** @typedef {import("../typings").HtmlTagObject} HtmlTagObject */
|
3 | /**
|
4 | * @file
|
5 | * This file provides to helper to create html as a object representation as
|
6 | * those objects are easier to modify than pure string representations
|
7 | *
|
8 | * Usage:
|
9 | * ```
|
10 | * const element = createHtmlTagObject('h1', {class: 'demo'}, 'Hello World');
|
11 | * const html = htmlTagObjectToString(element);
|
12 | * console.log(html) // -> <h1 class="demo">Hello World</h1>
|
13 | * ```
|
14 | */
|
15 |
|
16 | /**
|
17 | * All html tag elements which must not contain innerHTML
|
18 | * @see https://www.w3.org/TR/html5/syntax.html#void-elements
|
19 | */
|
20 | const voidTags = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'];
|
21 |
|
22 | /**
|
23 | * Turn a tag definition into a html string
|
24 | * @param {HtmlTagObject} tagDefinition
|
25 | * A tag element according to the htmlWebpackPlugin object notation
|
26 | *
|
27 | * @param xhtml {boolean}
|
28 | * Whether the generated html should add closing slashes to be xhtml compliant
|
29 | */
|
30 | function htmlTagObjectToString (tagDefinition, xhtml) {
|
31 | const attributes = Object.keys(tagDefinition.attributes || {})
|
32 | .filter(function (attributeName) {
|
33 | return tagDefinition.attributes[attributeName] === '' || tagDefinition.attributes[attributeName];
|
34 | })
|
35 | .map(function (attributeName) {
|
36 | if (tagDefinition.attributes[attributeName] === true) {
|
37 | return xhtml ? attributeName + '="' + attributeName + '"' : attributeName;
|
38 | }
|
39 | return attributeName + '="' + tagDefinition.attributes[attributeName] + '"';
|
40 | });
|
41 | return '<' + [tagDefinition.tagName].concat(attributes).join(' ') + (tagDefinition.voidTag && xhtml ? '/' : '') + '>' +
|
42 | (tagDefinition.innerHTML || '') +
|
43 | (tagDefinition.voidTag ? '' : '</' + tagDefinition.tagName + '>');
|
44 | }
|
45 |
|
46 | /**
|
47 | * Static helper to create a tag object to be get injected into the dom
|
48 | *
|
49 | * @param {string} tagName
|
50 | * the name of the tag e.g. 'div'
|
51 | *
|
52 | * @param {{[attributeName: string]: string|boolean|null|undefined}} [attributes]
|
53 | * tag attributes e.g. `{ 'class': 'example', disabled: true }`
|
54 | *
|
55 | * @param {string} [innerHTML]
|
56 | *
|
57 | * @param {{[attributeName: string]: string|boolean|null|undefined}} [meta]
|
58 | * meta information about the tag e.g. `{ 'plugin': 'html-webpack-plugin' }`
|
59 | *
|
60 | * @returns {HtmlTagObject}
|
61 | */
|
62 | function createHtmlTagObject (tagName, attributes, innerHTML, meta) {
|
63 | return {
|
64 | tagName: tagName,
|
65 | voidTag: voidTags.indexOf(tagName) !== -1,
|
66 | attributes: attributes || {},
|
67 | meta: meta || {},
|
68 | innerHTML: innerHTML
|
69 | };
|
70 | }
|
71 |
|
72 | /**
|
73 | * The `HtmlTagArray Array with a custom `.toString()` method.
|
74 | *
|
75 | * This allows the following:
|
76 | * ```
|
77 | * const tags = HtmlTagArray.from([tag1, tag2]);
|
78 | * const scriptTags = tags.filter((tag) => tag.tagName === 'script');
|
79 | * const html = scriptTags.toString();
|
80 | * ```
|
81 | *
|
82 | * Or inside a string literal:
|
83 | * ```
|
84 | * const tags = HtmlTagArray.from([tag1, tag2]);
|
85 | * const html = `<html><body>${tags.filter((tag) => tag.tagName === 'script')}</body></html>`;
|
86 | * ```
|
87 | *
|
88 | */
|
89 | class HtmlTagArray extends Array {
|
90 | toString () {
|
91 | return this.join('');
|
92 | }
|
93 | }
|
94 |
|
95 | module.exports = {
|
96 | HtmlTagArray: HtmlTagArray,
|
97 | createHtmlTagObject: createHtmlTagObject,
|
98 | htmlTagObjectToString: htmlTagObjectToString
|
99 | };
|