1 | /**
|
2 | * Create a DOM element from a CSS query with option to include content
|
3 | *
|
4 | * @author Laurent Blanes <laurent.blanes@gmail.com>
|
5 | * @param {String} querySelector (optional) default to div
|
6 | * @param {...*} [content] (optional) String|Number|DOMElement
|
7 | * @return DOMElement
|
8 | *
|
9 | * @example
|
10 | * - createElement(); // <div>
|
11 | * - createElement('span#my-id.my-class.second-class'); // <span id="my-id" class="my-class second-class">
|
12 | * - createElement('#my-id.my-class.second-class', 'text to insert', 12345); // <div id="my-id" class="my-class second-class">
|
13 | * - const div = createElement('#my-div',
|
14 | * 'Random text',
|
15 | * createElement('p.paragraph', 'my text'),
|
16 | * createElement('p.paragraph', 'my second text'),
|
17 | * createElement('a.link[href=https://github.com/hekigan/create-element]', 'link to a site'),
|
18 | * ); // <div id="my-id" class="my-class second-class">
|
19 | * // Random text
|
20 | * // <p class="paragraph">my text</p>
|
21 | * // <p class="paragraph">my second text</p>
|
22 | * // <a class="link" href="https://github.com/hekigan/create-element" class="paragraph">link to a site</a>
|
23 | * // </div>
|
24 | */
|
25 | export default function createElement (querySelector = 'div', ...content) {
|
26 | let nodeType = querySelector.match(/^[a-z]+/i);
|
27 | let id = querySelector.match(/#([a-z]+[a-z0-9-]*)/gi);
|
28 | let classes = querySelector.match(/\.([a-z]+[a-z0-9-]*)/gi);
|
29 | let attributes = querySelector.match(/\[([a-z][a-z-]+)(=['|"]?([^\]]*)['|"]?)?\]/gi);
|
30 | let node = (nodeType) ? nodeType[0] : 'div';
|
31 |
|
32 | if (id && id.length > 1) {
|
33 | throw CreateElementException('only 1 ID is allowed');
|
34 | }
|
35 |
|
36 | const elt = document.createElement(node);
|
37 |
|
38 | if (id) {
|
39 | elt.id = id[0].replace('#', '');
|
40 | }
|
41 |
|
42 | if (classes) {
|
43 | const attrClasses = classes.join(' ').replace(/\./g, '');
|
44 | elt.setAttribute('class', attrClasses);
|
45 | }
|
46 |
|
47 | if (attributes) {
|
48 | attributes.forEach(item => {
|
49 | item = item.slice(0, -1).slice(1);
|
50 | let [label, value] = item.split('=');
|
51 | if (value) {
|
52 | value = value.replace(/^['"](.*)['"]$/, '$1');
|
53 | }
|
54 | elt.setAttribute(label, value || '');
|
55 | });
|
56 | }
|
57 |
|
58 | content.forEach(item => {
|
59 | if (typeof item === 'string' || typeof item === 'number') {
|
60 | elt.appendChild(document.createTextNode(item));
|
61 | } else if (item.nodeType === document.ELEMENT_NODE) {
|
62 | elt.appendChild(item);
|
63 | }
|
64 | });
|
65 |
|
66 | return elt;
|
67 | }
|
68 |
|
69 | function CreateElementException (message) {
|
70 | this.message = message;
|
71 | this.name = 'CreateElementException';
|
72 | }
|