Skip to content

Commit

Permalink
chore: [#1510] Starts on implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
capricorn86 committed Aug 21, 2024
1 parent e18524e commit 897a657
Show file tree
Hide file tree
Showing 16 changed files with 430 additions and 26 deletions.
2 changes: 1 addition & 1 deletion packages/happy-dom/src/ClassMethodBinder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export default class ClassMethodBinder {
public static bindMethods(
target: Object,
classes: any[],
options?: { bindSymbols: boolean; forwardToPrototype: boolean }
options?: { bindSymbols?: boolean; forwardToPrototype?: boolean }
): void {
for (const _class of classes) {
const propertyDescriptors = Object.getOwnPropertyDescriptors(_class.prototype);
Expand Down
2 changes: 1 addition & 1 deletion packages/happy-dom/src/PropertySymbol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,6 @@ export const computedStyle = Symbol('computedStyle');
export const getFormControlItems = Symbol('getFormControlItems');
export const getFormControlNamedItem = Symbol('getFormControlNamedItem');
export const dataset = Symbol('dataset');
export const customElementDefineCallback = Symbol('customElementDefineCallback');
export const getNamespaceItemKey = Symbol('getNamespaceItemKey');
export const getNamedItemKey = Symbol('getNamedItemKey');
export const namespaceItems = Symbol('namespaceItems');
Expand Down Expand Up @@ -220,3 +219,4 @@ export const id = Symbol('id');
export const illegalConstructor = Symbol('illegalConstructor');
export const state = Symbol('state');
export const canvas = Symbol('canvas');
export const popoverTargetElement = Symbol('popoverTargetElement');
13 changes: 11 additions & 2 deletions packages/happy-dom/src/nodes/document/Document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,7 @@ export default class Document extends Node {
/**
* Returns URL.
*
* @returns the URL of the current document.
* @returns URL of the current document.
* */
public get URL(): string {
return this[PropertySymbol.ownerWindow].location.href;
Expand All @@ -557,12 +557,21 @@ export default class Document extends Node {
/**
* Returns document URI.
*
* @returns the URL of the current document.
* @returns URL of the current document.
* */
public get documentURI(): string {
return this.URL;
}

/**
* Returns domain.
*
* @returns Domain.
* */
public get domain(): string {
return this[PropertySymbol.ownerWindow].location.hostname;
}

/**
* Returns document visibility state.
*
Expand Down
5 changes: 1 addition & 4 deletions packages/happy-dom/src/nodes/element/HTMLCollection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,7 @@ export default class HTMLCollection<T extends Element, NamedItem = T> {
ClassMethodBinder.bindMethods(
this,
this.constructor !== HTMLCollection ? [HTMLCollection, this.constructor] : [HTMLCollection],
{
bindSymbols: true,
forwardToPrototype: true
}
{ bindSymbols: true }
);

return new Proxy(this, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export default class HTMLButtonElement extends HTMLElement {
public [PropertySymbol.validationMessage] = '';
public [PropertySymbol.validity] = new ValidityState(this);
public [PropertySymbol.formNode]: HTMLFormElement | null = null;
public [PropertySymbol.popoverTargetElement]: HTMLElement | null = null;

/**
* Returns validation message.
Expand Down Expand Up @@ -250,6 +251,51 @@ export default class HTMLButtonElement extends HTMLElement {
return HTMLLabelElementUtility.getAssociatedLabelElements(this);
}

/**
* Returns popover target element.
*
* @returns Popover target element.
*/
public get popoverTargetElement(): HTMLElement | null {
return this[PropertySymbol.popoverTargetElement];
}

/**
* Sets popover target element.
*
* @param popoverTargetElement Popover target element.
*/
public set popoverTargetElement(popoverTargetElement: HTMLElement | null) {
if (popoverTargetElement !== null && !(popoverTargetElement instanceof HTMLElement)) {
throw new TypeError(
`Failed to set the 'popoverTargetElement' property on 'HTMLInputElement': Failed to convert value to 'Element'.`
);
}
this[PropertySymbol.popoverTargetElement] = popoverTargetElement;
}

/**
* Returns popover target action.
*
* @returns Popover target action.
*/
public get popoverTargetAction(): string {
const value = this.getAttribute('popovertargetaction');
if (value === null || (value !== 'hide' && value !== 'show' && value !== 'toggle')) {
return 'toggle';
}
return value;
}

/**
* Sets popover target action.
*
* @param value Popover target action.
*/
public set popoverTargetAction(value: string) {
this.setAttribute('popovertargetaction', value);
}

/**
* Checks validity.
*
Expand Down
51 changes: 42 additions & 9 deletions packages/happy-dom/src/nodes/html-element/HTMLElement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,10 @@ export default class HTMLElement extends Element {
public [PropertySymbol.clientLeft] = 0;
public [PropertySymbol.clientTop] = 0;
public [PropertySymbol.style]: CSSStyleDeclaration = null;
private [PropertySymbol.dataset]: DOMStringMap | null = null;
private [PropertySymbol.customElementDefineCallback]: () => void = null;
public [PropertySymbol.dataset]: DOMStringMap | null = null;

// Private properties
#customElementDefineCallback: () => void = null;

/**
* Returns access key.
Expand Down Expand Up @@ -453,6 +455,39 @@ export default class HTMLElement extends Element {
this.setAttribute('title', title);
}

/**
* Returns popover.
*
* @returns Popover.
*/
public get popover(): string | null {
const value = this.getAttribute('popover');
switch (value) {
case null:
return null;
case '':
case 'auto':
return 'auto';
case 'manual':
return 'manual';
default:
return 'manual';
}
}

/**
* Sets popover.
*
* @param value Value.
*/
public set popover(value: string | null) {
if (value === null) {
this.removeAttribute('popover');
return;
}
this.setAttribute('popover', value);
}

/**
* Triggers a click event.
*/
Expand Down Expand Up @@ -515,7 +550,7 @@ export default class HTMLElement extends Element {
PropertySymbol.callbacks
];

if (!this[PropertySymbol.customElementDefineCallback]) {
if (!this.#customElementDefineCallback) {
const callback = (): void => {
if (this[PropertySymbol.parentNode]) {
const newElement = <HTMLElement>(
Expand Down Expand Up @@ -595,7 +630,7 @@ export default class HTMLElement extends Element {
};
callbacks[localName] = callbacks[localName] || [];
callbacks[localName].push(callback);
this[PropertySymbol.customElementDefineCallback] = callback;
this.#customElementDefineCallback = callback;
}
}

Expand All @@ -622,17 +657,15 @@ export default class HTMLElement extends Element {
PropertySymbol.callbacks
];

if (callbacks[localName] && this[PropertySymbol.customElementDefineCallback]) {
const index = callbacks[localName].indexOf(
this[PropertySymbol.customElementDefineCallback]
);
if (callbacks[localName] && this.#customElementDefineCallback) {
const index = callbacks[localName].indexOf(this.#customElementDefineCallback);
if (index !== -1) {
callbacks[localName].splice(index, 1);
}
if (!callbacks[localName].length) {
delete callbacks[localName];
}
this[PropertySymbol.customElementDefineCallback] = null;
this.#customElementDefineCallback = null;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export default class HTMLInputElement extends HTMLElement {
public [PropertySymbol.validity] = new ValidityState(this);
public [PropertySymbol.files]: FileList = new FileList();
public [PropertySymbol.formNode]: HTMLFormElement | null = null;
public [PropertySymbol.popoverTargetElement]: HTMLElement | null = null;

// Private properties
#selectionStart: number = null;
Expand Down Expand Up @@ -1115,6 +1116,51 @@ export default class HTMLInputElement extends HTMLElement {
return <HTMLDataListElement | null>rootNode.querySelector(`datalist#${id}`);
}

/**
* Returns popover target element.
*
* @returns Popover target element.
*/
public get popoverTargetElement(): HTMLElement | null {
return this[PropertySymbol.popoverTargetElement];
}

/**
* Sets popover target element.
*
* @param popoverTargetElement Popover target element.
*/
public set popoverTargetElement(popoverTargetElement: HTMLElement | null) {
if (popoverTargetElement !== null && !(popoverTargetElement instanceof HTMLElement)) {
throw new TypeError(
`Failed to set the 'popoverTargetElement' property on 'HTMLInputElement': Failed to convert value to 'Element'.`
);
}
this[PropertySymbol.popoverTargetElement] = popoverTargetElement;
}

/**
* Returns popover target action.
*
* @returns Popover target action.
*/
public get popoverTargetAction(): string {
const value = this.getAttribute('popovertargetaction');
if (value === null || (value !== 'hide' && value !== 'show' && value !== 'toggle')) {
return 'toggle';
}
return value;
}

/**
* Sets popover target action.
*
* @param value Popover target action.
*/
public set popoverTargetAction(value: string) {
this.setAttribute('popovertargetaction', value);
}

/**
* Sets validation message.
*
Expand Down
5 changes: 1 addition & 4 deletions packages/happy-dom/src/nodes/node/NodeList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,7 @@ class NodeList<T extends Node> {
ClassMethodBinder.bindMethods(
this,
this.constructor !== NodeList ? [NodeList, this.constructor] : [NodeList],
{
bindSymbols: true,
forwardToPrototype: true
}
{ bindSymbols: true }
);

return new Proxy(this, {
Expand Down
11 changes: 9 additions & 2 deletions packages/happy-dom/test/nodes/document/Document.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -549,18 +549,25 @@ describe('Document', () => {
});
});

describe('URL', () => {
describe('get URL()', () => {
it('Returns the URL of the document.', () => {
document.location.href = 'http://localhost:8080/path/to/file.html';
expect(document.URL).toBe('http://localhost:8080/path/to/file.html');
});
});
describe('documentURI', () => {

describe('get documentURI()', () => {
it('Returns the documentURI of the document.', () => {
document.location.href = 'http://localhost:8080/path/to/file.html';
expect(document.documentURI).toBe('http://localhost:8080/path/to/file.html');
});
});
describe('get domain()', () => {
it('Returns hostname.', () => {
document.location.href = 'http://localhost:8080/path/to/file.html';
expect(document.domain).toBe('localhost');
});
});

describe('append()', () => {
it('Inserts a set of Node objects or DOMString objects after the last child of the ParentNode. DOMString objects are inserted as equivalent Text nodes.', () => {
Expand Down
38 changes: 38 additions & 0 deletions packages/happy-dom/test/nodes/element/HTMLCollection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { beforeEach, describe, it, expect } from 'vitest';
import HTMLElement from '../../../src/nodes/html-element/HTMLElement.js';
import * as PropertySymbol from '../../../src/PropertySymbol.js';
import HTMLCollection from '../../../src/nodes/element/HTMLCollection.js';
import Element from '../../../src/nodes/element/Element.js';

describe('HTMLCollection', () => {
let window: Window;
Expand Down Expand Up @@ -170,4 +171,41 @@ describe('HTMLCollection', () => {
expect(typeof div.children['item']).toBe('function');
});
});

describe('[Symbol.iterator]()', () => {
it('Returns iterator', () => {
const elements: Element[] = [];

const parent = document.createElement('div');
const element1 = document.createElement('div');
const element2 = document.createElement('div');
const element3 = document.createElement('div');

parent.appendChild(element1);
parent.appendChild(element2);
parent.appendChild(element3);

for (const child of parent.children) {
elements.push(child);
}

expect(elements).toEqual([element1, element2, element3]);
});
});

describe('Array.from()', () => {
it('Should support Array.from()', () => {
const items: Element[] = [];
const collection = new HTMLCollection(PropertySymbol.illegalConstructor, () => items);
const element1 = document.createElement('div');
const element2 = document.createElement('div');
const element3 = document.createElement('div');

items.push(element1);
items.push(element2);
items.push(element3);

expect(Array.from(collection)).toEqual([element1, element2, element3]);
});
});
});
Loading

0 comments on commit 897a657

Please sign in to comment.