Skip to content

Commit

Permalink
capricorn86#1188@minor: Makes properties getters and setters in Node …
Browse files Browse the repository at this point in the history
…classes according to spec.
  • Loading branch information
capricorn86 committed Jan 14, 2024
1 parent b9d5b65 commit e470b8e
Show file tree
Hide file tree
Showing 88 changed files with 2,186 additions and 954 deletions.
68 changes: 67 additions & 1 deletion packages/happy-dom/src/PropertySymbol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ export const setupVMContext = Symbol('setupVMContext');
export const shadowRoot = Symbol('shadowRoot');
export const start = Symbol('start');
export const style = Symbol('style');
export const styleSheet = Symbol('styleSheet');
export const target = Symbol('target');
export const textAreaNode = Symbol('textAreaNode');
export const unobserve = Symbol('unobserve');
Expand All @@ -82,3 +81,70 @@ export const mutationObservers = Symbol('mutationObservers');
export const openerFrame = Symbol('openerFrame');
export const openerWindow = Symbol('openerFrame');
export const popup = Symbol('popup');
export const isConnected = Symbol('isConnected');
export const parentNode = Symbol('parentNode');
export const nodeType = Symbol('nodeType');
export const tagName = Symbol('tagName');
export const prefix = Symbol('prefix');
export const scrollHeight = Symbol('scrollHeight');
export const scrollWidth = Symbol('scrollWidth');
export const scrollTop = Symbol('scrollTop');
export const scrollLeft = Symbol('scrollLeft');
export const attributes = Symbol('attributes');
export const namespaceURI = Symbol('namespaceURI');
export const accessKey = Symbol('accessKey');
export const accessKeyLabel = Symbol('accessKeyLabel');
export const contentEditable = Symbol('contentEditable');
export const isContentEditable = Symbol('isContentEditable');
export const offsetHeight = Symbol('offsetHeight');
export const offsetWidth = Symbol('offsetWidth');
export const offsetLeft = Symbol('offsetLeft');
export const offsetTop = Symbol('offsetTop');
export const clientHeight = Symbol('clientHeight');
export const clientWidth = Symbol('clientWidth');
export const clientLeft = Symbol('clientLeft');
export const clientTop = Symbol('clientTop');
export const name = Symbol('name');
export const specified = Symbol('specified');
export const adoptedStyleSheets = Symbol('adoptedStyleSheets');
export const implementation = Symbol('implementation');
export const readyState = Symbol('readyState');
export const ownerWindow = Symbol('ownerWindow');
export const publicId = Symbol('publicId');
export const systemId = Symbol('systemId');
export const validationMessage = Symbol('validationMessage');
export const validity = Symbol('validity');
export const returnValue = Symbol('returnValue');
export const elements = Symbol('elements');
export const length = Symbol('length');
export const complete = Symbol('complete');
export const naturalHeight = Symbol('naturalHeight');
export const naturalWidth = Symbol('naturalWidth');
export const loading = Symbol('loading');
export const x = Symbol('x');
export const y = Symbol('y');
export const defaultChecked = Symbol('defaultChecked');
export const files = Symbol('files');
export const sheet = Symbol('sheet');
export const volume = Symbol('volume');
export const paused = Symbol('paused');
export const currentTime = Symbol('currentTime');
export const playbackRate = Symbol('playbackRate');
export const defaultPlaybackRate = Symbol('defaultPlaybackRate');
export const muted = Symbol('muted');
export const defaultMuted = Symbol('defaultMuted');
export const preservesPitch = Symbol('preservesPitch');
export const buffered = Symbol('buffered');
export const duration = Symbol('duration');
export const error = Symbol('error');
export const ended = Symbol('ended');
export const networkState = Symbol('networkState');
export const textTracks = Symbol('textTracks');
export const videoTracks = Symbol('videoTracks');
export const seeking = Symbol('seeking');
export const seekable = Symbol('seekable');
export const played = Symbol('played');
export const options = Symbol('options');
export const content = Symbol('content');
export const mode = Symbol('mode');
export const host = Symbol('host');
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export default class BrowserFrameNavigator {
(<number>frame.window.devicePixelRatio) = devicePixelRatio;

if (options?.referrer) {
(<string>frame.window.document.referrer) = options.referrer;
frame.window.document[PropertySymbol.referrer] = options.referrer;
}

if (targetURL.protocol === 'about:') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,21 +79,21 @@ export default abstract class AbstractCSSStyleDeclaration {

if (this.#ownerElement) {
const style = new CSSStyleDeclarationPropertyManager({ cssText });
let styleAttribute = <IAttr>this.#ownerElement.attributes['style'];
let styleAttribute = <IAttr>this.#ownerElement[PropertySymbol.attributes]['style'];

if (!styleAttribute) {
styleAttribute = this.#ownerElement.ownerDocument.createAttribute('style');
styleAttribute = this.#ownerElement[PropertySymbol.ownerDocument].createAttribute('style');
// We use "[PropertySymbol.setNamedItemWithoutConsequences]" here to avoid triggering setting "Element.style.cssText" when setting the "style" attribute.
(<NamedNodeMap>this.#ownerElement.attributes)[
(<NamedNodeMap>this.#ownerElement[PropertySymbol.attributes])[
PropertySymbol.setNamedItemWithoutConsequences
](styleAttribute);
}

if (this.#ownerElement.isConnected) {
this.#ownerElement.ownerDocument[PropertySymbol.cacheID]++;
if (this.#ownerElement[PropertySymbol.isConnected]) {
this.#ownerElement[PropertySymbol.ownerDocument][PropertySymbol.cacheID]++;
}

styleAttribute.value = style.toString();
styleAttribute[PropertySymbol.value] = style.toString();
} else {
this.#style = new CSSStyleDeclarationPropertyManager({ cssText });
}
Expand Down Expand Up @@ -136,25 +136,25 @@ export default abstract class AbstractCSSStyleDeclaration {
if (!stringValue) {
this.removeProperty(name);
} else if (this.#ownerElement) {
let styleAttribute = <IAttr>this.#ownerElement.attributes['style'];
let styleAttribute = <IAttr>this.#ownerElement[PropertySymbol.attributes]['style'];

if (!styleAttribute) {
styleAttribute = this.#ownerElement.ownerDocument.createAttribute('style');
styleAttribute = this.#ownerElement[PropertySymbol.ownerDocument].createAttribute('style');

// We use "[PropertySymbol.setNamedItemWithoutConsequences]" here to avoid triggering setting "Element.style.cssText" when setting the "style" attribute.
(<NamedNodeMap>this.#ownerElement.attributes)[
(<NamedNodeMap>this.#ownerElement[PropertySymbol.attributes])[
PropertySymbol.setNamedItemWithoutConsequences
](styleAttribute);
}

if (this.#ownerElement.isConnected) {
this.#ownerElement.ownerDocument[PropertySymbol.cacheID]++;
if (this.#ownerElement[PropertySymbol.isConnected]) {
this.#ownerElement[PropertySymbol.ownerDocument][PropertySymbol.cacheID]++;
}

const style = this.#elementStyle.getElementStyle();
style.set(name, stringValue, !!priority);

styleAttribute.value = style.toString();
styleAttribute[PropertySymbol.value] = style.toString();
} else {
this.#style.set(name, stringValue, !!priority);
}
Expand All @@ -180,15 +180,16 @@ export default abstract class AbstractCSSStyleDeclaration {
style.remove(name);
const newCSSText = style.toString();

if (this.#ownerElement.isConnected) {
this.#ownerElement.ownerDocument[PropertySymbol.cacheID]++;
if (this.#ownerElement[PropertySymbol.isConnected]) {
this.#ownerElement[PropertySymbol.ownerDocument][PropertySymbol.cacheID]++;
}

if (newCSSText) {
(<IAttr>this.#ownerElement.attributes['style']).value = newCSSText;
(<IAttr>this.#ownerElement[PropertySymbol.attributes]['style'])[PropertySymbol.value] =
newCSSText;
} else {
// We use "[PropertySymbol.removeNamedItemWithoutConsequences]" here to avoid triggering setting "Element.style.cssText" when setting the "style" attribute.
(<NamedNodeMap>this.#ownerElement.attributes)[
(<NamedNodeMap>this.#ownerElement[PropertySymbol.attributes])[
PropertySymbol.removeNamedItemWithoutConsequences
]('style');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export default class CSSStyleDeclarationElementStyle {
return this.getComputedElementStyle();
}

const cssText = this.element.attributes['style']?.value;
const cssText = this.element[PropertySymbol.attributes]['style']?.[PropertySymbol.value];

if (cssText) {
if (this.cache.propertyManager && this.cache.cssText === cssText) {
Expand Down Expand Up @@ -94,34 +94,37 @@ export default class CSSStyleDeclarationElementStyle {
};
let shadowRootElements: Array<IStyleAndElement> = [];

if (!this.element.isConnected) {
if (!this.element[PropertySymbol.isConnected]) {
return new CSSStyleDeclarationPropertyManager();
}

if (
this.cache.propertyManager &&
this.cache.documentCacheID === this.element.ownerDocument[PropertySymbol.cacheID]
this.cache.documentCacheID ===
this.element[PropertySymbol.ownerDocument][PropertySymbol.cacheID]
) {
return this.cache.propertyManager;
}

this.cache.documentCacheID = this.element.ownerDocument[PropertySymbol.cacheID];
this.cache.documentCacheID = this.element[PropertySymbol.ownerDocument][PropertySymbol.cacheID];

// Walks through all parent elements and stores them in an array with element and matching CSS text.
while (styleAndElement.element) {
if (styleAndElement.element.nodeType === NodeTypeEnum.elementNode) {
if (styleAndElement.element[PropertySymbol.nodeType] === NodeTypeEnum.elementNode) {
const rootNode = styleAndElement.element.getRootNode();
if (rootNode.nodeType === NodeTypeEnum.documentNode) {
if (rootNode[PropertySymbol.nodeType] === NodeTypeEnum.documentNode) {
documentElements.unshift(styleAndElement);
} else {
shadowRootElements.unshift(styleAndElement);
}
parentElements.unshift(styleAndElement);
}

if (styleAndElement.element === this.element.ownerDocument) {
if (styleAndElement.element === this.element[PropertySymbol.ownerDocument]) {
const styleSheets = <INodeList<IHTMLStyleElement>>(
this.element.ownerDocument.querySelectorAll('style,link[rel="stylesheet"]')
this.element[PropertySymbol.ownerDocument].querySelectorAll(
'style,link[rel="stylesheet"]'
)
);

for (const styleSheet of styleSheets) {
Expand All @@ -136,7 +139,7 @@ export default class CSSStyleDeclarationElementStyle {

styleAndElement = { element: null, cssTexts: [] };
} else if (
styleAndElement.element.nodeType === NodeTypeEnum.documentFragmentNode &&
styleAndElement.element[PropertySymbol.nodeType] === NodeTypeEnum.documentFragmentNode &&
(<IShadowRoot>styleAndElement.element).host
) {
const styleSheets = <INodeList<IHTMLStyleElement>>(
Expand All @@ -160,7 +163,10 @@ export default class CSSStyleDeclarationElementStyle {
}
shadowRootElements = [];
} else {
styleAndElement = { element: <IElement>styleAndElement.element.parentNode, cssTexts: [] };
styleAndElement = {
element: <IElement>styleAndElement.element[PropertySymbol.parentNode],
cssTexts: []
};
}
}

Expand All @@ -175,36 +181,49 @@ export default class CSSStyleDeclarationElementStyle {
parentElement.cssTexts.sort((a, b) => a.priorityWeight - b.priorityWeight);

let elementCSSText = '';
if (CSSStyleDeclarationElementDefaultCSS[(<IElement>parentElement.element).tagName]) {
if (
CSSStyleDeclarationElementDefaultCSS[
(<IElement>parentElement.element)[PropertySymbol.tagName]
]
) {
if (
typeof CSSStyleDeclarationElementDefaultCSS[(<IElement>parentElement.element).tagName] ===
'string'
typeof CSSStyleDeclarationElementDefaultCSS[
(<IElement>parentElement.element)[PropertySymbol.tagName]
] === 'string'
) {
elementCSSText +=
CSSStyleDeclarationElementDefaultCSS[(<IElement>parentElement.element).tagName];
CSSStyleDeclarationElementDefaultCSS[
(<IElement>parentElement.element)[PropertySymbol.tagName]
];
} else {
for (const key of Object.keys(
CSSStyleDeclarationElementDefaultCSS[(<IElement>parentElement.element).tagName]
CSSStyleDeclarationElementDefaultCSS[
(<IElement>parentElement.element)[PropertySymbol.tagName]
]
)) {
if (key === 'default' || !!parentElement.element[key]) {
elementCSSText +=
CSSStyleDeclarationElementDefaultCSS[(<IElement>parentElement.element).tagName][
key
];
CSSStyleDeclarationElementDefaultCSS[
(<IElement>parentElement.element)[PropertySymbol.tagName]
][key];
}
}
}
elementCSSText +=
CSSStyleDeclarationElementDefaultCSS[(<IElement>parentElement.element).tagName];
CSSStyleDeclarationElementDefaultCSS[
(<IElement>parentElement.element)[PropertySymbol.tagName]
];
}

for (const cssText of parentElement.cssTexts) {
elementCSSText += cssText.cssText;
}

const elementStyleAttribute = (<IElement>parentElement.element).attributes['style'];
const elementStyleAttribute = (<IElement>parentElement.element)[PropertySymbol.attributes][
'style'
];
if (elementStyleAttribute) {
elementCSSText += elementStyleAttribute.value;
elementCSSText += elementStyleAttribute[PropertySymbol.value];
}

CSSStyleDeclarationCSSParser.parse(elementCSSText, (name, value, important) => {
Expand All @@ -229,7 +248,7 @@ export default class CSSStyleDeclarationElementStyle {
parentFontSize,
parentSize: parentFontSize
});
if ((<IElement>parentElement.element).tagName === 'HTML') {
if ((<IElement>parentElement.element)[PropertySymbol.tagName] === 'HTML') {
rootFontSize = parsedValue;
} else if (parentElement !== targetElement) {
parentFontSize = parsedValue;
Expand Down Expand Up @@ -277,7 +296,7 @@ export default class CSSStyleDeclarationElementStyle {
return;
}

const ownerWindow = this.element.ownerDocument[PropertySymbol.defaultView];
const ownerWindow = this.element[PropertySymbol.ownerDocument][PropertySymbol.ownerWindow];

for (const rule of options.cssRules) {
if (rule.type === CSSRuleTypeEnum.styleRule) {
Expand Down Expand Up @@ -308,7 +327,7 @@ export default class CSSStyleDeclarationElementStyle {
new MediaQueryList({
ownerWindow,
media: (<CSSMediaRule>rule).conditionText,
rootFontSize: this.element.tagName === 'HTML' ? 16 : null
rootFontSize: this.element[PropertySymbol.tagName] === 'HTML' ? 16 : null
}).matches
) {
this.parseCSSRules({
Expand Down Expand Up @@ -362,7 +381,7 @@ export default class CSSStyleDeclarationElementStyle {
}): string {
if (
WindowBrowserSettingsReader.getSettings(
this.element.ownerDocument[PropertySymbol.defaultView]
this.element[PropertySymbol.ownerDocument][PropertySymbol.ownerWindow]
).disableComputedStyleRendering
) {
return options.value;
Expand All @@ -375,7 +394,7 @@ export default class CSSStyleDeclarationElementStyle {
while ((match = regexp.exec(options.value)) !== null) {
if (match[1] !== 'px') {
const valueInPixels = CSSMeasurementConverter.toPixels({
ownerWindow: this.element.ownerDocument[PropertySymbol.defaultView],
ownerWindow: this.element[PropertySymbol.ownerDocument][PropertySymbol.ownerWindow],
value: match[0],
rootFontSize: options.rootFontSize,
parentFontSize: options.parentFontSize,
Expand Down
12 changes: 6 additions & 6 deletions packages/happy-dom/src/dom-implementation/DOMImplementation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ export default class DOMImplementation {
* TODO: Not fully implemented.
*/
public createDocument(): IDocument {
return new this.#document[PropertySymbol.defaultView].HTMLDocument();
return new this.#document[PropertySymbol.ownerWindow].HTMLDocument();
}

/**
* Creates and returns an HTML Document.
*/
public createHTMLDocument(): IDocument {
return new this.#document[PropertySymbol.defaultView].HTMLDocument();
return new this.#document[PropertySymbol.ownerWindow].HTMLDocument();
}

/**
Expand All @@ -48,11 +48,11 @@ export default class DOMImplementation {
): DocumentType {
const documentType = NodeFactory.createNode<DocumentType>(
this.#document,
this.#document[PropertySymbol.defaultView].DocumentType
this.#document[PropertySymbol.ownerWindow].DocumentType
);
documentType.name = qualifiedName;
documentType.publicId = publicId;
documentType.systemId = systemId;
documentType[PropertySymbol.name] = qualifiedName;
documentType[PropertySymbol.publicId] = publicId;
documentType[PropertySymbol.systemId] = systemId;
return documentType;
}
}
Loading

0 comments on commit e470b8e

Please sign in to comment.