Skip to content

Commit

Permalink
Merge pull request capricorn86#619 from IGx89/task/618-fix-select-opt…
Browse files Browse the repository at this point in the history
…ion-issues

capricorn86#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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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.

Original file line number Diff line number Diff line change
@@ -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]);
}
}
}
Original file line number Diff line number Diff line change
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.