Last active
March 5, 2016 16:17
-
-
Save rspieker/9bed3c6065b805f71d31 to your computer and use it in GitHub Desktop.
Suggestions on how to improve the helper library at http://blog.wearecolony.com/a-year-without-jquery/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @param {Element} el | |
* @param {string} selector | |
* @return {Element[]} | |
*/ | |
h.children = function(el, selector) { | |
var selectors = null, | |
children = null, | |
childSelectors = [], | |
tempId = ''; | |
selectors = selector.split(','); | |
if (!el.id) { | |
tempId = '_temp_'; | |
el.id = tempId; | |
} | |
while (selectors.length) { | |
childSelectors.push('#' + el.id + '>' + selectors.pop()); | |
} | |
children = document.querySelectorAll(childSelectors.join(', ')); | |
if (tempId) { | |
el.removeAttribute('id'); | |
} | |
return children; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Element.querySelectorAll is available in IE8 and better | |
// https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelectorAll | |
h.children = function(el, selector) { | |
return el.querySelectorAll(selector); | |
}; | |
/* | |
It provides the exact same result, without the array mangling and creation | |
of a fairly expensive selector. | |
One thing to be aware of using CSS selector is that these do not work how you expect, | |
as they are actually read from right to left. | |
So lets say you have created a selector like '#myId > span', what will happen is that | |
the browser will create a list of all spans and remove the ones not being present in | |
any element with the id 'myId'. | |
NOTE: sorry, this will somewhat force you to change the following claim in your article: | |
"And crucially, in the case of children(), and index(), still have no native DOM API equivalents." | |
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @param {Element} el | |
* @param {string} selector | |
* @param {boolean} [includeSelf] | |
* @return {Element|null} | |
*/ | |
h.closestParent = function(el, selector, includeSelf) { | |
var parent = el.parentNode; | |
if (includeSelf && el.matches(selector)) { | |
return el; | |
} | |
while (parent && parent !== document.body) { | |
if (parent.matches && parent.matches(selector)) { | |
return parent; | |
} else if (parent.parentNode) { | |
parent = parent.parentNode; | |
} else { | |
return null; | |
} | |
} | |
return null; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
h.closestParent = function(el, selector, include) { | |
var target = el; | |
while (target && target !== document.body) { | |
if (include && target.matches && target.matches(selector)) { | |
return target; | |
} | |
include = true; | |
target = target.parentNode; | |
} | |
}; | |
/* | |
It reduces the flow and does not require two separate tests for `matches`, | |
which allows for easier maintenance and is less likely to end up differently. | |
Why reduce the flow? | |
Did you know parent.parentNode already equals null if there is no parentNode? | |
This makes the `else if (parent.parentNode) {..} else {..}` very redundant and | |
does not provide anything other than a very explicit way of doing the exact same | |
thing. | |
Why should I have two tests for `matches`? | |
Well, firstly it is not DRY (Don't Repeat Yourself, considered good practise in | |
programming) and secondly, you already introduced a slight difference in those | |
two ;-) | |
`if (includeSelf && el.matches(selector))` does not test for `matches` to exist, | |
while `if (parent.matches && parent.matches(selector))` does do this | |
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @param {string} html | |
* @return {DocumentFragment} | |
*/ | |
h.createElement = function(html) { | |
var frag = document.createDocumentFragment(), | |
temp = document.createElement('div'); | |
temp.innerHTML = html; | |
while (temp.firstChild) { | |
frag.appendChild(temp.firstChild); | |
} | |
return frag; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// I'd suggest renaming this method to prevent confusion the DOM `createElement` method which does actually return | |
// an element | |
// suggestion: createFragment |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @param {Element} el | |
* @return {void} | |
*/ | |
h.deleteElement = function(el) { | |
if (el.parentElement) { | |
el.parentElement.removeChild(el); | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
h.removeElement = function(el) { | |
return el.parentNode ? el.parentNode.removeChild(el) : null; | |
} | |
/* | |
As a matter of preference I tend to write simple if/else conditions which return | |
value as a single ternary statement. | |
NOTE: I used parentNode instead of parentElement, as this will actually allow you to remove | |
the `<html>` element from the document and any element from a documentFragment should you ever want to do this. | |
The parentNode and parentElement are faily similar, except parentElement does not consider the document itself | |
nor a document fragment as Element (because they are not), they are - however - Nodes and it is the Node interface | |
that implements the removeChild method. | |
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @param {Element} el | |
* @param {string} [selector] | |
* @return {number} | |
*/ | |
h.index = function(el, selector) { | |
var i = 0; | |
while ((el = el.previousElementSibling) !== null) { | |
if (!selector || el.matches(selector)) { | |
++i; | |
} | |
} | |
return i; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// I have no improvements for this function, it is a beauty. | |
// You could safely remove the `!== null`, as the `while` will test `el` as false if there is no `previousElementSibling` | |
// One slight concern: `el` itself is not required to match the selector itself, not sure if this was intentional |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment