Skip to content

Instantly share code, notes, and snippets.

@liron-navon
Last active January 27, 2019 13:26
Show Gist options
  • Select an option

  • Save liron-navon/29cfdc7018917a01f5f72104ba17c56f to your computer and use it in GitHub Desktop.

Select an option

Save liron-navon/29cfdc7018917a01f5f72104ba17c56f to your computer and use it in GitHub Desktop.
A rebuild of JQuery with es6
// a simple utility function for normalizing return values
const returnValue = values => values.length === 1 ? values[0] : values;;
// a simple function to check existence
const exists = value => value !== undefined && value !== null;
const isString = value => typeof value === 'string';
const isArray = value => Array.isArray(value);
// This is the actual class to hold all of our classes
class ElementAbstraction {
constructor(htmlElements) {
// we can use __elementAbstraction to identify our abstraction instances
this.__elementAbstraction = true;
if (!htmlElements && htmlElements.length === 0) {
// if no elements were past, we can default to body
this.elements = [document.body];
} else if (htmlElements.__elementAbstraction && htmlElements.elements) {
// we just copy the elements from the passed abstraction
this.elements = htmlElements.elements;
} else {
// turn the NodeList elements from a selector into an array
this.elements = [...htmlElements];
}
}
// set or get html
html(newHTML) {
const values = this.elements.map(el => {
if (exists(newHTML)) {
el.innerHTML = newHTML;
}
return el.innerHTML;
});
return returnValue(values);
}
// find the children of the elements
find(selector) {
if(!exists(selector)) {
return this;
}
const elements = this.elements.reduce((acc, el) => {
return [...acc, ...el.querySelectorAll(selector)];
}, []);
return new ElementAbstraction(elements);
}
// hide the elements
hide() {
this.element.forEach(el => {
el.style.visibility = "hidden";
});
}
// show the elements
show() {
this.element.forEach(el => {
el.style.visibility = "visible";
});
}
// append to the elements
append(...elementsOrAbstractions) {
this.elements.forEach(el => {
elementsOrAbstractions.forEach(elementOrAbstraction => {
const newElement = elementOrAbstraction.__elementAbstraction
? elementOrAbstraction.element
: elementOrAbstraction;
el.append(newElement);
});
});
}
// prepend elements
prepend(...elementsOrAbstractions) {
this.elements.forEach(el => {
elementsOrAbstractions.forEach(elementOrAbstraction => {
const newElement = elementOrAbstraction.__elementAbstraction
? elementOrAbstraction.element
: elementOrAbstraction;
el.prepend(newElement);
});
});
}
// attach event to elements
on(eventName, callbackOrSelector, callback) {
if (isString(callbackOrSelector)) {
this.elements.forEach(el => {
el = el.find(callbackOrSelector);
if (el) {
el.addEventListener(eventName, callback);
}
});
} else {
this.elements.forEach(el =>
el.addEventListener(eventName, callbackOrSelector)
);
}
}
// remove event from elements
off(eventName, callbackOrSelector, callback = null) {
if (isString(callbackOrSelector)) {
this.elements.forEach(el => {
el = el.find(callbackOrSelector);
if (el) {
el.removeEventListener(eventName, callback);
}
});
} else {
this.elements.forEach(el =>
el.removeEventListener(eventName, callbackOrSelector)
);
}
}
// sets or get the css of the elements, can also accept an array of propNames
css(propNames, value = null) {
if (value) {
this.elements.forEach(el => (el.css[propNames] = value));
} else if (isArray(propNames)) {
const els = this.elements.reduce(
(acc, el) => [...acc, propNames.map(name => el.css[name])],
[]
);
return returnValue(els);
} else {
const els = this.element.reduce(
(acc, el) => [...acc, el.css[propNames]],
acc
);
return returnValue(els);
}
}
// sets or get the attribute of the elements, can also accept an array of attributeNames
attr(attributeNames, value = null) {
if (value) {
this.elements.forEach(el => (el.attributes[attributeNames] = value));
} else if (isArray(attributeNames)) {
const els = this.elements.reduce(
(acc, el) => [...acc, attributeNames.map(name => el.attributes[name])],
[]
);
return returnValue(els);
} else {
const els = this.element.reduce(
(acc, el) => [...acc, el.attributes[attributeNames]],
acc
);
return returnValue(els);
}
}
// get the value of elements, optionally pass a callback
val(callback = null) {
if (callback) {
this.elements.forEach(callback);
} else {
const values = this.elements.reduce((acc, el) => [...acc, el.value], []);
return returnValue(values);
}
}
// get the combined text of the element and it's children
text() {
const values = this.elements.map(el => el.innerText);
return returnValue(values);
}
// loop the elements, and call a callback with the context of the element
each(callback) {
this.element.forEach((el, index) => callback.call(el, index));
}
}
// here is the main function to generate the abstractions for us
const jquery = selector => {
if (!selector) {
// when calling "$()""
return new ElementAbstraction();
}
if (typeof selector === "string") {
// when calling "$('li')"
return new ElementAbstraction(document.querySelectorAll(selector));
} else if (selector.__elementAbstraction) {
// when calling "$($(li))", people do it for some reason
return new ElementAbstraction([selector.element]);
} else {
// when calling "$()"
return new ElementAbstraction();
}
};
window.$ = jquery;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment