Skip to content

Commit

Permalink
fix: [#1332] Return URL relative to window location in HTMLIFrameElem…
Browse files Browse the repository at this point in the history
…ent.src
  • Loading branch information
capricorn86 committed Apr 10, 2024
1 parent 614bd9d commit aa67746
Show file tree
Hide file tree
Showing 22 changed files with 303 additions and 34 deletions.
1 change: 1 addition & 0 deletions packages/happy-dom/src/PropertySymbol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,4 @@ export const constraints = Symbol('constraints');
export const capabilities = Symbol('capabilities');
export const settings = Symbol('settings');
export const dataListNode = Symbol('dataListNode');
export const setNamedItem = Symbol('setNamedItem');
20 changes: 17 additions & 3 deletions packages/happy-dom/src/named-node-map/NamedNodeMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export default class NamedNodeMap {
* @returns Replaced item.
*/
public setNamedItem(item: Attr): Attr | null {
return this[PropertySymbol.setNamedItemWithoutConsequences](item);
return this[PropertySymbol.setNamedItem](item);
}

/**
Expand All @@ -97,7 +97,7 @@ export default class NamedNodeMap {
* @returns Replaced item.
*/
public setNamedItemNS(item: Attr): Attr | null {
return this.setNamedItem(item);
return this[PropertySymbol.setNamedItem](item);
}

/**
Expand Down Expand Up @@ -134,7 +134,19 @@ export default class NamedNodeMap {
}

/**
* Sets named item without calling listeners for certain attributes.
* Sets named item.
*
* This method may be overridden by subclasses to act on attribute changes.
*
* @param item Item.
* @returns Replaced item.
*/
public [PropertySymbol.setNamedItem](item: Attr): Attr | null {
return this[PropertySymbol.setNamedItemWithoutConsequences](item);
}

/**
* Sets named item without potential overrides done in [PropertySymbol.setNamedItem]().
*
* @param item Item.
* @returns Replaced item.
Expand Down Expand Up @@ -164,6 +176,8 @@ export default class NamedNodeMap {
/**
* Removes an item without throwing if it doesn't exist.
*
* This method may be overridden by subclasses to act on attribute changes.
*
* @param name Name of item.
* @returns Removed item, or null if it didn't exist.
*/
Expand Down
4 changes: 2 additions & 2 deletions packages/happy-dom/src/nodes/element/ElementNamedNodeMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,15 @@ export default class ElementNamedNodeMap extends NamedNodeMap {
/**
* @override
*/
public override setNamedItem(item: Attr): Attr | null {
public override [PropertySymbol.setNamedItem](item: Attr): Attr | null {
if (!item[PropertySymbol.name]) {
return null;
}

item[PropertySymbol.name] = this[PropertySymbol.getAttributeName](item[PropertySymbol.name]);
(<Element>item[PropertySymbol.ownerElement]) = this[PropertySymbol.ownerElement];

const replacedItem = super.setNamedItem(item);
const replacedItem = super[PropertySymbol.setNamedItem](item);
const oldValue = replacedItem ? replacedItem[PropertySymbol.value] : null;

if (this[PropertySymbol.ownerElement][PropertySymbol.isConnected]) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ export default class HTMLButtonElementNamedNodeMap extends HTMLElementNamedNodeM
/**
* @override
*/
public override setNamedItem(item: Attr): Attr | null {
const replacedItem = super.setNamedItem(item);
public override [PropertySymbol.setNamedItem](item: Attr): Attr | null {
const replacedItem = super[PropertySymbol.setNamedItem](item);

if (
(item[PropertySymbol.name] === 'id' || item[PropertySymbol.name] === 'name') &&
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,39 @@
import Event from '../../event/Event.js';
import HTMLElement from '../html-element/HTMLElement.js';
import * as PropertySymbol from '../../PropertySymbol.js';
import NamedNodeMap from '../../named-node-map/NamedNodeMap.js';
import HTMLDetailsElementNamedNodeMap from './HTMLDetailsElementNamedNodeMap.js';

/**
* HTMLDetailsElement
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLDetailsElement
*/
export default class HTMLDetailsElement extends HTMLElement {}
export default class HTMLDetailsElement extends HTMLElement {
public override [PropertySymbol.attributes]: NamedNodeMap = new HTMLDetailsElementNamedNodeMap(
this
);

// Events
public ontoggle: (event: Event) => void | null = null;

/**
* Returns the open attribute.
*/
public get open(): boolean {
return this.getAttribute('open') !== null;
}

/**
* Sets the open attribute.
*
* @param open New value.
*/
public set open(open: boolean) {
if (open) {
this.setAttribute('open', '');
} else {
this.removeAttribute('open');
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import Attr from '../attr/Attr.js';
import * as PropertySymbol from '../../PropertySymbol.js';
import HTMLElementNamedNodeMap from '../html-element/HTMLElementNamedNodeMap.js';
import Event from '../../event/Event.js';
import HTMLDetailsElement from './HTMLDetailsElement.js';

/**
* Named Node Map.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/NamedNodeMap
*/
export default class HTMLDetailsElementNamedNodeMap extends HTMLElementNamedNodeMap {
protected [PropertySymbol.ownerElement]: HTMLDetailsElement;

/**
* @override
*/
public override [PropertySymbol.setNamedItem](item: Attr): Attr | null {
const replacedItem = super[PropertySymbol.setNamedItem](item);

if (item[PropertySymbol.name] === 'open') {
if (item[PropertySymbol.value] !== replacedItem?.[PropertySymbol.value]) {
this[PropertySymbol.ownerElement].dispatchEvent(new Event('toggle'));
}
}

return replacedItem || null;
}

/**
* @override
*/
public override [PropertySymbol.removeNamedItem](name: string): Attr | null {
const removedItem = super[PropertySymbol.removeNamedItem](name);

if (removedItem && removedItem[PropertySymbol.name] === 'open') {
this[PropertySymbol.ownerElement].dispatchEvent(new Event('toggle'));
}

return removedItem;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import * as PropertySymbol from '../../PropertySymbol.js';
/**
* HTML Dialog Element.
*
* Reference:
* https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement.
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement
*/
export default class HTMLDialogElement extends HTMLElement {
// Internal properties
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ export default class HTMLElementNamedNodeMap extends ElementNamedNodeMap {
/**
* @override
*/
public override setNamedItem(item: Attr): Attr | null {
const replacedItem = super.setNamedItem(item);
public override [PropertySymbol.setNamedItem](item: Attr): Attr | null {
const replacedItem = super[PropertySymbol.setNamedItem](item);

if (
item[PropertySymbol.name] === 'style' &&
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,90 @@
import HTMLElement from '../html-element/HTMLElement.js';
import * as PropertySymbol from '../../PropertySymbol.js';

/**
* HTMLEmbedElement
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLEmbedElement
*/
export default class HTMLEmbedElement extends HTMLElement {}
export default class HTMLEmbedElement extends HTMLElement {
/**
* Returns height.
*
* @returns Height.
*/
public get height(): string {
return this.getAttribute('height') || '';
}

/**
* Sets height.
*
* @param height Height.
*/
public set height(height: string) {
this.setAttribute('height', height);
}

/**
* Returns width.
*
* @returns Width.
*/
public get width(): string {
return this.getAttribute('width') || '';
}

/**
* Sets width.
*
* @param width Width.
*/
public set width(width: string) {
this.setAttribute('width', width);
}

/**
* Returns source.
*
* @returns Source.
*/
public get src(): string {
if (!this.hasAttribute('src')) {
return '';
}

try {
return new URL(this.getAttribute('src'), this[PropertySymbol.ownerDocument].location.href)
.href;
} catch (e) {
return this.getAttribute('src');
}
}

/**
* Sets source.
*
* @param src Source.
*/
public set src(src: string) {
this.setAttribute('src', src);
}

/**
* Returns type.
*
* @returns Type.
*/
public get type(): string {
return this.getAttribute('type') || '';
}

/**
* Sets type.
*
* @param type Type.
*/
public set type(type: string) {
this.setAttribute('type', type);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ export default class HTMLHyperlinkElementNamedNodeMap extends HTMLElementNamedNo
/**
* @override
*/
public override setNamedItem(item: Attr): Attr | null {
const replacedItem = super.setNamedItem(item);
public override [PropertySymbol.setNamedItem](item: Attr): Attr | null {
const replacedItem = super[PropertySymbol.setNamedItem](item);

if (
item[PropertySymbol.name] === 'rel' &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,16 @@ export default class HTMLIFrameElement extends HTMLElement {
* @returns Source.
*/
public get src(): string {
return this.getAttribute('src') || '';
if (!this.hasAttribute('src')) {
return '';
}

try {
return new URL(this.getAttribute('src'), this[PropertySymbol.ownerDocument].location.href)
.href;
} catch (e) {
return this.getAttribute('src');
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ export default class HTMLIFrameElementNamedNodeMap extends HTMLElementNamedNodeM
/**
* @override
*/
public override setNamedItem(item: Attr): Attr | null {
const replacedAttribute = super.setNamedItem(item);
public override [PropertySymbol.setNamedItem](item: Attr): Attr | null {
const replacedAttribute = super[PropertySymbol.setNamedItem](item);

if (
item[PropertySymbol.name] === 'src' &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ export default class HTMLInputElementNamedNodeMap extends HTMLElementNamedNodeMa
/**
* @override
*/
public override setNamedItem(item: Attr): Attr | null {
const replacedItem = super.setNamedItem(item);
public override [PropertySymbol.setNamedItem](item: Attr): Attr | null {
const replacedItem = super[PropertySymbol.setNamedItem](item);

if (
(item[PropertySymbol.name] === 'id' || item[PropertySymbol.name] === 'name') &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ export default class HTMLLinkElementNamedNodeMap extends HTMLElementNamedNodeMap
/**
* @override
*/
public override setNamedItem(item: Attr): Attr | null {
const replacedItem = super.setNamedItem(item);
public override [PropertySymbol.setNamedItem](item: Attr): Attr | null {
const replacedItem = super[PropertySymbol.setNamedItem](item);

if (
item[PropertySymbol.name] === 'rel' &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ export default class HTMLOptionElementNamedNodeMap extends HTMLElementNamedNodeM
/**
* @override
*/
public override setNamedItem(item: Attr): Attr | null {
const replacedItem = super.setNamedItem(item);
public override [PropertySymbol.setNamedItem](item: Attr): Attr | null {
const replacedItem = super[PropertySymbol.setNamedItem](item);

if (
!this[PropertySymbol.ownerElement][PropertySymbol.dirtyness] &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ export default class HTMLScriptElementNamedNodeMap extends HTMLElementNamedNodeM
/**
* @override
*/
public override setNamedItem(item: Attr): Attr | null {
const replacedItem = super.setNamedItem(item);
public override [PropertySymbol.setNamedItem](item: Attr): Attr | null {
const replacedItem = super[PropertySymbol.setNamedItem](item);

if (
item[PropertySymbol.name] === 'src' &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ export default class HTMLSelectElementNamedNodeMap extends HTMLElementNamedNodeM
/**
* @override
*/
public override setNamedItem(item: Attr): Attr | null {
const replacedItem = super.setNamedItem(item);
public override [PropertySymbol.setNamedItem](item: Attr): Attr | null {
const replacedItem = super[PropertySymbol.setNamedItem](item);

if (
(item[PropertySymbol.name] === 'id' || item[PropertySymbol.name] === 'name') &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ export default class HTMLTextAreaElementNamedNodeMap extends HTMLElementNamedNod
/**
* @override
*/
public override setNamedItem(item: Attr): Attr | null {
const replacedItem = super.setNamedItem(item);
public override [PropertySymbol.setNamedItem](item: Attr): Attr | null {
const replacedItem = super[PropertySymbol.setNamedItem](item);

if (
(item[PropertySymbol.name] === 'id' || item[PropertySymbol.name] === 'name') &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ export default class SVGElementNamedNodeMap extends ElementNamedNodeMap {
/**
* @override
*/
public override setNamedItem(item: Attr): Attr | null {
const replacedItem = super.setNamedItem(item);
public override [PropertySymbol.setNamedItem](item: Attr): Attr | null {
const replacedItem = super[PropertySymbol.setNamedItem](item);

if (
item[PropertySymbol.name] === 'style' &&
Expand Down

0 comments on commit aa67746

Please sign in to comment.