Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#517@minor: Implement dialog element. #518

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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('');
});
});
});