Skip to content

Commit

Permalink
#517@minor: Implement dialog element.
Browse files Browse the repository at this point in the history
  • Loading branch information
markgaze committed Jun 30, 2022
1 parent 57a8d33 commit e69a953
Show file tree
Hide file tree
Showing 7 changed files with 188 additions and 2 deletions.
3 changes: 2 additions & 1 deletion packages/happy-dom/src/config/ElementTag.ts
Expand Up @@ -16,6 +16,7 @@ import HTMLBaseElement from '../nodes/html-base-element/HTMLBaseElement';
import HTMLSelectElement from '../nodes/html-select-element/HTMLSelectElement';
import HTMLOptionElement from '../nodes/html-option-element/HTMLOptionElement';
import HTMLOptGroupElement from '../nodes/html-opt-group-element/HTMLOptGroupElement';
import HTMLDialogElement from '../nodes/html-dialog-element/HTMLDialogElement';

export default {
A: HTMLElement,
Expand Down Expand Up @@ -67,7 +68,7 @@ export default {
DEL: HTMLElement,
DETAILS: HTMLElement,
DFN: HTMLElement,
DIALOG: HTMLElement,
DIALOG: HTMLDialogElement,
DIV: HTMLElement,
DL: HTMLElement,
DT: HTMLElement,
Expand Down
6 changes: 5 additions & 1 deletion packages/happy-dom/src/index.ts
Expand Up @@ -104,6 +104,8 @@ import Storage from './storage/Storage';
import DOMRect from './nodes/element/DOMRect';
import { URLSearchParams } from 'url';
import Selection from './selection/Selection';
import HTMLDialogElement from './nodes/html-dialog-element/HTMLDialogElement';
import IHTMLDialogElement from './nodes/html-dialog-element/IHTMLDialogElement';

export {
GlobalWindow,
Expand Down Expand Up @@ -211,5 +213,7 @@ export {
Storage,
DOMRect,
URLSearchParams,
Selection
Selection,
HTMLDialogElement,
IHTMLDialogElement
};
@@ -0,0 +1,52 @@
import Event from '../../event/Event';
import HTMLElement from '../html-element/HTMLElement';
import IHTMLDialogElement from './IHTMLDialogElement';

/**
* HTML Dialog Element.
*
* Reference:
* https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement.
*/
export default class HTMLDialogElement extends HTMLElement implements IHTMLDialogElement {
/**
* Returns returnValue.
*
* @returns ReturnValue.
*/
public returnValue: string;

/**
* Returns open.
*
* @returns Open.
*/
public get open(): boolean {
return this.hasAttributeNS(null, 'open');
}

/**
* Closes the dialog.
*
* @param returnValue ReturnValue.
*/
public close(returnValue?: string): void {
this.removeAttributeNS(null, 'open');
this.returnValue = returnValue;
this.dispatchEvent(new Event('close', { bubbles: false, cancelable: false }));
}

/**
* Shows the modal.
*/
public showModal(): void {
this.setAttributeNS(null, 'open', '');
}

/**
* Shows the dialog.
*/
public show(): void {
this.setAttributeNS(null, 'open', '');
}
}
@@ -0,0 +1,15 @@
import IHTMLElement from '../html-element/IHTMLElement';

/**
* HTML Dialog Element.
*
* Reference:
* https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement.
*/
export default interface IHTMLDialogElement extends IHTMLElement {
open: boolean;
returnValue: string;
close(returnValue?: string): void;
showModal(): void;
show(): void;
}
2 changes: 2 additions & 0 deletions packages/happy-dom/src/window/IWindow.ts
Expand Up @@ -24,6 +24,7 @@ import HTMLBaseElement from '../nodes/html-base-element/HTMLBaseElement';
import SVGSVGElement from '../nodes/svg-element/SVGSVGElement';
import SVGElement from '../nodes/svg-element/SVGElement';
import HTMLScriptElement from '../nodes/html-script-element/HTMLScriptElement';
import HTMLDialogElement from '../nodes/html-dialog-element/HTMLDialogElement';
import HTMLImageElement from '../nodes/html-image-element/HTMLImageElement';
import Image from '../nodes/html-image-element/Image';
import DocumentFragment from '../nodes/document-fragment/DocumentFragment';
Expand Down Expand Up @@ -112,6 +113,7 @@ export default interface IWindow extends IEventTarget, NodeJS.Global {
readonly HTMLLabelElement: typeof HTMLLabelElement;
readonly HTMLMetaElement: typeof HTMLMetaElement;
readonly HTMLBaseElement: typeof HTMLBaseElement;
readonly HTMLDialogElement: typeof HTMLDialogElement;
readonly SVGSVGElement: typeof SVGSVGElement;
readonly SVGElement: typeof SVGElement;
readonly Image: typeof Image;
Expand Down
2 changes: 2 additions & 0 deletions packages/happy-dom/src/window/Window.ts
Expand Up @@ -21,6 +21,7 @@ import HTMLSlotElement from '../nodes/html-slot-element/HTMLSlotElement';
import HTMLLabelElement from '../nodes/html-label-element/HTMLLabelElement';
import HTMLMetaElement from '../nodes/html-meta-element/HTMLMetaElement';
import HTMLBaseElement from '../nodes/html-base-element/HTMLBaseElement';
import HTMLDialogElement from '../nodes/html-dialog-element/HTMLDialogElement';
import SVGSVGElement from '../nodes/svg-element/SVGSVGElement';
import SVGElement from '../nodes/svg-element/SVGElement';
import HTMLScriptElement from '../nodes/html-script-element/HTMLScriptElement';
Expand Down Expand Up @@ -129,6 +130,7 @@ export default class Window extends EventTarget implements IWindow {
public readonly HTMLSlotElement = HTMLSlotElement;
public readonly HTMLMetaElement = HTMLMetaElement;
public readonly HTMLBaseElement = HTMLBaseElement;
public readonly HTMLDialogElement = HTMLDialogElement;
public readonly SVGSVGElement = SVGSVGElement;
public readonly SVGElement = SVGElement;
public readonly Text = Text;
Expand Down
@@ -0,0 +1,110 @@
import { Event } from 'src';
import Document from '../../../src/nodes/document/Document';
import HTMLDialogElement from '../../../src/nodes/html-dialog-element/HTMLDialogElement';
import Window from '../../../src/window/Window';

describe('HTMLDialogElement', () => {
let window: Window;
let document: Document;
let element: HTMLDialogElement;

beforeEach(() => {
window = new Window();
document = window.document;
element = <HTMLDialogElement>document.createElement('dialog');
});

describe('open', () => {
it('Should be closed by default', () => {
expect(element.open).toBe(false);
});

it('Should be open when show has been called', () => {
element.show();
expect(element.open).toBe(true);
});

it('Should be open when showModal has been called', () => {
element.showModal();
expect(element.open).toBe(true);
});
});

describe('returnValue', () => {
it('Should be undefined by default', () => {
expect(element.returnValue).toBe(undefined);
});

it('Should be set when close has been called with a return value', () => {
element.close('foo');
expect(element.returnValue).toBe('foo');
});

it('Should be possible to set manually', () => {
element.returnValue = 'foo';
expect(element.returnValue).toBe('foo');
});
});

describe('close', () => {
it('Should be possible to close an open dialog', () => {
element.show();
element.close();
expect(element.open).toBe(false);
expect(element.getAttributeNS(null, 'open')).toBe(null);
});

it('Should be possible to close an open modal dialog', () => {
element.showModal();
element.close();
expect(element.open).toBe(false);
expect(element.getAttributeNS(null, 'open')).toBe(null);
});

it('Should be possible to close the dialog with a return value', () => {
element.show();
element.close('foo');
expect(element.returnValue).toBe('foo');
});

it('Should be possible to close the modal dialog with a return value', () => {
element.showModal();
element.close('foo');
expect(element.returnValue).toBe('foo');
});

it('Should dispatch a close event', () => {
let dispatched: Event = null;
element.addEventListener('close', (event: Event) => (dispatched = event));
element.show();
element.close();
expect(dispatched.cancelable).toBe(false);
expect(dispatched.bubbles).toBe(false);
});

it('Should dispatch a close event when closing a modal', () => {
let dispatched: Event = null;
element.addEventListener('close', (event: Event) => (dispatched = event));
element.showModal();
element.close();
expect(dispatched.cancelable).toBe(false);
expect(dispatched.bubbles).toBe(false);
});
});

describe('showModal', () => {
it('Should be possible to show a modal dialog', () => {
element.showModal();
expect(element.open).toBe(true);
expect(element.getAttributeNS(null, 'open')).toBe('');
});
});

describe('show', () => {
it('Should be possible to show a dialog', () => {
element.show();
expect(element.open).toBe(true);
expect(element.getAttributeNS(null, 'open')).toBe('');
});
});
});

0 comments on commit e69a953

Please sign in to comment.