1 | const escape = require('html-escaper').escape;
|
2 |
|
3 | const Attr = require('./Attr');
|
4 | const Element = require('./Element');
|
5 | const DOMStringMap = require('./DOMStringMap');
|
6 | const CSSStyleDeclaration = require('./CSSStyleDeclaration');
|
7 |
|
8 | const {setPrototypeOf} = Object;
|
9 |
|
10 |
|
11 | class HTMLElement extends Element {
|
12 | constructor(ownerDocument, name) {
|
13 | super(ownerDocument, name);
|
14 | this.dataset = new DOMStringMap(this);
|
15 | this.style = new CSSStyleDeclaration();
|
16 | const style = new Attr(this, 'style', this.style);
|
17 | this.attributes.push(style);
|
18 | this.attributes.style = style;
|
19 | this.__isCE = -1;
|
20 | }
|
21 | get isCustomElement() {
|
22 | if (this.__isCE < 0) {
|
23 | this.__isCE = 0;
|
24 | const is = this.getAttribute('is') || this.nodeName;
|
25 | const ceName = -1 < is.indexOf('-');
|
26 | if (ceName) {
|
27 | const Class = this.ownerDocument.customElements.get(is);
|
28 | if (Class) {
|
29 | this.__isCE = 1;
|
30 | setPrototypeOf(this, Class.prototype);
|
31 | }
|
32 | }
|
33 | }
|
34 | return this.__isCE === 1;
|
35 | }
|
36 | }
|
37 |
|
38 | [
|
39 | 'click',
|
40 | 'focus',
|
41 | 'blur'
|
42 | ].forEach(type => {
|
43 | Object.defineProperty(HTMLElement.prototype, type, {
|
44 | configurable: true,
|
45 | value: function () {
|
46 | const {ownerDocument} = this;
|
47 | ownerDocument.activeElement = type === 'blur' ? null : this;
|
48 | const event = ownerDocument.createEvent('Event');
|
49 | event.initEvent(type, true, true);
|
50 | this.dispatchEvent(event);
|
51 | }
|
52 | });
|
53 | });
|
54 |
|
55 | [
|
56 | 'title',
|
57 | 'lang',
|
58 | 'translate',
|
59 | 'dir',
|
60 | 'hidden',
|
61 | 'tabIndex',
|
62 | 'accessKey',
|
63 | 'draggable',
|
64 | 'spellcheck',
|
65 | 'contentEditable'
|
66 | ].forEach(name => {
|
67 | const lowName = name;
|
68 | Object.defineProperty(HTMLElement.prototype, name, {
|
69 | configurable: true,
|
70 | get() { return this.getAttribute(lowName); },
|
71 | set(value) { this.setAttribute(lowName, value); }
|
72 | });
|
73 | });
|
74 |
|
75 |
|
76 |
|
77 |
|
78 | [
|
79 | 'onabort',
|
80 | 'onblur',
|
81 | 'oncancel',
|
82 | 'oncanplay',
|
83 | 'oncanplaythrough',
|
84 | 'onchange',
|
85 | 'onclick',
|
86 | 'onclose',
|
87 | 'oncontextmenu',
|
88 | 'oncuechange',
|
89 | 'ondblclick',
|
90 | 'ondrag',
|
91 | 'ondragend',
|
92 | 'ondragenter',
|
93 | 'ondragleave',
|
94 | 'ondragover',
|
95 | 'ondragstart',
|
96 | 'ondrop',
|
97 | 'ondurationchange',
|
98 | 'onemptied',
|
99 | 'onended',
|
100 | 'onerror',
|
101 | 'onfocus',
|
102 | 'oninput',
|
103 | 'oninvalid',
|
104 | 'onkeydown',
|
105 | 'onkeypress',
|
106 | 'onkeyup',
|
107 | 'onload',
|
108 | 'onloadeddata',
|
109 | 'onloadedmetadata',
|
110 | 'onloadstart',
|
111 | 'onmousedown',
|
112 | 'onmouseenter',
|
113 | 'onmouseleave',
|
114 | 'onmousemove',
|
115 | 'onmouseout',
|
116 | 'onmouseover',
|
117 | 'onmouseup',
|
118 | 'onmousewheel',
|
119 | 'onpause',
|
120 | 'onplay',
|
121 | 'onplaying',
|
122 | 'onprogress',
|
123 | 'onratechange',
|
124 | 'onreset',
|
125 | 'onresize',
|
126 | 'onscroll',
|
127 | 'onseeked',
|
128 | 'onseeking',
|
129 | 'onselect',
|
130 | 'onshow',
|
131 | 'onstalled',
|
132 | 'onsubmit',
|
133 | 'onsuspend',
|
134 | 'ontimeupdate',
|
135 | 'ontoggle',
|
136 | 'onvolumechange',
|
137 | 'onwaiting',
|
138 | 'onauxclick',
|
139 | 'ongotpointercapture',
|
140 | 'onlostpointercapture',
|
141 | 'onpointercancel',
|
142 | 'onpointerdown',
|
143 | 'onpointerenter',
|
144 | 'onpointerleave',
|
145 | 'onpointermove',
|
146 | 'onpointerout',
|
147 | 'onpointerover',
|
148 | 'onpointerup'
|
149 | ].forEach(ontype => {
|
150 | let _value = null;
|
151 | const type = ontype.slice(2);
|
152 | Object.defineProperty(HTMLElement.prototype, ontype, {
|
153 | configurable: true,
|
154 | get() {
|
155 | return _value;
|
156 | },
|
157 | set(value) {
|
158 | if (!value) {
|
159 | if (_value) {
|
160 | value = _value;
|
161 | _value = null;
|
162 | this.removeEventListener(type, value);
|
163 | }
|
164 | this.removeAttribute(ontype);
|
165 | } else {
|
166 | _value = value;
|
167 | this.addEventListener(type, value);
|
168 | this.setAttribute(ontype, 'return (' + escape(
|
169 | JS_SHORTCUT.test(value) && !JS_FUNCTION.test(value) ?
|
170 | ('function ' + value) :
|
171 | ('' + value)
|
172 | ) + ').call(this, event)');
|
173 | }
|
174 | }
|
175 | });
|
176 | });
|
177 |
|
178 |
|
179 | const JS_SHORTCUT = /^[a-z$_]\S*?\(/;
|
180 | const JS_FUNCTION = /^function\S*?\(/;
|
181 |
|
182 | module.exports = HTMLElement;
|