Skip to content

Commit

Permalink
Merge pull request #619 from IGx89/task/618-fix-select-option-issues
Browse files Browse the repository at this point in the history
#618@patch: Fix various issues with <select> and <option>.
  • Loading branch information
capricorn86 committed Oct 14, 2022
2 parents 00abde9 + 5929b01 commit fca8d47
Show file tree
Hide file tree
Showing 12 changed files with 646 additions and 120 deletions.
18 changes: 3 additions & 15 deletions packages/happy-dom/src/nodes/element/Element.ts
Expand Up @@ -365,13 +365,9 @@ export default class Element extends Node implements IElement {
}

/**
* Append a child node to childNodes.
*
* @override
* @param node Node to append.
* @returns Appended node.
*/
public appendChild(node: INode): INode {
public override appendChild(node: INode): INode {
// If the type is DocumentFragment, then the child nodes of if it should be moved instead of the actual node.
// See: https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment
if (node.nodeType !== Node.DOCUMENT_FRAGMENT_NODE) {
Expand All @@ -391,12 +387,9 @@ export default class Element extends Node implements IElement {
}

/**
* Remove Child element from childNodes array.
*
* @override
* @param node Node to remove.
*/
public removeChild(node: INode): INode {
public override removeChild(node: INode): INode {
if (node.nodeType === Node.ELEMENT_NODE) {
const index = this.children.indexOf(<IElement>node);
if (index !== -1) {
Expand All @@ -415,14 +408,9 @@ export default class Element extends Node implements IElement {
}

/**
* Inserts a node before another.
*
* @override
* @param newNode Node to insert.
* @param [referenceNode] Node to insert before.
* @returns Inserted node.
*/
public insertBefore(newNode: INode, referenceNode?: INode): INode {
public override insertBefore(newNode: INode, referenceNode: INode | null): INode {
const returnValue = super.insertBefore(newNode, referenceNode);

// If the type is DocumentFragment, then the child nodes of if it should be moved instead of the actual node.
Expand Down
@@ -1,9 +1,10 @@
import HTMLElement from '../html-element/HTMLElement';
import IHTMLElement from '../html-element/IHTMLElement';
import IHTMLFormElement from '../html-form-element/IHTMLFormElement';
import HTMLOptionElementValueSanitizer from './HTMLOptionElementValueSanitizer';
import IHTMLOptionElement from './IHTMLOptionElement';

const NEW_LINES_REGEXP = /[\n\r]/gm;

/**
* HTML Option Element.
*
Expand Down Expand Up @@ -112,6 +113,6 @@ export default class HTMLOptionElement extends HTMLElement implements IHTMLOptio
* @param value Value.
*/
public set value(value: string) {
this.setAttributeNS(null, 'value', HTMLOptionElementValueSanitizer.sanitize(value));
this.setAttributeNS(null, 'value', String(value).trim().replace(NEW_LINES_REGEXP, ''));
}
}

This file was deleted.

@@ -1,7 +1,9 @@
import DOMException from '../../exception/DOMException';
import HTMLCollection from '../element/HTMLCollection';
import HTMLOptGroupElement from '../html-opt-group-element/HTMLOptGroupElement';
import IHTMLOptGroupElement from '../html-opt-group-element/IHTMLOptGroupElement';
import IHTMLSelectElement from '../html-select-element/IHTMLSelectElement';
import HTMLOptionElement from './HTMLOptionElement';
import IHTMLOptionElement from './IHTMLOptionElement';
import IHTMLOptionsCollection from './IHTMLOptionsCollection';

/**
Expand All @@ -14,15 +16,32 @@ export default class HTMLOptionsCollection
extends HTMLCollection
implements IHTMLOptionsCollection
{
public _selectedIndex: number;
private _selectElement: IHTMLSelectElement;

/**
*
* @param selectElement
*/
constructor(selectElement: IHTMLSelectElement) {
super();

this._selectElement = selectElement;
}

/**
* Returns selectedIndex.
*
* @returns SelectedIndex.
*/
public get selectedIndex(): number {
return this._selectedIndex;
for (let i = 0; i < this.length; i++) {
const item = this[i];
if (item instanceof HTMLOptionElement && item.selected) {
return i;
}
}

return -1;
}

/**
Expand All @@ -31,15 +50,20 @@ export default class HTMLOptionsCollection
* @param selectedIndex SelectedIndex.
*/
public set selectedIndex(selectedIndex: number) {
this._selectedIndex = selectedIndex;
for (let i = 0; i < this.length; i++) {
const item = this[i];
if (item instanceof HTMLOptionElement) {
this[i].selected = i === selectedIndex;
}
}
}

/**
* Returns item by index.
*
* @param index Index.
*/
public item(index: number): HTMLOptionElement | HTMLOptGroupElement {
public item(index: number): IHTMLOptionElement | IHTMLOptGroupElement {
return this[index];
}

Expand All @@ -49,11 +73,11 @@ export default class HTMLOptionsCollection
* @param before
*/
public add(
element: HTMLOptionElement | HTMLOptGroupElement,
before?: number | HTMLOptionElement | HTMLOptGroupElement
element: IHTMLOptionElement | IHTMLOptGroupElement,
before?: number | IHTMLOptionElement | IHTMLOptGroupElement
): void {
if (!before && before !== 0) {
this.push(element);
this._selectElement.appendChild(element);
return;
}

Expand All @@ -62,18 +86,19 @@ export default class HTMLOptionsCollection
return;
}

this.splice(<number>before, 0, element);
this._selectElement.insertBefore(element, this[<number>before]);
return;
}

const idx = this.findIndex((element) => element === before);
if (idx === -1) {
const index = this.indexOf(before);

if (index === -1) {
throw new DOMException(
"Failed to execute 'add' on 'DOMException': The node before which the new node is to be inserted is not a child of this node."
);
}

this.splice(idx, 0, element);
this._selectElement.insertBefore(element, this[index]);
}

/**
Expand All @@ -82,13 +107,8 @@ export default class HTMLOptionsCollection
* @param index Index.
*/
public remove(index: number): void {
this.splice(index, 1);
if (index === this.selectedIndex) {
if (this.length) {
this.selectedIndex = 0;
} else {
this.selectedIndex = -1;
}
if (this[index]) {
this._selectElement.removeChild(<IHTMLOptionElement>this[index]);
}
}
}
Expand Up @@ -24,6 +24,13 @@ export default interface IHTMLOptionsCollection
before?: number | IHTMLOptionElement | IHTMLOptGroupElement
): void;

/**
* Returns option element by index.
*
* @param index Index.
*/
item(index: number): IHTMLOptionElement | IHTMLOptGroupElement;

/**
* Removes option element from the collection.
*
Expand Down

0 comments on commit fca8d47

Please sign in to comment.