You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
154 lines
3.5 KiB
JavaScript
154 lines
3.5 KiB
JavaScript
'use strict';
|
|
const {DOCUMENT_FRAGMENT_NODE} = require('./shared/constants.js');
|
|
const {defineProperties, getOwnPropertyDescriptors} = require('./shared/object.js');
|
|
|
|
const {Attr} = require('./interface/attr.js');
|
|
const {CharacterData} = require('./interface/character-data.js');
|
|
const {Element} = require('./interface/element.js');
|
|
|
|
const {ParentNode} = require('./mixin/parent-node.js');
|
|
const {NonElementParentNode} = require('./mixin/non-element-parent-node.js');
|
|
const {HTMLDocument} = require('./html/document.js');
|
|
|
|
const {
|
|
childNodesWM,
|
|
childrenWM,
|
|
querySelectorWM,
|
|
querySelectorAllWM,
|
|
get,
|
|
reset
|
|
} = require('./shared/cache.js');
|
|
|
|
// Attr
|
|
const {value: {
|
|
get: getAttributeValue,
|
|
set: setAttributeValue
|
|
}} = getOwnPropertyDescriptors(Attr.prototype);
|
|
|
|
defineProperties(Attr.prototype, {
|
|
value: {
|
|
get: getAttributeValue,
|
|
set(value) {
|
|
reset(this.ownerElement);
|
|
setAttributeValue.call(this, value);
|
|
}
|
|
}
|
|
});
|
|
|
|
|
|
// CharacterData
|
|
// TODO: is txtContent really necessary to patch here?
|
|
const {remove: removeCharacterData} = CharacterData.prototype;
|
|
defineProperties(CharacterData.prototype, {
|
|
remove: {value() {
|
|
reset(this.parentNode);
|
|
removeCharacterData.call(this);
|
|
}}
|
|
});
|
|
|
|
|
|
// Element
|
|
const elementProtoDescriptors = {};
|
|
for (const name of [
|
|
'remove',
|
|
'setAttribute',
|
|
'setAttributeNS',
|
|
'setAttributeNode',
|
|
'setAttributeNodeNS',
|
|
'removeAttribute',
|
|
'removeAttributeNS',
|
|
'removeAttributeNode'
|
|
]) {
|
|
const method = Element.prototype[name];
|
|
elementProtoDescriptors[name] = {
|
|
value() {
|
|
reset(this.parentNode);
|
|
return method.apply(this, arguments);
|
|
}
|
|
};
|
|
}
|
|
defineProperties(Element.prototype, elementProtoDescriptors);
|
|
|
|
|
|
// ParentNode
|
|
const {
|
|
childNodes: {get: getChildNodes},
|
|
children: {get: getChildren}
|
|
} = getOwnPropertyDescriptors(ParentNode.prototype);
|
|
|
|
defineProperties(ParentNode.prototype, {
|
|
childNodes: {get() {
|
|
return get(childNodesWM, this, getChildNodes);
|
|
}},
|
|
children: {get() {
|
|
return get(childrenWM, this, getChildren);
|
|
}}
|
|
});
|
|
|
|
const {
|
|
insertBefore,
|
|
querySelector,
|
|
querySelectorAll
|
|
} = ParentNode.prototype;
|
|
|
|
const query = (wm, method, self, selectors) => {
|
|
if (!wm.has(self))
|
|
wm.set(self, new Map);
|
|
const map = wm.get(self);
|
|
if (map.has(selectors))
|
|
return map.get(selectors);
|
|
const result = method.call(self, selectors);
|
|
map.set(selectors, result);
|
|
return result;
|
|
};
|
|
|
|
defineProperties(ParentNode.prototype, {
|
|
insertBefore: {value(node, before) {
|
|
reset(this);
|
|
if (node.nodeType === DOCUMENT_FRAGMENT_NODE)
|
|
reset(node);
|
|
return insertBefore.call(this, node, before);
|
|
}},
|
|
getElementsByClassName: {value(className) {
|
|
return this.querySelectorAll('.' + className);
|
|
}},
|
|
getElementsByTagName: {value(tagName) {
|
|
return this.querySelectorAll(tagName);
|
|
}},
|
|
querySelector: {value(selectors) {
|
|
return query(querySelectorWM, querySelector, this, selectors);
|
|
}},
|
|
querySelectorAll: {value(selectors) {
|
|
return query(querySelectorAllWM, querySelectorAll, this, selectors);
|
|
}}
|
|
});
|
|
|
|
|
|
// NonElementParentNode
|
|
defineProperties(NonElementParentNode.prototype, {
|
|
getElementById: {value(id) {
|
|
return this.querySelector('#' + id);
|
|
}}
|
|
});
|
|
|
|
|
|
// HTMLDocument
|
|
const {title: {
|
|
get: getTitle,
|
|
set: setTitle
|
|
}} = getOwnPropertyDescriptors(HTMLDocument.prototype);
|
|
|
|
defineProperties(HTMLDocument.prototype, {
|
|
title: {
|
|
get: getTitle,
|
|
set(value) {
|
|
reset(this.head);
|
|
setTitle.call(this, value);
|
|
}
|
|
}
|
|
});
|
|
|
|
|
|
(m => Object.keys(m).map(k => k !== 'default' && (exports[k] = m[k])))
|
|
(require('./index.js'));
|