Skip to content

Instantly share code, notes, and snippets.

@mhluska
Last active September 7, 2018 12:09
Show Gist options
  • Save mhluska/f85808331cd07a22ca2c079c7389a705 to your computer and use it in GitHub Desktop.
Save mhluska/f85808331cd07a22ca2c079c7389a705 to your computer and use it in GitHub Desktop.
Simulate document.querySelector() in Ember FastBoot
import Service, { inject as service } from '@ember/service';
import { getOwner } from '@ember/application';
import { computed } from '@ember/object';
export default Service.extend({
fastboot: service(),
init() {
this._elemCache = {};
this._super(...arguments);
},
document: computed(function() {
return getOwner(this).lookup('service:-document');
}),
body: computed('document', function() {
return this.get('document.body');
}),
head: computed('document', function() {
return this.get('document.head');
}),
// NOTE: Only supports single class for now.
querySelector(selector) {
const body = this.get('body');
if (this.get('fastboot.isFastBoot')) {
if (this._elemCache.hasOwnProperty(selector)) {
return this._elemCache[selector];
} else {
const elem = this._breadthFirstSearch(body, selector.slice(1));
this._elemCache[selector] = elem;
return elem;
}
} else {
return body.querySelector(selector);
}
},
_breadthFirstSearch(rootNode, className) {
const queue = [rootNode];
while (queue.length !== 0) {
const currentNode = queue.shift();
if (currentNode.nodeType !== 1) continue;
const attr = currentNode.getAttribute ? currentNode.getAttribute('class') : null;
const classList = attr ? attr.split(/\s+/) : [];
if (classList.includes(className)) return currentNode;
for (let current = currentNode.firstChild; current; current = current.nextSibling) {
queue.push(current);
}
}
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment