8eeb22b7b8 | 8 years ago | |
---|---|---|
src | 8 years ago | |
.gitignore | 8 years ago | |
.npmignore | 8 years ago | |
CHANGELOG.md | 8 years ago | |
README.md | 8 years ago | |
gulpfile.js | 8 years ago | |
index.js | 8 years ago | |
package.json | 8 years ago | |
test.js | 8 years ago |
README.md
riot-query
A module for easily traversing through a Riot.js tag hierarchy, using a simple custom query language. Can be used stand-alone or as a tag mixin.
Why you might need this
- Riot.js is inconsistent in how it exposes its
tags
- it will be an array if there are multiple, and a single element if there's only one. This means you constantly have to normalize the results. - While selecting direct descendants is easy, it's a lot trickier when you need to search in the entire hierarchy, for example because you have a wrapper element that
yield
s its content.
License
WTFPL or CC0, whichever you prefer. A donation and/or attribution are appreciated, but not required.
Donate
Maintaining open-source projects takes a lot of time, and the more donations I receive, the more time I can dedicate to open-source. If this module is useful to you, consider making a donation!
You can donate using Bitcoin, PayPal, Flattr, cash-in-mail, SEPA transfers, and pretty much anything else. Thank you!
Contributing
Pull requests welcome. Please make sure your modifications are in line with the overall code style, and ensure that you're editing the files in src/
, not those in lib/
.
Build tool of choice is gulp
; simply run gulp
while developing, and it will watch for changes.
Be aware that by making a pull request, you agree to release your modifications under the licenses stated above.
Query language
A query consists of two parts: a Riot query and a DOM query. Both are optional, but you must always specify at least one of them.
In the Riot part of a query, the structure always refers to the hierarchy of Riot tags, not other DOM elements. In other words, the hierarchy follows the one you'd find in this.tags
. In the DOM part of the query, you can specify DOM elements to select in the set of Riot tags that you've selected.
The riot-query
language is somewhat syntactically similar to shell expansion. Below is a reference chart:
Syntax | Meaning |
---|---|
foo |
Each foo tag. |
foo/bar |
Each bar tag that is a direct descendant of a foo tag. |
foo/**/bar |
Each bar tag that is a child of a foo tag, anywhere in its subtree - it does not have to be a direct descendant. |
{foo,bar} |
Each foo and bar tag |
foo/{bar,baz} |
Each bar and baz tag that is a direct descendant of a foo tag. |
foo/{bar,baz,} |
Each foo , foo/bar and foo/baz tag (note the last comma!) |
foo//.someClass |
Each DOM element matching .someClass that exists somewhere within a foo tag. |
foo//.someClass > .sub |
Each DOM element matching .someClass > .sub that exists somewhere within a foo tag. |
These are only some simplified examples - any combination of the above is valid, as long as the (optional) DOM part of the query comes last. riot-query
uses a real query parser, so there are no edge cases.
Usage
An example of a simple query:
menu-bar/{menu-button,menu-submenu}
This would select every menu-button
and menu-submenu
that is directly nested within a menu-bar
.
An example of a contrived, complex query:
foo/bar/**/{baz,qux/quz,something/{hai,bai},}/{duck,swan}//.domFoo .domBar
This would select every DOM element matching .domFoo .domBar
that exists within any of the following paths:
foo/bar/**/baz/duck
foo/bar/**/baz/swan
foo/bar/**/qux/quz/duck
foo/bar/**/qux/quz/swan
foo/bar/**/something/hai/duck
foo/bar/**/something/hai/swan
foo/bar/**/something/bai/duck
foo/bar/**/something/bai/swan
foo/bar/**/duck
foo/bar/**/swan
The last two might seem a little odd, but note the extra comma at the end of the first group - a trailing comma is considered to indicate an empty item, similar to how it works in Bash, and in riot-query
that means that the entire segment is ignored.
An example of making a query using riot-query
as a mixin:
<menu-bar>
<menu-section>
<menu-item>Text 1</menu-item>
<menu-item>Text 2</menu-item>
</menu-section>
<script>
this.mixin(require("riot-query").mixin);
this.on("mount", () => {
this.query("**/menu-item").forEach((menuItem) => {
menuItem.on("clicked", () => {
console.log("Clicked menu item", menuItem);
});
});
});
</script>
</menu-bar>
A similar example, but selecting DOM nodes rather than Riot tags:
<menu-bar>
<menu-section>
<menu-item>
<i class="icon icon-house"></i>
Text 1
</menu-item>
<menu-item>
<i class="icon icon-keys"></i>
Text 2
</menu-item>
</menu-section>
<script>
this.mixin(require("riot-query").mixin);
this.on("mount", () => {
this.query("**/menu-item//i.icon").forEach((icon) => {
console.log("Icon classes", icon.classList);
});
});
</script>
</menu-bar>
An example using riot-query
stand-alone rather than as a mixin:
<menu-bar>
<menu-section>
<menu-item>
<i class="icon icon-house"></i>
Text 1
</menu-item>
<menu-item>
<i class="icon icon-keys"></i>
Text 2
</menu-item>
</menu-section>
<script>
const riotQuery = require("riot-query");
this.on("mount", () => {
riotQuery(this, "**/menu-item//i.icon").forEach((icon) => {
console.log("Icon classes", icon.classList);
});
});
</script>
</menu-bar>
API
riotQuery(tag, query)
Run a query
on a given tag
, and return the results.
- tag: The Riot.js tag to query from. This cannot be a regular DOM element, it must be a tag.
- query: The query to run, following the query syntax described above.
If the query
contains a DOM query, this function will return DOM elements. If it doesn't, it will return Riot tags. If only a DOM query is specified without a Riot query (eg. //.someClass
), then riot-query
will search through the DOM tree for the tag that riotQuery
was called on.
Keep in mind that if your query selects DOM nodes rather than Riot tags, they will be returned as an array, not as a NodeList. Additionally, DOM queries will also include DOM elements in child tags, not just those that are a part of the tag you're querying from.
riotQuery.one(tag, query)
The same as riotQuery
, but it only ever returns the first result, without being wrapped in an array.
riotQuery.mixin
A mixin object that you can pass into the this.mixin
method for any Riot tag.
Mixin API
this.query(query)
The same as riotQuery
, but without the need to specify a tag
- it will always apply to the current tag.
this.queryOne(query)
The same as riotQuery.one
, but without the need to specify a tag
.