Skip to content

Instantly share code, notes, and snippets.

@AdaRoseCannon
Last active June 22, 2023 23:59
Show Gist options
  • Save AdaRoseCannon/d95a7cbb8edd730443c62f0daff875ac to your computer and use it in GitHub Desktop.
Save AdaRoseCannon/d95a7cbb8edd730443c62f0daff875ac to your computer and use it in GitHub Desktop.
Oh no!
// This is just the worst don't use it.
function $(...s) {
if (s.length === 0) return document.childNodes;
// Handle it being used as a template tag
const inString = (typeof s[0] === 'string' ? s[0] : String.raw(...s)).trim();
if (inString[0].includes('<')) {
return document.createRange().createContextualFragment(inString);
} else {
return document.querySelectorAll(inString);
}
}
Element.prototype.on = window.on = function (name, fn, options) {
if (!this.funcRef) this.funcRef = new Set();
// Store it for later
this.funcRef.add(fn);
this.addEventListener(name, fn, options);
return this;
};
Element.prototype.off = window.off = function (name, fn) {
if (!this.funcRef) return;
if (fn) {
this.removeEventListener(name, fn);
} else {
this.funcRef.forEach(fn => this.removeEventListener(name, fn));
}
this.funcRef.delete(fn);
return this;
};
Element.prototype.once = window.once = function (name, fn, options) {
const o = {once: true};
Object.assign(o, options);
this.on(name, function tempF(e) {
fn.bind(this)(e);
this.off(name, tempF);
}, o);
return this;
};
const childAccessorProxy = {
get(target, prop) {
if (prop in target) return target[prop];
// Maps each parent to that property on that parent
// If they are functions they get bound.
const propFromEachElement = target.map((i,index) => {
return (i[prop] && 'bind' in i[prop]) ? i[prop].bind(i) : i[prop]
});
const proxiedArray = new Proxy(propFromEachElement, childAccessorProxy);
// Return a function which will try to call all of the children with the arguments.
// Otherwise will reflect them onto the proxied array of the requested property from all the
return new Proxy(function (...args) {
target.forEach(i => i[prop] && i[prop](...args));
return target;
}, {
get(target,...args){return Reflect.get(proxiedArray, ...args)},
set(target,...args){return Reflect.set(proxiedArray, ...args)},
has(target,...args){return Reflect.has(proxiedArray, ...args)},
});
},
set(target, prop, value) {
if (prop in target) {
target[prop] = value;
} else {
target.forEach(i => i[prop] = value);
}
}
};
// Add all properties and functions on Element to NodeList
// This is a bad thing to do
for (const key in Element.prototype) {
if (key in NodeList.prototype) continue;
Object.defineProperty(NodeList.prototype, key, {
get(){
try {
if (typeof Element.prototype[key] === 'function') return function (...args) {
this.forEach(el => el instanceof Element && el[key](...args));
return this;
}
} catch (e) {}
return new Proxy(Array.from(this).filter(el => el instanceof Element).map(el=>el[key]), childAccessorProxy);
},
set(value){
this.forEach(el=>el[key]=value)
},
configurable: true
})
}
export default $;
document.querySelectorAll('span').textContent = 'butts'; // Change the text of every span
// Get at an Array of all the textContents
document.querySelectorAll('span').textContent;
// ['butts', 'butts', 'butts', 'butts', 'butts', 'butts', ...]
// $('span') or $`span` can also be used.
// It also recursively works on the properties:
$`span`.classList.add('blue');
// You can also use it to create fragments on the fly
$`body`.appendChild($`<b>hi!`)
@WebReflection
Copy link

as you go for .trim() after checking s[0], you might as well consider using the way more performant typeof check:

const inString = (typeof s[0] === 'string' ? s[0] : String.raw(...s)).trim();

also, as if (inString[0] === '<') { wouldn't consider fragments with < within the query, and as that's still not valid CSS selector, you might as well go for:

if (inString.includes('<'))

Last, but not least, whenever you pollute global/native prototypes, it's always welcome to use, at least, configurable: true, for whatever patch is needed in the future, or for those environments that would like to delete these non-standards entries.

@AdaRoseCannon
Copy link
Author

I updated it with these changes 👍

@nuxodin
Copy link

nuxodin commented Apr 25, 2022

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment