Skip to content

Commit

Permalink
Merge branch 'master' into feature/add-queryCommandSupported
Browse files Browse the repository at this point in the history
  • Loading branch information
capricorn86 committed May 6, 2024
2 parents 3a426bd + 7a5b003 commit 9bf6a59
Show file tree
Hide file tree
Showing 16 changed files with 633 additions and 32 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ And much more..

<p align="center"><b>Backers</b></p>

<p align="center"><a href="https://sourcegraph.com/"><img alt="Sourcegraph" src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/3979584?v=4&h=40&w=40&fit=cover&mask=circle&maxage=7d"></a> <a href="https://github.com/maxmilton"><img alt="Github user @maxmilton" src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/14946546?v=4&h=40&w=40&fit=cover&mask=circle&maxage=7d"></a> <a href="https://github.com/taufiq-dev"><img alt="Github user @taufiq-dev" src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/20721306?v=4&h=40&w=40&fit=cover&mask=circle&maxage=7d"></a></p>
<p align="center"><a href="https://sourcegraph.com/"><img alt="Sourcegraph" src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/3979584?v=4&h=40&w=40&fit=cover&mask=circle&maxage=7d"></a></p>

## Contributing

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ export default class BrowserFrameNavigator {
const width = frame.window.innerWidth;
const height = frame.window.innerHeight;
const devicePixelRatio = frame.window.devicePixelRatio;
const parentWindow = frame.window.parent !== frame.window ? frame.window.parent : null;
const topWindow = frame.window.top !== frame.window ? frame.window.top : null;

for (const childFrame of frame.childFrames) {
BrowserFrameFactory.destroyFrame(childFrame);
Expand All @@ -104,6 +106,8 @@ export default class BrowserFrameNavigator {
frame[PropertySymbol.asyncTaskManager] = new AsyncTaskManager();

(<BrowserWindow>frame.window) = new windowClass(frame, { url: targetURL.href, width, height });
(<BrowserWindow>frame.window.parent) = parentWindow;
(<BrowserWindow>frame.window.top) = topWindow;
(<number>frame.window.devicePixelRatio) = devicePixelRatio;

if (referrer) {
Expand Down
2 changes: 2 additions & 0 deletions packages/happy-dom/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ import DocumentFragment from './nodes/document-fragment/DocumentFragment.js';
import DocumentType from './nodes/document-type/DocumentType.js';
import Document from './nodes/document/Document.js';
import DOMRect from './nodes/element/DOMRect.js';
import DOMRectReadOnly from './nodes/element/DOMRectReadOnly.js';
import Element from './nodes/element/Element.js';
import HTMLCollection from './nodes/element/HTMLCollection.js';
import HTMLAnchorElement from './nodes/html-anchor-element/HTMLAnchorElement.js';
Expand Down Expand Up @@ -211,6 +212,7 @@ export {
DOMException,
DOMParser,
DOMRect,
DOMRectReadOnly,
DataTransfer,
DataTransferItem,
DataTransferItemList,
Expand Down
4 changes: 2 additions & 2 deletions packages/happy-dom/src/nodes/document/Document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -318,8 +318,8 @@ export default class Document extends Node {
/**
* Returns a collection of all form elements in a document.
*/
public get forms(): NodeList<HTMLFormElement> {
return this.querySelectorAll('form');
public get forms(): HTMLCollection<HTMLFormElement> {
return this.getElementsByTagName('form');
}

/**
Expand Down
64 changes: 41 additions & 23 deletions packages/happy-dom/src/nodes/element/DOMRect.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,48 @@
import DOMRectReadOnly from './DOMRectReadOnly.js';
import * as PropertySymbol from '../../PropertySymbol.js';
import IDOMRectInit from './IDOMRectInit.js';

/* eslint-disable jsdoc/require-jsdoc */

/**
* Bounding rect object.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/DOMRect
*/
export default class DOMRect {
public x = 0;
public y = 0;
public width = 0;
public height = 0;
public top = 0;
public right = 0;
public bottom = 0;
public left = 0;

/**
* Constructor.
*
* @param [x] X position.
* @param [y] Y position.
* @param [width] Width.
* @param [height] Height.
*/
constructor(x?, y?, width?, height?) {
this.x = x || 0;
this.y = y || 0;
this.width = width || 0;
this.height = height || 0;
export default class DOMRect extends DOMRectReadOnly {
public set x(value: number) {
this[PropertySymbol.x] = value;
}

public get x(): number {
return this[PropertySymbol.x];
}

public set y(value: number) {
this[PropertySymbol.y] = value;
}

public get y(): number {
return this[PropertySymbol.y];
}

public set width(value: number) {
this[PropertySymbol.width] = value;
}

public get width(): number {
return this[PropertySymbol.width];
}

public set height(value: number) {
this[PropertySymbol.height] = value;
}

public get height(): number {
return this[PropertySymbol.height];
}

public static fromRect(other: IDOMRectInit): DOMRect {
return new DOMRect(other.x, other.y, other.width, other.height);
}
}
80 changes: 80 additions & 0 deletions packages/happy-dom/src/nodes/element/DOMRectReadOnly.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import * as PropertySymbol from '../../PropertySymbol.js';
import IDOMRectInit from './IDOMRectInit.js';

/* eslint-disable jsdoc/require-jsdoc */

/**
* Bounding rect readonly object.
*
* @see https://drafts.fxtf.org/geometry/#DOMRect
*/
export default class DOMRectReadOnly implements IDOMRectInit {
protected [PropertySymbol.x]: number = 0;
protected [PropertySymbol.y]: number = 0;
protected [PropertySymbol.width]: number = 0;
protected [PropertySymbol.height]: number = 0;

/**
* Constructor.
*
* @param [x] X position.
* @param [y] Y position.
* @param [width] Width.
* @param [height] Height.
*/
constructor(x?: number | null, y?: number | null, width?: number | null, height?: number | null) {
this[PropertySymbol.x] = x !== undefined && x !== null ? Number(x) : 0;
this[PropertySymbol.y] = y !== undefined && y !== null ? Number(y) : 0;
this[PropertySymbol.width] = width !== undefined && width !== null ? Number(width) : 0;
this[PropertySymbol.height] = height !== undefined && height !== null ? Number(height) : 0;
}

public get x(): number {
return this[PropertySymbol.x];
}

public get y(): number {
return this[PropertySymbol.y];
}

public get width(): number {
return this[PropertySymbol.width];
}

public get height(): number {
return this[PropertySymbol.height];
}

public get top(): number {
return Math.min(this[PropertySymbol.y], this[PropertySymbol.y] + this[PropertySymbol.height]);
}

public get right(): number {
return Math.max(this[PropertySymbol.x], this[PropertySymbol.x] + this[PropertySymbol.width]);
}

public get bottom(): number {
return Math.max(this[PropertySymbol.y], this[PropertySymbol.y] + this[PropertySymbol.height]);
}

public get left(): number {
return Math.min(this[PropertySymbol.x], this[PropertySymbol.x] + this[PropertySymbol.width]);
}

public toJSON(): object {
return {
x: this.x,
y: this.y,
width: this.width,
height: this.height,
top: this.top,
right: this.right,
bottom: this.bottom,
left: this.left
};
}

public static fromRect(other: IDOMRectInit): DOMRectReadOnly {
return new DOMRectReadOnly(other.x, other.y, other.width, other.height);
}
}
7 changes: 7 additions & 0 deletions packages/happy-dom/src/nodes/element/ElementUtility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,13 @@ export default class ElementUtility {
parentNodeChildren.splice(index, 1);
}
}
const parentChildNodes = (<Element>ancestorNode)[PropertySymbol.childNodes];
if (parentChildNodes) {
const index = parentChildNodes.indexOf(newNode);
if (index !== -1) {
parentChildNodes.splice(index, 1);
}
}
}

const ancestorNodeChildren = <HTMLCollection<HTMLElement>>(
Expand Down
6 changes: 6 additions & 0 deletions packages/happy-dom/src/nodes/element/IDOMRectInit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default interface IDOMRectInit {
readonly x: number;
readonly y: number;
readonly width: number;
readonly height: number;
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,14 @@ export default class HTMLIFrameElementNamedNodeMap extends HTMLElementNamedNodeM
public override setNamedItem(item: Attr): Attr | null {
const replacedAttribute = super.setNamedItem(item);

if (item[PropertySymbol.name] === 'srcdoc') {
this.#pageLoader.loadPage();
}

// If the src attribute and the srcdoc attribute are both specified together, the srcdoc attribute takes priority.
if (
item[PropertySymbol.name] === 'src' &&
this[PropertySymbol.ownerElement][PropertySymbol.attributes]['srcdoc']?.value === undefined &&
item[PropertySymbol.value] &&
item[PropertySymbol.value] !== replacedAttribute?.[PropertySymbol.value]
) {
Expand All @@ -70,6 +76,21 @@ export default class HTMLIFrameElementNamedNodeMap extends HTMLElementNamedNodeM
return replacedAttribute || null;
}

/**
* @override
*/
public override [PropertySymbol.removeNamedItem](name: string): Attr | null {
const removedItem = super[PropertySymbol.removeNamedItem](name);
if (
removedItem &&
(removedItem[PropertySymbol.name] === 'srcdoc' || removedItem[PropertySymbol.name] === 'src')
) {
this.#pageLoader.loadPage();
}

return removedItem;
}

/**
*
* @param tokens
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export default class HTMLIFrameElementPageLoader {
#contentWindowContainer: { window: BrowserWindow | CrossOriginBrowserWindow | null };
#browserParentFrame: IBrowserFrame;
#browserIFrame: IBrowserFrame;
#srcdoc: string | null = null;

/**
* Constructor.
Expand All @@ -44,15 +45,43 @@ export default class HTMLIFrameElementPageLoader {
*/
public loadPage(): void {
if (!this.#element[PropertySymbol.isConnected]) {
if (this.#browserIFrame) {
BrowserFrameFactory.destroyFrame(this.#browserIFrame);
this.#browserIFrame = null;
}
this.#contentWindowContainer.window = null;
this.unloadPage();
return;
}

const srcdoc = this.#element.getAttribute('srcdoc');
const window = this.#element[PropertySymbol.ownerDocument][PropertySymbol.ownerWindow];

if (srcdoc !== null) {
if (this.#srcdoc === srcdoc) {
return;
}

this.unloadPage();

this.#browserIFrame = BrowserFrameFactory.createChildFrame(this.#browserParentFrame);
this.#browserIFrame.url = 'about:srcdoc';

this.#contentWindowContainer.window = this.#browserIFrame.window;

(<BrowserWindow>this.#browserIFrame.window.top) = this.#browserParentFrame.window.top;
(<BrowserWindow>this.#browserIFrame.window.parent) = this.#browserParentFrame.window;

this.#browserIFrame.window.document.open();
this.#browserIFrame.window.document.write(srcdoc);

this.#srcdoc = srcdoc;

this.#element[PropertySymbol.ownerDocument][PropertySymbol.ownerWindow].requestAnimationFrame(
() => this.#element.dispatchEvent(new Event('load'))
);
return;
}

if (this.#srcdoc !== null) {
this.unloadPage();
}

const originURL = this.#browserParentFrame.window.location;
const targetURL = BrowserFrameURL.getRelativeURL(this.#browserParentFrame, this.#element.src);

Expand Down Expand Up @@ -105,5 +134,6 @@ export default class HTMLIFrameElementPageLoader {
this.#browserIFrame = null;
}
this.#contentWindowContainer.window = null;
this.#srcdoc = null;
}
}
2 changes: 2 additions & 0 deletions packages/happy-dom/src/window/BrowserWindow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ import Plugin from '../navigator/Plugin.js';
import PluginArray from '../navigator/PluginArray.js';
import Fetch from '../fetch/Fetch.js';
import DOMRect from '../nodes/element/DOMRect.js';
import DOMRectReadOnly from '../nodes/element/DOMRectReadOnly.js';
import VMGlobalPropertyScript from './VMGlobalPropertyScript.js';
import VM from 'vm';
import { Buffer } from 'buffer';
Expand Down Expand Up @@ -372,6 +373,7 @@ export default class BrowserWindow extends EventTarget implements INodeJSGlobal
public readonly PluginArray = PluginArray;
public readonly FileList = FileList;
public readonly DOMRect = DOMRect;
public readonly DOMRectReadOnly = DOMRectReadOnly;
public readonly RadioNodeList = RadioNodeList;
public readonly ValidityState = ValidityState;
public readonly Headers = Headers;
Expand Down
1 change: 1 addition & 0 deletions packages/happy-dom/test/nodes/document/Document.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ describe('Document', () => {

const forms = document.forms;

expect(forms).toBeInstanceOf(HTMLCollection);
expect(forms.length).toBe(2);
expect(forms[0]).toBe(form1);
expect(forms[1]).toBe(form2);
Expand Down

0 comments on commit 9bf6a59

Please sign in to comment.