@shgysk8zer0/polyfills 0.4.12 → 0.4.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/all.min.js +6 -6
- package/all.min.js.map +1 -1
- package/browser.min.js +6 -6
- package/browser.min.js.map +1 -1
- package/command.js +146 -0
- package/element.js +1 -0
- package/package.json +1 -1
package/command.js
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
if (! ('command' in HTMLButtonElement.prototype)) {
|
|
2
|
+
const COMMAND_FOR = Symbol('command:for');
|
|
3
|
+
|
|
4
|
+
const CLICK_OPTIONS = { passive: true };
|
|
5
|
+
|
|
6
|
+
Object.defineProperty(HTMLButtonElement.prototype, 'command', {
|
|
7
|
+
get() {
|
|
8
|
+
return this.getAttribute('command');
|
|
9
|
+
},
|
|
10
|
+
set(val) {
|
|
11
|
+
if (typeof val === 'string') {
|
|
12
|
+
this.setAttribute('command', val);
|
|
13
|
+
} else {
|
|
14
|
+
this.removeAttribute('command');
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
Object.defineProperty(HTMLButtonElement.prototype, 'commandForElement', {
|
|
20
|
+
get() {
|
|
21
|
+
if (this[COMMAND_FOR] instanceof Element) {
|
|
22
|
+
return this[COMMAND_FOR];
|
|
23
|
+
} else if (this.hasAttribute('commandfor')) {
|
|
24
|
+
return document.getElementById(this.getAttribute('commandfor'));
|
|
25
|
+
} else {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
set(val) {
|
|
30
|
+
if (! (val instanceof Element)) {
|
|
31
|
+
this.removeAttribute('commandfor');
|
|
32
|
+
this[COMMAND_FOR] = null;
|
|
33
|
+
} else if (val.id.length === 0) {
|
|
34
|
+
this.setAttribute('commandfor', '');
|
|
35
|
+
this[COMMAND_FOR] = val;
|
|
36
|
+
} else {
|
|
37
|
+
this.setAttribute('commandfor', val.id);
|
|
38
|
+
this[COMMAND_FOR] = null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
class CommandEvent extends Event {
|
|
44
|
+
#source = null;
|
|
45
|
+
#command = '';
|
|
46
|
+
|
|
47
|
+
constructor(type, { source, command, bubbles, cancelable, composed } = {}) {
|
|
48
|
+
super(type, { bubbles, cancelable, composed });
|
|
49
|
+
|
|
50
|
+
if (typeof command === 'string') {
|
|
51
|
+
this.#command = command;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (source instanceof HTMLButtonElement) {
|
|
55
|
+
this.#source = source;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
get command() {
|
|
60
|
+
return this.#command;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
get source() {
|
|
64
|
+
return this.#source;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function dispatchCommand({ currentTarget }) {
|
|
69
|
+
if (currentTarget instanceof HTMLButtonElement && currentTarget.hasAttribute('command') && currentTarget.hasAttribute('commandfor')) {
|
|
70
|
+
const target = currentTarget.commandForElement;
|
|
71
|
+
const command = currentTarget.command;
|
|
72
|
+
|
|
73
|
+
if (target instanceof Element && typeof command === 'string') {
|
|
74
|
+
const event = new CommandEvent('command', { command, source: currentTarget, cancelable: true });
|
|
75
|
+
target.dispatchEvent(event);
|
|
76
|
+
|
|
77
|
+
if (! event.defaultPrevented) {
|
|
78
|
+
switch(command) {
|
|
79
|
+
case 'show-modal':
|
|
80
|
+
if (target instanceof HTMLDialogElement) {
|
|
81
|
+
target.showModal();
|
|
82
|
+
}
|
|
83
|
+
break;
|
|
84
|
+
|
|
85
|
+
case 'close':
|
|
86
|
+
if (target instanceof HTMLDialogElement) {
|
|
87
|
+
target.close();
|
|
88
|
+
}
|
|
89
|
+
break;
|
|
90
|
+
|
|
91
|
+
case 'request-close':
|
|
92
|
+
if (target instanceof HTMLDialogElement) {
|
|
93
|
+
target.requestClose();
|
|
94
|
+
}
|
|
95
|
+
break;
|
|
96
|
+
|
|
97
|
+
case 'show-popover':
|
|
98
|
+
target.showPopover();
|
|
99
|
+
break;
|
|
100
|
+
|
|
101
|
+
case 'hide-popover':
|
|
102
|
+
target.hidePopover();
|
|
103
|
+
break;
|
|
104
|
+
|
|
105
|
+
case 'toggle-popover':
|
|
106
|
+
target.togglePopover();
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const observer = new MutationObserver(mutations => {
|
|
115
|
+
for (const mutation of mutations) {
|
|
116
|
+
if (mutation.type === 'childList') {
|
|
117
|
+
for (const node of mutation.addedNodes) {
|
|
118
|
+
if (node instanceof HTMLButtonElement && node.hasAttribute('command') && node.hasAttribute('commandfor')) {
|
|
119
|
+
node.addEventListener('click', dispatchCommand, CLICK_OPTIONS);
|
|
120
|
+
} else if (node instanceof Element) {
|
|
121
|
+
for (const btn of node.querySelectorAll('button[command][commandfor]')) {
|
|
122
|
+
btn.addEventListener('click', dispatchCommand, CLICK_OPTIONS);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
} else if (
|
|
127
|
+
mutation.type === 'attributes'
|
|
128
|
+
&& mutation.target instanceof HTMLButtonElement
|
|
129
|
+
&& typeof mutation.oldValue !== typeof mutation.target.getAttribute(mutation.attributeName)
|
|
130
|
+
) {
|
|
131
|
+
if (mutation.target.hasAttribute('command') && mutation.target.hasAttribute('commandfor')) {
|
|
132
|
+
mutation.target.addEventListener('click', dispatchCommand, CLICK_OPTIONS);
|
|
133
|
+
} else {
|
|
134
|
+
mutation.target.removeEventListener('click', dispatchCommand, CLICK_OPTIONS);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const config = { childList: true, subtree: true, attributes: true, attributeFilter: ['command', 'commandfor'], attributeOldValue: true };
|
|
141
|
+
observer.observe(document, config);
|
|
142
|
+
document.querySelectorAll('button').forEach(btn => btn.addEventListener('click', dispatchCommand, CLICK_OPTIONS));
|
|
143
|
+
globalThis.CommandEvent = CommandEvent;
|
|
144
|
+
// For use in Shadow DOM
|
|
145
|
+
globalThis[Symbol.for('polyfill-command')] = target => observer.observe(target, config);
|
|
146
|
+
}
|
package/element.js
CHANGED
|
@@ -2,6 +2,7 @@ import { aria } from './aom.js';
|
|
|
2
2
|
import { polyfillGetterSetter, polyfillMethod, overwriteMethod } from './utils.js';
|
|
3
3
|
import { getHTML, setHTMLUnsafe } from './methods/dom.js';
|
|
4
4
|
import './sanitizer.js';
|
|
5
|
+
import './command.js';
|
|
5
6
|
|
|
6
7
|
polyfillMethod(Element.prototype, 'setHTMLUnsafe', setHTMLUnsafe);
|
|
7
8
|
polyfillMethod(Element.prototype, 'getHTML', getHTML);
|