Skip to content

Commit 05f01f6

Browse files
committed
Add freeze-element-property scriptlet
@Scriptlet freeze-element-property @description Conditionally prevent assignment to an element property. @param property The property name to freeze. @param [selector] Optional. The element must matches `selector` for the prevention to take place. @param [pattern] Optional. A pattern to match against the stringified assigned value. The pattern can be a plain string, or a regex. Prepend with `!` to reverse the match condition. The scriptlet `prevent-innerHTML` is now an alias for `##+js(freeze-element-property, innerHTML, ...)`
1 parent 751104a commit 05f01f6

File tree

1 file changed

+32
-46
lines changed

1 file changed

+32
-46
lines changed

src/js/resources/prevent-innerHTML.js

Lines changed: 32 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -24,29 +24,44 @@ import { registerScriptlet } from './base.js';
2424
import { safeSelf } from './safe-self.js';
2525

2626
/**
27-
* @scriptlet prevent-innerHTML
27+
* @scriptlet freeze-element-property
2828
*
2929
* @description
30-
* Conditionally prevent assignment to `innerHTML` property.
30+
* Conditionally prevent assignment to an element property.
31+
*
32+
* @param property
33+
* The property name to freeze.
3134
*
3235
* @param [selector]
3336
* Optional. The element must matches `selector` for the prevention to take
3437
* place.
3538
*
3639
* @param [pattern]
37-
* Optional. A pattern to match against the assigned value. The pattern can be
38-
* a plain string, or a regex. Prepend with `!` to reverse the match condition.
40+
* Optional. A pattern to match against the stringified assigned value. The
41+
* pattern can be a plain string, or a regex. Prepend with `!` to reverse the
42+
* match condition.
3943
*
4044
* */
4145

42-
export function preventInnerHTML(
46+
function freezeElementProperty(
47+
property = '',
4348
selector = '',
4449
pattern = ''
4550
) {
4651
const safe = safeSelf();
47-
const logPrefix = safe.makeLogPrefix('prevent-innerHTML', selector, pattern);
52+
const logPrefix = safe.makeLogPrefix('freeze-element-property', property, selector, pattern);
4853
const matcher = safe.initPattern(pattern, { canNegate: true });
49-
const current = safe.Object_getOwnPropertyDescriptor(Element.prototype, 'innerHTML');
54+
const owner = (( ) => {
55+
if ( Object.hasOwn(Element.prototype, property) ) {
56+
return Element.prototype;
57+
}
58+
if ( Object.hasOwn(HTMLElement.prototype, property) ) {
59+
return HTMLElement.prototype;
60+
}
61+
return null;
62+
})();
63+
if ( owner === null ) { return; }
64+
const current = safe.Object_getOwnPropertyDescriptor(owner, property);
5065
if ( current === undefined ) { return; }
5166
const shouldPreventSet = (elem, a) => {
5267
if ( selector !== '' ) {
@@ -55,15 +70,15 @@ export function preventInnerHTML(
5570
}
5671
return safe.testPattern(matcher, `${a}`);
5772
};
58-
Object.defineProperty(Element.prototype, 'innerHTML', {
73+
Object.defineProperty(owner, property, {
5974
get: function() {
6075
return current.get
6176
? current.get.call(this)
6277
: current.value;
6378
},
6479
set: function(a) {
6580
if ( shouldPreventSet(this, a) ) {
66-
safe.uboLog(logPrefix, 'Prevented');
81+
safe.uboLog(logPrefix, 'Assignment prevented');
6782
} else if ( current.set ) {
6883
current.set.call(this, a);
6984
}
@@ -74,18 +89,18 @@ export function preventInnerHTML(
7489
},
7590
});
7691
}
77-
registerScriptlet(preventInnerHTML, {
78-
name: 'prevent-innerHTML.js',
92+
registerScriptlet(freezeElementProperty, {
93+
name: 'freeze-element-property.js',
7994
dependencies: [
8095
safeSelf,
8196
],
8297
});
8398

8499
/**
85-
* @scriptlet prevent-textContent
100+
* @scriptlet prevent-innerHTML
86101
*
87102
* @description
88-
* Conditionally prevent assignment to `textContent` property.
103+
* Conditionally prevent assignment to `innerHTML` property.
89104
*
90105
* @param [selector]
91106
* Optional. The element must matches `selector` for the prevention to take
@@ -97,44 +112,15 @@ registerScriptlet(preventInnerHTML, {
97112
*
98113
* */
99114

100-
export function preventTextContent(
115+
function preventInnerHTML(
101116
selector = '',
102117
pattern = ''
103118
) {
104-
const safe = safeSelf();
105-
const logPrefix = safe.makeLogPrefix('prevent-textContent', selector, pattern);
106-
const matcher = safe.initPattern(pattern, { canNegate: true });
107-
const current = safe.Object_getOwnPropertyDescriptor(Element.prototype, 'textContent');
108-
if ( current === undefined ) { return; }
109-
const shouldPreventSet = (elem, a) => {
110-
if ( selector !== '' ) {
111-
if ( typeof elem.matches !== 'function' ) { return false; }
112-
if ( elem.matches(selector) === false ) { return false; }
113-
}
114-
return safe.testPattern(matcher, `${a}`);
115-
};
116-
Object.defineProperty(Element.prototype, 'textContent', {
117-
get: function() {
118-
return current.get
119-
? current.get.call(this)
120-
: current.value;
121-
},
122-
set: function(a) {
123-
if ( shouldPreventSet(this, a) ) {
124-
safe.uboLog(logPrefix, 'Prevented');
125-
} else if ( current.set ) {
126-
current.set.call(this, a);
127-
}
128-
if ( safe.logLevel > 1 ) {
129-
safe.uboLog(logPrefix, `Assigned:\n${a}`);
130-
}
131-
current.value = a;
132-
},
133-
});
119+
freezeElementProperty('innerHTML', selector, pattern);
134120
}
135121
registerScriptlet(preventInnerHTML, {
136-
name: 'prevent-textContent.js',
122+
name: 'prevent-innerHTML.js',
137123
dependencies: [
138-
safeSelf,
124+
freezeElementProperty,
139125
],
140126
});

0 commit comments

Comments
 (0)