src/HTMLElement/elements/HTMLTableElement.js
import HTMLElement from '../../HTMLElement';
import DOMException from '../../DOMException';
/**
* <table> element.
*
* @see https://developer.mozilla.org/en/docs/Web/API/HTMLTableElement
*/
export default class HTMLTableElement extends HTMLElement {
/**
* Is an {@link HTMLTableCaptionElement} representing the first <caption> that is a child of the element,
* or null if none is found.
* When set, if the object doesn't represent a <caption>,
* a {@link DOMException} with the HierarchyRequestError name is thrown.
* If a correct object is given, it is inserted in the tree as the first child of this element
* and the first <caption> that is a child of this element is removed from the tree, if any.
*
* @type {HTMLTableCaptionElement|null}
*/
get caption() {
return this._childNodeFind(child => child.tagName === 'caption');
}
/**
* @param {HTMLTableCaptionElement|null} element
* @ignore
*/
set caption(element) {
if (element.tagName !== 'caption') {
throw new DOMException('HierarchyRequestError');
}
let previousCaption = this.caption;
if (previousCaption) {
this.removeChild(previousCaption);
}
if (this.firstChild) {
this.insertBefore(element, this.firstChild);
} else {
this.appendChild(element);
}
}
/**
* Is an {@link HTMLTableSectionElement} representing the first <thead> that is a child of the element,
* or null if none is found.
* When set, if the object doesn't represent a <thead>,
* a {@link DOMException} with the HierarchyRequestError name is thrown.
* If a correct object is given, it is inserted in the tree immediately before the first element
* that is neither a <caption>, nor a <colgroup>, or as the last child if there is no such element,
* and the first <thead> that is a child of this element is removed from the tree, if any.
*
* @type {HTMLTableSectionElement|null}
*/
get tHead() {
return this._childNodeFind(child => child.tagName === 'thead');
}
/**
* @ignore
* @param {HTMLTableSectionElement|null} element
*/
set tHead(element) {
if (element.tagName !== 'thead') {
throw new DOMException('HierarchyRequestError');
}
const previousTHead = this.tHead;
if (previousTHead) {
this.removeChild(previousTHead);
}
if (!this.children.some((child) => {
if (child.tagName !== 'caption' && child.tagName !== 'colgroup') {
this.insertBefore(element, child);
return true;
}
return false;
})) {
this.appendChild(element);
}
}
/**
* Is an {@link HTMLTableSectionElement} representing the first <tfoot> that is a child of the element,
* or null if none is found.
* When set, if the object doesn't represent a <tfoot>,
* a {@link DOMException} with the HierarchyRequestError name is thrown.
* If a correct object is given, it is inserted in the tree immediately before the first element
* that is neither a <caption>, a <colgroup>, nor a <thead>, or as the last child
* if there is no such element, and the first <tfoot> that is a child of this element is removed
* from the tree, if any.
*
* @type {HTMLElement|null}
*/
get tFoot() {
return this._childNodeFind(child => child.tagName === 'tfoot');
}
/**
* @ignore
* @param {HTMLElement|null} element
*/
set tFoot(element) {
if (element.tagName !== 'tfoot') {
throw new DOMException('HierarchyRequestError');
}
const previousTFoot = this.tFoot;
if (previousTFoot) {
this.removeChild(previousTFoot);
}
if (!this.children.some((child) => {
if (child.tagName !== 'caption' && child.tagName !== 'colgroup' && child.tagName !== 'thead') {
this.insertBefore(element, child);
return true;
}
return false;
})) {
this.appendChild(element);
}
}
/**
* Returns a live {@link HTMLCollection} containing all the rows of the element,
* that is all <tr> that are a child of the element,
* or a child or one of its <thead>, <tbody> and <tfoot> children.
* The rows members of a <thead> appear first, in tree order, and those members of a <tbody> last,
* also in tree order. The HTMLCollection is live and is automatically updated when the HTMLTableElement changes.
*
* @type {HTMLElement[]}
* @readonly
*/
get rows() {
const result = [];
if (this.tHead !== null) {
this.tHead.children.forEach((element) => {
if (element.tagName === 'tr') {
result.push(element);
}
});
}
const tBodies = this.tBodies;
if (tBodies.length !== 0) {
tBodies.forEach((body) => {
body.children.forEach((element) => {
if (element.tagName === 'tr') {
result.push(element);
}
});
});
}
if (this.tFoot !== null) {
this.tFoot.children.forEach((element) => {
if (element.tagName === 'tr') {
result.push(element);
}
});
}
return result;
}
/**
* Returns a live HTMLCollection containing all the <tbody> of the element. The HTMLCollection is live
* and is automatically updated when the HTMLTableElement changes.
*
* @type {HTMLElement[]}
* @readonly
*/
get tBodies() {
return this.children.filter(element => element.tagName === 'tbody');
}
/**
* Returns an HTMLElement representing the first <thead> that is a child of the element.
* If none is found, a new one is created and inserted in the tree immediately before the first element
* that is neither a <caption>, nor a <colgroup>, or as the last child if there is no such element.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableElement/createTHead
* @return {HTMLElement}
*/
createTHead() {
let tHead = this.tHead;
if (tHead !== null) {
return tHead;
}
tHead = this.ownerDocument.createElement('thead');
this.tHead = tHead;
return tHead;
}
/**
* Removes the first <thead> that is a child of the element.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableElement/deleteTHead
*/
deleteTHead() {
let tHead = this.tHead;
if (tHead !== null) {
this.removeChild(tHead);
}
}
/**
* Returns an {@link HTMLElement} representing the first <tfoot> that is a child of the element.
* If none is found, a new one is created and inserted in the tree immediately before the first element
* that is neither a <caption>, a <colgroup>, nor a <thead>, or as the last child
* if there is no such element.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableElement/createTFoot
* @return {HTMLElement}
*/
createTFoot() {
let tFoot = this.tFoot;
if (tFoot !== null) {
return tFoot;
}
tFoot = this.ownerDocument.createElement('tfoot');
this.tFoot = tFoot;
return tFoot;
}
/**
* Removes the first <tfoot> that is a child of the element.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableElement/deleteTFoot
*/
deleteTFoot() {
let tFoot = this.tFoot;
if (tFoot !== null) {
this.removeChild(tFoot);
}
}
/**
* Returns an {@link HTMLElement} representing the first <caption> that is a child of the element.
* If none is found, a new one is created and inserted in the tree as the first child of the <table> element.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableElement/createCaption
* @return {HTMLElement}
*/
createCaption() {
let caption = this.caption;
if (caption !== null) {
return caption;
}
caption = this.ownerDocument.createElement('caption');
this.caption = caption;
return caption;
}
/**
* Removes the first <caption> that is a child of the element.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableElement/deleteCaption
*/
deleteCaption() {
let caption = this.caption;
if (caption !== null) {
this.removeChild(caption);
}
}
/**
* Method creates <tbody> element and puts it in particular place
*
* @private
*/
_createTBody() {
let tBody = this.ownerDocument.createElement('tbody');
let tFoot = this.tFoot;
if (tFoot) {
this.insertBefore(tBody, tFoot);
} else {
this.appendChild(tBody);
}
return tBody;
}
/**
* Returns an {@link HTMLElement} representing a new row of the table. It inserts it in the rows collection
* immediately before the <tr> element at the given index position. If necessary a <tbody> is created.
* If the index is -1, the new row is appended to the collection. If the index is smaller than -1 or greater than
* the number of rows in the collection, a {@link DOMException} with the value IndexSizeError is raised.
*
* @param {number} [index=-1]
* @return {HTMLElement}
*/
insertRow(index = -1) {
let row = this.ownerDocument.createElement('tr');
let tBody = null;
let tBodies = this.tBodies;
if (tBodies.length === 0) {
tBody = this._createTBody();
} else {
tBody = tBodies[tBodies.length - 1];
}
if (index === -1 || index === tBody.length) {
tBody.appendChild(row);
} else if (index < tBody.length - 1) {
tBody.insertBefore(row, tBody.children[index]);
} else {
throw new DOMException('IndexSizeError');
}
return row;
}
/**
* @inheritdoc
*/
appendChild(element) {
if (element.tagName === 'tr') {
let tBodies = this.tBodies;
let tBody = null;
if (tBodies.length === 0) {
tBody = this._createTBody();
} else {
tBody = tBodies[tBodies.length - 1];
}
return tBody.appendChild(element);
}
return super.appendChild(element);
}
}
/**
* @constant {string} HTMLTableElement#nodeName table
*/
Object.defineProperty(HTMLTableElement.prototype, 'nodeName', { value: 'table' });