Comparing version 0.1.15 to 0.1.16
@@ -14,2 +14,5 @@ 'use strict'; | ||
const {Text} = require('./text.js'); | ||
const {Range} = require('./range.js'); | ||
const {HTMLElement} = require('./html-element.js'); | ||
const {HTMLTemplateElement} = require('./html-template-element.js'); | ||
@@ -29,3 +32,3 @@ /** | ||
/** | ||
* @type {HTMLElement?} | ||
* @type {Element?} | ||
*/ | ||
@@ -106,5 +109,18 @@ this.root = null; | ||
createElement(localName, options = {}) { | ||
const element = new Element(this, localName); | ||
if (options.is) | ||
element.setAttribute('is', options.is); | ||
let element; | ||
if (this._mime.ignoreCase) { | ||
switch (localName) { | ||
case 'template': | ||
case 'TEMPLATE': | ||
element = new HTMLTemplateElement(this); | ||
break; | ||
default: | ||
element = new HTMLElement(localName, this); | ||
break; | ||
} | ||
if (options.is) | ||
element.setAttribute('is', options.is); | ||
} | ||
else | ||
element = new Element(this, localName); | ||
return element; | ||
@@ -114,3 +130,3 @@ } | ||
/** | ||
* @param {string} textContent | ||
* @param {string} textContent | ||
*/ | ||
@@ -132,2 +148,6 @@ createComment(textContent) { | ||
createRange() { | ||
return new Range; | ||
} | ||
toString() { | ||
@@ -134,0 +154,0 @@ return this._mime.docType + (this.root || '').toString(); |
@@ -78,2 +78,22 @@ 'use strict'; | ||
/** | ||
* @type {string} | ||
*/ | ||
get textContent() { | ||
const text = []; | ||
let {_next, _end} = this; | ||
while (_next !== _end) { | ||
if (_next.nodeType === TEXT_NODE) | ||
text.push(_next.textContent); | ||
_next = _next._next; | ||
} | ||
return text.join(''); | ||
} | ||
set textContent(text) { | ||
this.replaceChildren(); | ||
if (text) | ||
this.appendChild(this.ownerDocument.createTextNode(text)); | ||
} | ||
get innerHTML() { | ||
@@ -140,2 +160,9 @@ return this.childNodes.join(''); | ||
closest(selectors) { | ||
let parentElement = this; | ||
while (parentElement && !parentElement.matches(selectors)) | ||
parentElement = parentElement.parentElement; | ||
return parentElement; | ||
} | ||
/** | ||
@@ -142,0 +169,0 @@ * @param {string} name |
@@ -5,2 +5,3 @@ 'use strict'; | ||
})(require('./dom-parser.js')); | ||
(m => { | ||
@@ -15,3 +16,8 @@ exports.HTMLDocument = m.HTMLDocument; | ||
})(require('./xml-document.js')); | ||
(m => { | ||
exports.HTMLElement = m.HTMLElement; | ||
})(require('./html-element.js')); | ||
(m => { | ||
exports.CustomEvent = m.CustomEvent; | ||
@@ -18,0 +24,0 @@ exports.Event = m.Event; |
@@ -11,3 +11,3 @@ 'use strict'; | ||
const {findNext, getEnd} = require('./utils.js'); | ||
const {findNext, getEnd, invalidate} = require('./utils.js'); | ||
@@ -61,3 +61,3 @@ const asFragment = (ownerDocument, nodes) => { | ||
remove(node) { | ||
let {_prev, _next, nodeType} = node; | ||
let {_prev, _next, nodeType, parentNode} = node; | ||
let _end = node; | ||
@@ -71,2 +71,4 @@ if (nodeType === ELEMENT_NODE) { | ||
node.parentNode = node._prev = _end._next = null; | ||
if (parentNode) | ||
invalidate(parentNode); | ||
} | ||
@@ -141,2 +143,3 @@ }; | ||
const append = (element, nodes) => { | ||
invalidate(element); | ||
const {ownerDocument, _end} = element; | ||
@@ -205,2 +208,3 @@ for (const node of nodes) | ||
prepend(element, nodes) { | ||
invalidate(element); | ||
const {ownerDocument, firstChild} = element; | ||
@@ -221,2 +225,3 @@ for (const node of nodes) | ||
replaceChildren(element, nodes) { | ||
invalidate(element); | ||
let {_next, _end} = element; | ||
@@ -223,0 +228,0 @@ while (_next !== _end) { |
@@ -20,3 +20,4 @@ 'use strict'; | ||
getBoundaries, | ||
getEnd | ||
getEnd, | ||
invalidate | ||
} = require('./utils.js'); | ||
@@ -232,2 +233,12 @@ | ||
const getChildNodes = element => { | ||
const childNodes = new NodeList; | ||
let {_next, _end} = findNext(element); | ||
while (_next !== _end) { | ||
childNodes.push(_next); | ||
_next = getEnd(_next)._next; | ||
} | ||
return childNodes; | ||
}; | ||
class NodeElement extends Node { | ||
@@ -237,4 +248,3 @@ | ||
super(ownerDocument, localName, nodeType); | ||
this._childNodes = null; | ||
this._children = null; | ||
invalidate(this); | ||
} | ||
@@ -314,11 +324,3 @@ | ||
get childNodes() { | ||
if (this._childNodes) | ||
return this._childNodes; | ||
const childNodes = new NodeList; | ||
let {_next, _end} = findNext(this); | ||
while (_next !== _end) { | ||
childNodes.push(_next); | ||
_next = getEnd(_next)._next; | ||
} | ||
return (this._childNodes = childNodes); | ||
return this._childNodes || (this._childNodes = getChildNodes(this)); | ||
} | ||
@@ -347,3 +349,3 @@ | ||
appendChild(node) { | ||
this._childNodes = this._children = null; | ||
invalidate(this); | ||
return this.insertBefore(node, this._end); | ||
@@ -358,3 +360,3 @@ } | ||
insertBefore(node, before) { | ||
this._childNodes = this._children = null; | ||
invalidate(this); | ||
const _end = before || this._end; | ||
@@ -373,2 +375,3 @@ const {_prev} = _end; | ||
case DOCUMENT_FRAGMENT_NODE: { | ||
invalidate(node); | ||
let {firstChild, lastChild} = node; | ||
@@ -407,3 +410,3 @@ if (firstChild) { | ||
normalize() { | ||
this._childNodes = this._children = null; | ||
let invalidated = false; | ||
let {_next, _end} = this; | ||
@@ -413,5 +416,8 @@ while (_next !== _end) { | ||
if (nodeType === TEXT_NODE) { | ||
if (!_next.textContent) | ||
if (!_next.textContent) { | ||
invalidated = true; | ||
_next.remove(); | ||
} | ||
else if (_prev && _prev.nodeType === TEXT_NODE) { | ||
invalidated = true; | ||
_prev.textContent += _next.textContent; | ||
@@ -423,2 +429,4 @@ _next.remove(); | ||
} | ||
if (invalidated) | ||
invalidate(this); | ||
} | ||
@@ -431,5 +439,5 @@ | ||
removeChild(node) { | ||
this._childNodes = this._children = null; | ||
if (node.parentNode !== this) | ||
throw new Error('node is not a child'); | ||
invalidate(this); | ||
node.remove(); | ||
@@ -445,4 +453,4 @@ return node; | ||
replaceChild(node, replaced) { | ||
this._childNodes = this._children = null; | ||
const {_prev, _next} = getBoundaries(replaced); | ||
invalidate(this); | ||
replaced.remove(); | ||
@@ -449,0 +457,0 @@ node.remove(); |
@@ -59,2 +59,10 @@ 'use strict'; | ||
const ignoreCase = ({ownerDocument}) => ownerDocument._mime.ignoreCase; | ||
exports.ignoreCase = ignoreCase; | ||
const invalidate = element => { | ||
element._childNodes = element._children = null; | ||
}; | ||
exports.invalidate = invalidate; | ||
const isVoidElement = ({localName, ownerDocument}) => { | ||
@@ -65,5 +73,2 @@ return ownerDocument._mime.voidElements.test(localName); | ||
const ignoreCase = ({ownerDocument}) => ownerDocument._mime.ignoreCase; | ||
exports.ignoreCase = ignoreCase; | ||
const localCase = ({localName, ownerDocument}) => { | ||
@@ -70,0 +75,0 @@ return ownerDocument._mime.ignoreCase ? localName.toUpperCase() : localName; |
@@ -13,2 +13,5 @@ import {DOCUMENT_NODE} from './constants.js'; | ||
import {Text} from './text.js'; | ||
import {Range} from './range.js'; | ||
import {HTMLElement} from './html-element.js'; | ||
import {HTMLTemplateElement} from './html-template-element.js'; | ||
@@ -28,3 +31,3 @@ /** | ||
/** | ||
* @type {HTMLElement?} | ||
* @type {Element?} | ||
*/ | ||
@@ -105,5 +108,18 @@ this.root = null; | ||
createElement(localName, options = {}) { | ||
const element = new Element(this, localName); | ||
if (options.is) | ||
element.setAttribute('is', options.is); | ||
let element; | ||
if (this._mime.ignoreCase) { | ||
switch (localName) { | ||
case 'template': | ||
case 'TEMPLATE': | ||
element = new HTMLTemplateElement(this); | ||
break; | ||
default: | ||
element = new HTMLElement(localName, this); | ||
break; | ||
} | ||
if (options.is) | ||
element.setAttribute('is', options.is); | ||
} | ||
else | ||
element = new Element(this, localName); | ||
return element; | ||
@@ -113,3 +129,3 @@ } | ||
/** | ||
* @param {string} textContent | ||
* @param {string} textContent | ||
*/ | ||
@@ -131,2 +147,6 @@ createComment(textContent) { | ||
createRange() { | ||
return new Range; | ||
} | ||
toString() { | ||
@@ -133,0 +153,0 @@ return this._mime.docType + (this.root || '').toString(); |
@@ -77,2 +77,22 @@ import {ELEMENT_NODE, ELEMENT_NODE_END, ATTRIBUTE_NODE, TEXT_NODE, COMMENT_NODE} from './constants.js'; | ||
/** | ||
* @type {string} | ||
*/ | ||
get textContent() { | ||
const text = []; | ||
let {_next, _end} = this; | ||
while (_next !== _end) { | ||
if (_next.nodeType === TEXT_NODE) | ||
text.push(_next.textContent); | ||
_next = _next._next; | ||
} | ||
return text.join(''); | ||
} | ||
set textContent(text) { | ||
this.replaceChildren(); | ||
if (text) | ||
this.appendChild(this.ownerDocument.createTextNode(text)); | ||
} | ||
get innerHTML() { | ||
@@ -139,2 +159,9 @@ return this.childNodes.join(''); | ||
closest(selectors) { | ||
let parentElement = this; | ||
while (parentElement && !parentElement.matches(selectors)) | ||
parentElement = parentElement.parentElement; | ||
return parentElement; | ||
} | ||
/** | ||
@@ -141,0 +168,0 @@ * @param {string} name |
export {DOMParser} from './dom-parser.js'; | ||
export {HTMLDocument} from './html-document.js'; | ||
export {SVGDocument} from './svg-document.js'; | ||
export {XMLDocument} from './xml-document.js'; | ||
export {HTMLElement} from './html-element.js'; | ||
export { | ||
@@ -6,0 +10,0 @@ CustomEvent, |
@@ -10,3 +10,3 @@ import { | ||
import {findNext, getEnd} from './utils.js'; | ||
import {findNext, getEnd, invalidate} from './utils.js'; | ||
@@ -60,3 +60,3 @@ const asFragment = (ownerDocument, nodes) => { | ||
remove(node) { | ||
let {_prev, _next, nodeType} = node; | ||
let {_prev, _next, nodeType, parentNode} = node; | ||
let _end = node; | ||
@@ -70,2 +70,4 @@ if (nodeType === ELEMENT_NODE) { | ||
node.parentNode = node._prev = _end._next = null; | ||
if (parentNode) | ||
invalidate(parentNode); | ||
} | ||
@@ -137,2 +139,3 @@ }; | ||
const append = (element, nodes) => { | ||
invalidate(element); | ||
const {ownerDocument, _end} = element; | ||
@@ -201,2 +204,3 @@ for (const node of nodes) | ||
prepend(element, nodes) { | ||
invalidate(element); | ||
const {ownerDocument, firstChild} = element; | ||
@@ -217,2 +221,3 @@ for (const node of nodes) | ||
replaceChildren(element, nodes) { | ||
invalidate(element); | ||
let {_next, _end} = element; | ||
@@ -219,0 +224,0 @@ while (_next !== _end) { |
@@ -19,3 +19,4 @@ import { | ||
getBoundaries, | ||
getEnd | ||
getEnd, | ||
invalidate | ||
} from './utils.js'; | ||
@@ -230,2 +231,12 @@ | ||
const getChildNodes = element => { | ||
const childNodes = new NodeList; | ||
let {_next, _end} = findNext(element); | ||
while (_next !== _end) { | ||
childNodes.push(_next); | ||
_next = getEnd(_next)._next; | ||
} | ||
return childNodes; | ||
}; | ||
export class NodeElement extends Node { | ||
@@ -235,4 +246,3 @@ | ||
super(ownerDocument, localName, nodeType); | ||
this._childNodes = null; | ||
this._children = null; | ||
invalidate(this); | ||
} | ||
@@ -312,11 +322,3 @@ | ||
get childNodes() { | ||
if (this._childNodes) | ||
return this._childNodes; | ||
const childNodes = new NodeList; | ||
let {_next, _end} = findNext(this); | ||
while (_next !== _end) { | ||
childNodes.push(_next); | ||
_next = getEnd(_next)._next; | ||
} | ||
return (this._childNodes = childNodes); | ||
return this._childNodes || (this._childNodes = getChildNodes(this)); | ||
} | ||
@@ -345,3 +347,3 @@ | ||
appendChild(node) { | ||
this._childNodes = this._children = null; | ||
invalidate(this); | ||
return this.insertBefore(node, this._end); | ||
@@ -356,3 +358,3 @@ } | ||
insertBefore(node, before) { | ||
this._childNodes = this._children = null; | ||
invalidate(this); | ||
const _end = before || this._end; | ||
@@ -371,2 +373,3 @@ const {_prev} = _end; | ||
case DOCUMENT_FRAGMENT_NODE: { | ||
invalidate(node); | ||
let {firstChild, lastChild} = node; | ||
@@ -405,3 +408,3 @@ if (firstChild) { | ||
normalize() { | ||
this._childNodes = this._children = null; | ||
let invalidated = false; | ||
let {_next, _end} = this; | ||
@@ -411,5 +414,8 @@ while (_next !== _end) { | ||
if (nodeType === TEXT_NODE) { | ||
if (!_next.textContent) | ||
if (!_next.textContent) { | ||
invalidated = true; | ||
_next.remove(); | ||
} | ||
else if (_prev && _prev.nodeType === TEXT_NODE) { | ||
invalidated = true; | ||
_prev.textContent += _next.textContent; | ||
@@ -421,2 +427,4 @@ _next.remove(); | ||
} | ||
if (invalidated) | ||
invalidate(this); | ||
} | ||
@@ -429,5 +437,5 @@ | ||
removeChild(node) { | ||
this._childNodes = this._children = null; | ||
if (node.parentNode !== this) | ||
throw new Error('node is not a child'); | ||
invalidate(this); | ||
node.remove(); | ||
@@ -443,4 +451,4 @@ return node; | ||
replaceChild(node, replaced) { | ||
this._childNodes = this._children = null; | ||
const {_prev, _next} = getBoundaries(replaced); | ||
invalidate(this); | ||
replaced.remove(); | ||
@@ -447,0 +455,0 @@ node.remove(); |
@@ -54,2 +54,8 @@ import {Parser} from 'htmlparser2'; | ||
export const ignoreCase = ({ownerDocument}) => ownerDocument._mime.ignoreCase; | ||
export const invalidate = element => { | ||
element._childNodes = element._children = null; | ||
}; | ||
export const isVoidElement = ({localName, ownerDocument}) => { | ||
@@ -59,4 +65,2 @@ return ownerDocument._mime.voidElements.test(localName); | ||
export const ignoreCase = ({ownerDocument}) => ownerDocument._mime.ignoreCase; | ||
export const localCase = ({localName, ownerDocument}) => { | ||
@@ -63,0 +67,0 @@ return ownerDocument._mime.ignoreCase ? localName.toUpperCase() : localName; |
{ | ||
"name": "linkedom", | ||
"version": "0.1.15", | ||
"version": "0.1.16", | ||
"description": "A triple-linked lists based DOM", | ||
@@ -5,0 +5,0 @@ "main": "./cjs/index.js", |
1500600
54
3768