diff --git a/src/types/YXmlFragment.js b/src/types/YXmlFragment.js index 16ee66cc..a00df815 100644 --- a/src/types/YXmlFragment.js +++ b/src/types/YXmlFragment.js @@ -195,6 +195,41 @@ export class YXmlFragment extends AbstractType { * @public */ querySelector (query) { + const iterator = new YXmlTreeWalker(this, this._walkFilter(query)) + const next = iterator.next() + + if (next.done) { + return null + } else { + return next.value + } + } + + /** + * Returns all YXmlElements that match the query. + * Similar to Dom's {@link querySelectorAll}. + * + * Query support: + * - tagname + * - id + * - attributes + * + * @param {CSS_Selector|Filters} query The query on the children. + * @return {Array} The elements that match this query. + * + * @public + */ + querySelectorAll (query) { + return Array.from(new YXmlTreeWalker(this, this._walkFilter(query))) + } + + /** + * Creates filter function to run against children when walking tree. + * + * @param {CSS_Selector|Filters} query The query on the children. + * @return {function(AbstractType):boolean} + */ + _walkFilter (query) { /** * @type {Filters} */ @@ -211,7 +246,7 @@ export class YXmlFragment extends AbstractType { filters.tagname = filters.tagname.toUpperCase() } - const iterator = new YXmlTreeWalker(this, element => { + return element => { // @ts-ignore if (filters.tagname && element.nodeName && element.nodeName.toUpperCase() === filters.tagname) { return true @@ -239,32 +274,9 @@ export class YXmlFragment extends AbstractType { } return false - }) - const next = iterator.next() - if (next.done) { - return null - } else { - return next.value } } - /** - * Returns all YXmlElements that match the query. - * Similar to Dom's {@link querySelectorAll}. - * - * @todo Does not yet support all queries. Currently only query by tagName. - * - * @param {CSS_Selector} query The query on the children - * @return {Array} The elements that match this query. - * - * @public - */ - querySelectorAll (query) { - query = query.toUpperCase() - // @ts-ignore - return Array.from(new YXmlTreeWalker(this, element => element.nodeName && element.nodeName.toUpperCase() === query)) - } - /** * Creates YXmlEvent and calls observers. * diff --git a/tests/y-xml.tests.js b/tests/y-xml.tests.js index f9c63ffc..939cb230 100644 --- a/tests/y-xml.tests.js +++ b/tests/y-xml.tests.js @@ -72,6 +72,9 @@ export const testTreewalker = tc => { t.assert(allParagraphs.length === 2, 'found exactly two paragraphs') t.assert(allParagraphs[0] === paragraph1, 'querySelectorAll found paragraph1') t.assert(allParagraphs[1] === paragraph2, 'querySelectorAll found paragraph2') + t.assert(xml0.querySelectorAll({ tagname: 'p' }).length === 2, 'found exactly two paragraphs by tagname') + t.assert(xml0.querySelectorAll({ id: paragraph1ID })[0] === paragraph1, 'querySelectorAll found paragraph1 by id') + t.assert(xml0.querySelectorAll({ attributes: { custom: '123' } })[0] === paragraph1, 'querySelectorAll found paragraph1 by attribute') t.assert(xml0.querySelector('p') === paragraph1, 'querySelector found paragraph1 by string query') t.assert(xml0.querySelector({ tagname: 'p' }) === paragraph1, 'querySelector found paragraph1 by tagname') t.assert(xml0.querySelector({ id: paragraph1ID }) === paragraph1, 'querySelector found paragraph1 by id')