Skip to content

Instantly share code, notes, and snippets.

@snewcomer
Created May 28, 2018 18:33
Show Gist options
  • Save snewcomer/c0b765a16f0f6f1a02a113b1da369c9f to your computer and use it in GitHub Desktop.
Save snewcomer/c0b765a16f0f6f1a02a113b1da369c9f to your computer and use it in GitHub Desktop.
node query class pattern
/* global Node */
import { assert } from 'ember-debug';
import { fireEvent, focus, matches } from '../system/synthetic-events';
export default class NodeQuery {
static query(selector, context = document) {
assert(`Invalid second parameter to NodeQuery.query`, context && context instanceof Node);
return new NodeQuery(toArray(context.querySelectorAll(selector)));
}
static element(element) {
return new NodeQuery([element]);
}
constructor(nodes) {
assert('NodeQuery must be initialized with a literal array', Array.isArray(nodes));
this.nodes = nodes;
for (let i=0; i<nodes.length; i++) {
this[i] = nodes[i];
}
this.length = nodes.length;
Object.freeze(this);
}
find(selector) {
assertSingle(this);
return this[0].querySelector(selector);
}
findAll(selector) {
let nodes = [];
this.nodes.forEach(node => {
nodes.push(...node.querySelectorAll(selector));
});
return new NodeQuery(nodes);
}
trigger(eventName, options) {
return this.nodes.map(node => fireEvent(node, eventName, options));
}
click() {
return this.trigger('click');
}
focus() {
this.nodes.forEach(focus);
}
text() {
return this.nodes.map(node => node.textContent).join('');
}
attr(name) {
if (arguments.length !== 1) {
throw new Error('not implemented');
}
assertSingle(this);
return this.nodes[0].getAttribute(name);
}
prop(name, value) {
if (arguments.length > 1) {
return this.setProp(name, value);
}
assertSingle(this);
return this.nodes[0][name];
}
setProp(name, value) {
this.nodes.forEach(node => node[name] = value);
return this;
}
val(value) {
if (arguments.length === 1) {
return this.setProp('value', value);
}
return this.prop('value');
}
is(selector) {
return this.nodes.every(node => matches(node, selector));
}
hasClass(className) {
return this.is(`.${className}`);
}
}
function assertSingle(nodeQuery) {
if (nodeQuery.length !== 1) {
throw new Error(`attr(name) called on a NodeQuery with ${this.nodes.length} elements. Expected one element.`);
}
}
function toArray(nodes) {
let out = [];
for (let i=0; i<nodes.length; i++) {
out.push(nodes[i]);
}
return out;
}
// example
$(sel) {
if (sel instanceof Element) {
return NodeQuery.element(sel);
} else if (typeof sel === 'string') {
return NodeQuery.query(sel, this.element);
} else if (sel !== undefined) {
throw new Error(`Invalid this.$(${sel})`);
} else {
return NodeQuery.element(this.element);
}
}
wrap(element) {
return NodeQuery.element(element);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment