81 lines
1.8 KiB
JavaScript
81 lines
1.8 KiB
JavaScript
/**
|
|
* @module types
|
|
*/
|
|
|
|
import { YXmlElement, YXmlFragment } from './YXmlElement.mjs' // eslint-disable-line
|
|
|
|
/**
|
|
* Define the elements to which a set of CSS queries apply.
|
|
* {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors|CSS_Selectors}
|
|
*
|
|
* @example
|
|
* query = '.classSelector'
|
|
* query = 'nodeSelector'
|
|
* query = '#idSelector'
|
|
*
|
|
* @typedef {string} CSS_Selector
|
|
*/
|
|
|
|
/**
|
|
* Represents a subset of the nodes of a YXmlElement / YXmlFragment and a
|
|
* position within them.
|
|
*
|
|
* Can be created with {@link YXmlFragment#createTreeWalker}
|
|
*
|
|
* @public
|
|
*/
|
|
export class YXmlTreeWalker {
|
|
constructor (root, f) {
|
|
this._filter = f || (() => true)
|
|
this._root = root
|
|
this._currentNode = root
|
|
this._firstCall = true
|
|
}
|
|
[Symbol.iterator] () {
|
|
return this
|
|
}
|
|
/**
|
|
* Get the next node.
|
|
*
|
|
* @return {YXmlElement} The next node.
|
|
*
|
|
* @public
|
|
*/
|
|
next () {
|
|
let n = this._currentNode
|
|
if (this._firstCall) {
|
|
this._firstCall = false
|
|
if (!n._deleted && this._filter(n)) {
|
|
return { value: n, done: false }
|
|
}
|
|
}
|
|
do {
|
|
if (!n._deleted && (n.constructor === YXmlElement || n.constructor === YXmlFragment) && n._start !== null) {
|
|
// walk down in the tree
|
|
n = n._start
|
|
} else {
|
|
// walk right or up in the tree
|
|
while (n !== this._root) {
|
|
if (n._right !== null) {
|
|
n = n._right
|
|
break
|
|
}
|
|
n = n._parent
|
|
}
|
|
if (n === this._root) {
|
|
n = null
|
|
}
|
|
}
|
|
if (n === this._root) {
|
|
break
|
|
}
|
|
} while (n !== null && (n._deleted || !this._filter(n)))
|
|
this._currentNode = n
|
|
if (n === null) {
|
|
return { done: true }
|
|
} else {
|
|
return { value: n, done: false }
|
|
}
|
|
}
|
|
}
|