@shgysk8zer0/polyfills 0.0.8 → 0.1.0
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 +16 -0
- package/CSSStyleSheet.js +83 -0
- package/Document.js +6 -0
- package/ShadowRoot.js +6 -0
- package/all.js +4 -1
- package/all.min.js +13 -13
- package/all.min.js.map +1 -1
- package/assets/Sanitizer.js +5 -3
- package/assets/adoptedStylesheets.js +53 -0
- package/assets/namespaces.js +6 -0
- package/assets/sanitizerUtils.js +143 -127
- package/deprecated/sanitizer.js +3 -0
- package/element.js +17 -15
- package/package.json +3 -5
- package/rollup.config.js +6 -10
- package/utils.js +22 -0
- package/sanitizer.js +0 -3
package/assets/Sanitizer.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @copyright 2022-2023 Chris Zuber <admin@kernvalley.us>
|
|
3
3
|
*/
|
|
4
|
-
import { nativeSupport, getSantizerUtils, sanitize,
|
|
4
|
+
import { nativeSupport, getSantizerUtils, sanitize, trustPolicies } from './sanitizerUtils.js';
|
|
5
5
|
import { SanitizerConfig as defaultConfig } from './SanitizerConfigW3C.js';
|
|
6
6
|
|
|
7
7
|
const protectedData = new WeakMap();
|
|
@@ -43,11 +43,13 @@ export class Sanitizer {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
sanitize(input) {
|
|
46
|
-
return sanitize(input,
|
|
46
|
+
return sanitize(input, this.getConfiguration());
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
sanitizeFor(tag, content) {
|
|
50
|
-
|
|
50
|
+
const el = document.createElement(tag);
|
|
51
|
+
el.setHTML(content, this.getConfiguration());
|
|
52
|
+
return el;
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
static getDefaultConfiguration() {
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This **REQUIRES** a CSP with `style-src blob:`
|
|
3
|
+
*/
|
|
4
|
+
export const adoptedStyleSheets = {
|
|
5
|
+
get() {
|
|
6
|
+
return Array.from(this.styleSheets)
|
|
7
|
+
.filter(sheet => sheet.ownerNode.classList.contains('_adopted'));
|
|
8
|
+
},
|
|
9
|
+
set(sheets) {
|
|
10
|
+
if (! Array.isArray(sheets)) {
|
|
11
|
+
throw new TypeError('Must be an array');
|
|
12
|
+
} else {
|
|
13
|
+
const current = new Set(this.adoptedStyleSheets);
|
|
14
|
+
|
|
15
|
+
current.difference(sheets).forEach(sheet => sheet.ownerNode.remove());
|
|
16
|
+
|
|
17
|
+
const links = [...new Set(sheets).difference(current)].map(sheet => {
|
|
18
|
+
const link = document.createElement('link');
|
|
19
|
+
const controller = new AbortController();
|
|
20
|
+
const signal = controller.signal;
|
|
21
|
+
const url = URL.createObjectURL(new File([], 'adopted.css', { type: 'text/css' }));
|
|
22
|
+
link.rel = 'stylesheet';
|
|
23
|
+
link.href = url;
|
|
24
|
+
link.classList.add('_adopted');
|
|
25
|
+
link.disabled = sheet.disabled;
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
link.addEventListener('load', ({ target }) => {
|
|
29
|
+
controller.abort();
|
|
30
|
+
link.media = sheet.media.mediaText;
|
|
31
|
+
[...sheet.cssRules].forEach((rule, index) => {
|
|
32
|
+
target.sheet.insertRule(rule.cssText, index);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
setTimeout(() => URL.revokeObjectURL(target.href), 100);
|
|
36
|
+
}, { once: true, signal });
|
|
37
|
+
|
|
38
|
+
link.addEventListener('error', ({ target }) => {
|
|
39
|
+
controller.abort();
|
|
40
|
+
URL.revokeObjectURL(target.href);
|
|
41
|
+
}, { once: true, signal });
|
|
42
|
+
|
|
43
|
+
return link;
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
if (this instanceof Document) {
|
|
47
|
+
this.head.append(...links);
|
|
48
|
+
} else {
|
|
49
|
+
this.append(...links);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export const HTML = 'http://www.w3.org/1999/xhtml';
|
|
2
|
+
export const SVG = 'http://www.w3.org/2000/svg';
|
|
3
|
+
export const MathML = 'http://www.w3.org/1998/Math/MathML';
|
|
4
|
+
export const XML = 'http://www.w3.org/XML/1998/namespace';
|
|
5
|
+
export const XMLNS = 'http://www.w3.org/2000/xmlns/';
|
|
6
|
+
export const XSLT = 'http://www.w3.org/1999/XSL/Transform';
|
package/assets/sanitizerUtils.js
CHANGED
|
@@ -9,6 +9,11 @@ import { urls } from './attributes.js';
|
|
|
9
9
|
export const supported = () => 'Sanitizer' in globalThis;
|
|
10
10
|
export const nativeSupport = supported();
|
|
11
11
|
|
|
12
|
+
export const setHTML = function setHTML(el, input, opts = defaultConfig) {
|
|
13
|
+
const doc = safeParseHTML(input, opts);
|
|
14
|
+
el.append(documentToFragment(doc));
|
|
15
|
+
};
|
|
16
|
+
|
|
12
17
|
const allowProtocols = ['https:'];
|
|
13
18
|
|
|
14
19
|
if (! allowProtocols.includes(location.protocol)) {
|
|
@@ -18,166 +23,190 @@ const policyName = 'sanitizer-raw#html';
|
|
|
18
23
|
const getPolicy = callOnce(() => createPolicy(policyName, { createHTML: input => input }));
|
|
19
24
|
const createHTML = input => getPolicy().createHTML(input);
|
|
20
25
|
|
|
21
|
-
function documentToFragment(doc) {
|
|
26
|
+
export function documentToFragment(doc) {
|
|
22
27
|
const frag = document.createDocumentFragment();
|
|
23
28
|
const clone = doc.cloneNode(true);
|
|
24
29
|
frag.append(...clone.head.childNodes, ...clone.body.childNodes);
|
|
25
30
|
return frag;
|
|
26
31
|
}
|
|
27
32
|
|
|
28
|
-
|
|
33
|
+
/**
|
|
34
|
+
* Helper function to adapt to changes in spec
|
|
35
|
+
*/
|
|
36
|
+
export function convertSanitizerConfig({
|
|
37
|
+
allowAttributes, allowComments, allowElements, allowCustomElements,
|
|
38
|
+
blockElements, dropAttributes, dropElements, allowUnknownMarkup, sanitizer,
|
|
39
|
+
} = {}, context) {
|
|
40
|
+
if (sanitizer instanceof Sanitizer) {
|
|
41
|
+
return convertSanitizerConfig(sanitizer.getConfiguration(), context);
|
|
42
|
+
} else {
|
|
43
|
+
switch (context) {
|
|
44
|
+
default:
|
|
45
|
+
if (typeof allowAttributes === 'undefined' && typeof dropAttributes === 'undefined') {
|
|
46
|
+
allowAttributes = defaultConfig.allowAttributes;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (typeof allowElements === 'undefined' && typeof dropElements === 'undefined') {
|
|
50
|
+
allowElements = defaultConfig.allowElements;
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
allowAttributes, allowComments, allowElements, allowCustomElements,
|
|
54
|
+
blockElements, dropAttributes, dropElements, allowUnknownMarkup,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function convertToSanitizerConfig({
|
|
61
|
+
allowAttributes, allowComments, allowElements, allowCustomElements,
|
|
62
|
+
blockElements, dropAttributes, dropElements, allowUnknownMarkup,
|
|
63
|
+
} = {}) {
|
|
64
|
+
if (typeof allowAttributes === 'undefined' && typeof dropAttributes === 'undefined') {
|
|
65
|
+
allowAttributes = defaultConfig.allowAttributes;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (typeof allowElements === 'undefined' && typeof dropElements === 'undefined') {
|
|
69
|
+
allowElements = defaultConfig.allowElements;
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
allowAttributes, allowComments, allowElements, allowCustomElements,
|
|
73
|
+
blockElements, dropAttributes, dropElements, allowUnknownMarkup,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function safeParseHTML(input, opts = defaultConfig) {
|
|
78
|
+
const doc = new DOMParser().parseFromString(createHTML(input), 'text/html');
|
|
79
|
+
// Not sure if this will be in spec, but it is necessary
|
|
80
|
+
if (Array.isArray(opts.allowElements) && ! opts.allowElements.includes('html') ) {
|
|
81
|
+
opts.allowElements = [...new Set([...opts.allowElements, 'html' ,'head', 'body'])];
|
|
82
|
+
}
|
|
83
|
+
return sanitizeNode(doc, opts);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function sanitize(input, opts = defaultConfig) {
|
|
29
87
|
if (! (input instanceof Node)) {
|
|
30
88
|
throw new TypeError('sanitize requires a Document or DocumentFragment');
|
|
31
89
|
} else if (input.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
|
|
32
|
-
return sanitizeNode(input,
|
|
90
|
+
return sanitizeNode(input, opts);
|
|
33
91
|
} else if (input.nodeType === Node.DOCUMENT_NODE) {
|
|
34
|
-
return sanitizeNode(documentToFragment(input),
|
|
92
|
+
return sanitizeNode(documentToFragment(input), opts);
|
|
35
93
|
} else {
|
|
36
94
|
throw new TypeError('sanitize requires a Document or DocumentFragment');
|
|
37
95
|
}
|
|
38
96
|
}
|
|
39
97
|
|
|
40
|
-
export function sanitizeFor(tag, content,
|
|
98
|
+
export function sanitizeFor(tag, content, opts = defaultConfig) {
|
|
41
99
|
const el = document.createElement(tag);
|
|
42
100
|
const temp = document.createElement('template');
|
|
43
101
|
temp.innerHTML = createHTML(content);
|
|
44
|
-
el.append(sanitize(temp.content,
|
|
102
|
+
el.append(sanitize(temp.content, opts));
|
|
45
103
|
return el;
|
|
46
104
|
}
|
|
47
105
|
|
|
48
|
-
export function sanitizeNode(
|
|
106
|
+
export function sanitizeNode(root, opts = defaultConfig) {
|
|
49
107
|
try {
|
|
50
|
-
if (! (
|
|
51
|
-
throw new TypeError(`Expected a Node but got a ${getType(
|
|
52
|
-
} else if (! isObject(
|
|
53
|
-
throw new TypeError(`Expected config to be an object but got ${getType(
|
|
108
|
+
if (! (root instanceof Node)) {
|
|
109
|
+
throw new TypeError(`Expected a Node but got a ${getType(root)}.`);
|
|
110
|
+
} else if (! isObject(opts)) {
|
|
111
|
+
throw new TypeError(`Expected config to be an object but got ${getType(opts)}.`);
|
|
54
112
|
}
|
|
55
113
|
|
|
56
114
|
const {
|
|
57
115
|
allowElements, allowComments, allowAttributes, allowCustomElements,
|
|
58
116
|
blockElements, dropAttributes, dropElements, allowUnknownMarkup,
|
|
59
|
-
} =
|
|
60
|
-
|
|
61
|
-
switch(node.nodeType) {
|
|
62
|
-
case Node.TEXT_NODE:
|
|
63
|
-
break;
|
|
64
|
-
|
|
65
|
-
case Node.ELEMENT_NODE: {
|
|
66
|
-
if (
|
|
67
|
-
! allowUnknownMarkup
|
|
68
|
-
&& ( ! (node instanceof HTMLElement) || node instanceof HTMLUnknownElement)
|
|
69
|
-
) {
|
|
70
|
-
node.remove();
|
|
71
|
-
break;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const tag = node.tagName.toLowerCase();
|
|
117
|
+
} = convertSanitizerConfig(opts);
|
|
75
118
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
[...node.childNodes].forEach(node => sanitizeNode(node, config));
|
|
81
|
-
node.replaceWith(...node.childNodes);
|
|
82
|
-
} else {
|
|
83
|
-
node.remove();
|
|
84
|
-
}
|
|
85
|
-
} else if (tag.includes('-') && ! allowCustomElements) {
|
|
86
|
-
node.remove();
|
|
87
|
-
} else if (Array.isArray(allowElements) && ! allowElements.includes(tag)) {
|
|
88
|
-
node.remove();
|
|
89
|
-
} else if (tag === 'template') {
|
|
90
|
-
sanitizeNode(node.content, config);
|
|
91
|
-
} else {
|
|
92
|
-
if (node.hasAttributes()) {
|
|
93
|
-
node.getAttributeNames()
|
|
94
|
-
.forEach(attr => sanitizeNode(node.getAttributeNode(attr), config));
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (node.hasChildNodes()) {
|
|
98
|
-
[...node.childNodes].forEach(node => sanitizeNode(node, config));
|
|
99
|
-
}
|
|
100
|
-
}
|
|
119
|
+
const iter = document.createNodeIterator(
|
|
120
|
+
root,
|
|
121
|
+
NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT,
|
|
122
|
+
);
|
|
101
123
|
|
|
102
|
-
|
|
103
|
-
|
|
124
|
+
let node = iter.root.nodeType === Node.ELEMENT_NODE
|
|
125
|
+
? iter.root
|
|
126
|
+
: iter.nextNode();
|
|
104
127
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const tag = ownerElement.tagName.toLowerCase();
|
|
109
|
-
|
|
110
|
-
if (
|
|
111
|
-
urls.includes(name)
|
|
112
|
-
&& ! allowProtocols.includes(new URL(value, document.baseURI).protocol)
|
|
113
|
-
) {
|
|
114
|
-
ownerElement.removeAttributeNode(node);
|
|
115
|
-
} else if (isObject(dropAttributes)) {
|
|
128
|
+
while (node instanceof Node) {
|
|
129
|
+
switch(node.nodeType) {
|
|
130
|
+
case Node.ELEMENT_NODE: {
|
|
116
131
|
if (
|
|
117
|
-
|
|
118
|
-
&&
|
|
132
|
+
! allowUnknownMarkup
|
|
133
|
+
&& ( ! (node instanceof HTMLElement) || node instanceof HTMLUnknownElement)
|
|
119
134
|
) {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
if (name.startsWith('on')) {
|
|
123
|
-
delete ownerElement[name];
|
|
124
|
-
}
|
|
135
|
+
node.remove();
|
|
136
|
+
break;
|
|
125
137
|
}
|
|
126
|
-
} else if (isObject(allowAttributes)) {
|
|
127
|
-
if (
|
|
128
|
-
! name.startsWith('data-')
|
|
129
|
-
&& ! (name in allowAttributes
|
|
130
|
-
&& ['*', tag].some(sel => allowAttributes[name].includes(sel)))
|
|
131
|
-
) {
|
|
132
|
-
ownerElement.removeAttributeNode(node);
|
|
133
138
|
|
|
134
|
-
|
|
135
|
-
|
|
139
|
+
const tag = node.tagName.toLowerCase();
|
|
140
|
+
|
|
141
|
+
if (Array.isArray(dropElements) && dropElements.includes(tag)) {
|
|
142
|
+
node.remove();
|
|
143
|
+
} else if (Array.isArray(blockElements) && blockElements.includes(tag)) {
|
|
144
|
+
if (node.hasChildNodes()) {
|
|
145
|
+
node.replaceWith(...node.childNodes);
|
|
146
|
+
} else {
|
|
147
|
+
node.remove();
|
|
148
|
+
}
|
|
149
|
+
} else if (tag.includes('-') && ! allowCustomElements) {
|
|
150
|
+
node.remove();
|
|
151
|
+
} else if (Array.isArray(allowElements) && ! allowElements.includes(tag)) {
|
|
152
|
+
node.remove();
|
|
153
|
+
} else {
|
|
154
|
+
if (node.hasAttributes()) {
|
|
155
|
+
node.getAttributeNames().forEach(name => {
|
|
156
|
+
const attr = node.getAttributeNode(name);
|
|
157
|
+
const { value } = attr;
|
|
158
|
+
|
|
159
|
+
if (
|
|
160
|
+
urls.includes(name)
|
|
161
|
+
&& ! allowProtocols.includes(new URL(value, document.baseURI).protocol)
|
|
162
|
+
) {
|
|
163
|
+
node.removeAttributeNode(attr);
|
|
164
|
+
} else if (isObject(dropAttributes)) {
|
|
165
|
+
if (
|
|
166
|
+
name in dropAttributes
|
|
167
|
+
&& ['*', tag].some(sel => dropAttributes[name].includes(sel))
|
|
168
|
+
) {
|
|
169
|
+
node.removeAttributeNode(attr);
|
|
170
|
+
}
|
|
171
|
+
} else if (isObject(allowAttributes)) {
|
|
172
|
+
if (
|
|
173
|
+
! (name in allowAttributes
|
|
174
|
+
&& ['*', tag].some(sel => allowAttributes[name].includes(sel)))
|
|
175
|
+
) {
|
|
176
|
+
node.removeAttributeNode(attr);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
});
|
|
136
180
|
}
|
|
137
181
|
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
break;
|
|
141
|
-
}
|
|
142
182
|
|
|
143
|
-
|
|
144
|
-
if (! allowComments) {
|
|
145
|
-
node.remove();
|
|
183
|
+
break;
|
|
146
184
|
}
|
|
147
185
|
|
|
148
|
-
|
|
149
|
-
|
|
186
|
+
case Node.COMMENT_NODE: {
|
|
187
|
+
if (! allowComments) {
|
|
188
|
+
node.remove();
|
|
189
|
+
}
|
|
150
190
|
|
|
151
|
-
|
|
152
|
-
case Node.DOCUMENT_FRAGMENT_NODE: {
|
|
153
|
-
if (node.hasChildNodes()) {
|
|
154
|
-
[...node.childNodes].forEach(node => sanitizeNode(node, config));
|
|
191
|
+
break;
|
|
155
192
|
}
|
|
156
|
-
|
|
157
|
-
break;
|
|
158
193
|
}
|
|
159
194
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
case Node.DOCUMENT_TYPE_NODE:
|
|
163
|
-
default: {
|
|
164
|
-
node.parentElement.removeChild(node);
|
|
195
|
+
if (node.localName === 'template') {
|
|
196
|
+
sanitizeNode(node.content, opts);
|
|
165
197
|
}
|
|
198
|
+
|
|
199
|
+
node = iter.nextNode();
|
|
166
200
|
}
|
|
201
|
+
|
|
202
|
+
return root;
|
|
167
203
|
} catch(err) {
|
|
168
|
-
node.parentElement.removeChild(node);
|
|
169
204
|
console.error(err);
|
|
205
|
+
root.parentElement.removeChild(root);
|
|
170
206
|
}
|
|
171
|
-
|
|
172
|
-
return node;
|
|
173
207
|
}
|
|
174
208
|
|
|
175
209
|
export function getSantizerUtils(Sanitizer, defaultConfig) {
|
|
176
|
-
const setHTML = function setHTML(el, input, { sanitizer = new Sanitizer() } = {}) {
|
|
177
|
-
const div = sanitizer.sanitizeFor('div', input);
|
|
178
|
-
el.replaceChildren(...div.children);
|
|
179
|
-
};
|
|
180
|
-
|
|
181
210
|
const polyfill = function polyfill() {
|
|
182
211
|
let polyfilled = false;
|
|
183
212
|
|
|
@@ -225,37 +254,24 @@ export function getSantizerUtils(Sanitizer, defaultConfig) {
|
|
|
225
254
|
} else if (! [Node.DOCUMENT_NODE, Node.DOCUMENT_FRAGMENT_NODE].includes(input.nodeType)) {
|
|
226
255
|
throw new TypeError('Expected a Document or DocumentFragment in `Sanitizer.sanitize()`.');
|
|
227
256
|
} else {
|
|
228
|
-
return sanitize(input,
|
|
257
|
+
return sanitize(input, this.getConfiguration());
|
|
229
258
|
}
|
|
230
259
|
};
|
|
231
260
|
polyfilled = true;
|
|
232
261
|
}
|
|
233
262
|
|
|
234
|
-
if (
|
|
235
|
-
! (globalThis.Sanitizer.prototype.sanitizeFor instanceof Function)
|
|
236
|
-
&& Element.prototype.setHTML instanceof Function
|
|
237
|
-
) {
|
|
238
|
-
globalThis.Sanitizer.prototype.sanitizeFor = function(element, input) {
|
|
239
|
-
const el = document.createElement(element);
|
|
240
|
-
el.setHTML(input, { sanitizer: this });
|
|
241
|
-
return el;
|
|
242
|
-
};
|
|
243
|
-
polyfilled = true;
|
|
244
|
-
} else if (! (globalThis.Sanitizer.prototype.sanitizeFor instanceof Function)) {
|
|
263
|
+
if (! (globalThis.Sanitizer.prototype.sanitizeFor instanceof Function)) {
|
|
245
264
|
globalThis.Sanitizer.prototype.sanitizeFor = function(element, input) {
|
|
246
265
|
const el = document.createElement(element);
|
|
247
|
-
|
|
248
|
-
tmp.innerHTML = createHTML(input);
|
|
249
|
-
el.append(this.sanitize(tmp.content));
|
|
266
|
+
setHTML(el, input,this.getConfiguration());
|
|
250
267
|
return el;
|
|
251
268
|
};
|
|
252
269
|
polyfilled = true;
|
|
253
270
|
}
|
|
254
271
|
|
|
255
272
|
if (! (Element.prototype.setHTML instanceof Function)) {
|
|
256
|
-
Element.prototype.setHTML = function(input,
|
|
257
|
-
|
|
258
|
-
this.replaceChildren(...el.children);
|
|
273
|
+
Element.prototype.setHTML = function(input, opts = defaultConfig) {
|
|
274
|
+
setHTML(this, input, opts);
|
|
259
275
|
};
|
|
260
276
|
polyfilled = true;
|
|
261
277
|
}
|
package/element.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { aria } from './aom.js';
|
|
2
|
+
import { overwriteMethod } from './utils.js';
|
|
3
|
+
import { SanitizerConfig as defaultConfig } from './assets/SanitizerConfigW3C.js';
|
|
4
|
+
import { setHTML as safeSetHTML, convertToSanitizerConfig } from './assets/sanitizerUtils.js';
|
|
2
5
|
|
|
3
6
|
if (! (HTMLScriptElement.supports instanceof Function)) {
|
|
4
7
|
HTMLScriptElement.supports = function supports(type) {
|
|
@@ -123,22 +126,21 @@ if (! (HTMLImageElement.prototype.decode instanceof Function)) {
|
|
|
123
126
|
};
|
|
124
127
|
}
|
|
125
128
|
|
|
126
|
-
if (
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
&& globalThis.Sanitizer.prototype.sanitizeFor instanceof Function
|
|
130
|
-
) {
|
|
131
|
-
Element.prototype.setHTML = function setHTML(input, { sanitizer = new globalThis.Sanitizer() } = {}) {
|
|
132
|
-
if (
|
|
133
|
-
('Sanitizer' in globalThis && sanitizer instanceof globalThis.Sanitizer)
|
|
134
|
-
|| (typeof sanitizer !== 'undefined' && sanitizer.sanitizeFor instanceof Function)
|
|
135
|
-
) {
|
|
136
|
-
const el = sanitizer.sanitizeFor(this.tagName.toLowerCase(), input);
|
|
137
|
-
this.replaceChildren(...el.children);
|
|
138
|
-
} else {
|
|
139
|
-
throw new TypeError('`sanitizer` is not a valid Sanitizer');
|
|
140
|
-
}
|
|
129
|
+
if (! (Element.prototype.setHTML instanceof Function)) {
|
|
130
|
+
Element.prototype.setHTML = function setHTML(input, opts = defaultConfig) {
|
|
131
|
+
safeSetHTML(this, input, opts);
|
|
141
132
|
};
|
|
133
|
+
} else {
|
|
134
|
+
overwriteMethod(Element.prototype, 'setHTML', function(orig) {
|
|
135
|
+
return function setHTML(input, opts = {}) {
|
|
136
|
+
if (! (opts.sanitizer instanceof Sanitizer)) {
|
|
137
|
+
const sanitizer = new Sanitizer(convertToSanitizerConfig(opts));
|
|
138
|
+
orig.call(this, input, { sanitizer });
|
|
139
|
+
} else {
|
|
140
|
+
orig.call(this, input, opts);
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
});
|
|
142
144
|
}
|
|
143
145
|
|
|
144
146
|
if (! HTMLTemplateElement.prototype.hasOwnProperty('shadowRootMode')) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shgysk8zer0/polyfills",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "A collection of JavaScript polyfills",
|
|
@@ -50,10 +50,8 @@
|
|
|
50
50
|
},
|
|
51
51
|
"homepage": "https://github.com/shgysk8zer0/polyfills#readme",
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@
|
|
54
|
-
"eslint": "^8.40.0",
|
|
53
|
+
"@shgysk8zer0/js-utils": "^1.0.0",
|
|
55
54
|
"htmlhint": "^1.1.4",
|
|
56
|
-
"http-server": "^14.1.1"
|
|
57
|
-
"rollup": "^3.23.0"
|
|
55
|
+
"http-server": "^14.1.1"
|
|
58
56
|
}
|
|
59
57
|
}
|
package/rollup.config.js
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
/* eslint-env node */
|
|
2
|
-
import
|
|
2
|
+
import { getConfig } from '@shgysk8zer0/js-utils/rollup';
|
|
3
3
|
|
|
4
|
-
export default {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
sourcemap: true,
|
|
10
|
-
},
|
|
11
|
-
plugins: [terser()],
|
|
12
|
-
};
|
|
4
|
+
export default getConfig('./all.js', {
|
|
5
|
+
sourcemap: true,
|
|
6
|
+
minify: true,
|
|
7
|
+
format: 'iife',
|
|
8
|
+
});
|
package/utils.js
CHANGED
|
@@ -7,3 +7,25 @@ export function polyfillMethod(parent, name, value, {
|
|
|
7
7
|
Object.defineProperty(parent, name, { value, writable, enumerable, configurable });
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
|
+
|
|
11
|
+
export function polyfillGetterSetter(parent, name, {
|
|
12
|
+
get,
|
|
13
|
+
set,
|
|
14
|
+
enumerable = true,
|
|
15
|
+
configurable = true,
|
|
16
|
+
} = {}) {
|
|
17
|
+
if (! parent.hasOwnProperty(name)) {
|
|
18
|
+
Object.defineProperty(parent, name, { get, set, enumerable, configurable });
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function overwriteMethod(parent, name, func) {
|
|
23
|
+
const { value, enumerable, configurable, writable } = Object.getOwnPropertyDescriptor(parent, name);
|
|
24
|
+
const newMethod = func(value);
|
|
25
|
+
|
|
26
|
+
if (! (newMethod instanceof Function)) {
|
|
27
|
+
throw new TypeError(`Error overwriting ${name}. The func MUST be a function that accepts the original as an argument and return a function.`);
|
|
28
|
+
} else {
|
|
29
|
+
Object.defineProperty(parent, name, { value: newMethod, enumerable, configurable, writable });
|
|
30
|
+
}
|
|
31
|
+
}
|
package/sanitizer.js
DELETED