Skip to content

Instantly share code, notes, and snippets.

View ryanmorr's full-sized avatar

Ryan Morr ryanmorr

View GitHub Profile
@ryanmorr
ryanmorr / scope.js
Last active March 29, 2024 06:40
Emulate the with statement
function scope(obj, callback) {
const source = callback.toString();
const vars = Object.getOwnPropertyNames(obj).map((key) => `${key} = this['${key}']`);
const body = source.substring(source.indexOf('{') + 1, source.lastIndexOf('}'));
const fn = new Function(`var ${vars.join(',')}; ${body}`);
fn.call(obj);
}
// Usage:
@ryanmorr
ryanmorr / css-vars.js
Last active February 15, 2024 19:19
Get, set, and remove a CSS variable in JavaScript
function getCSSVar(name, element = document.documentElement) {
return getComputedStyle(element).getPropertyValue(`--${name}`);
}
function setCSSVar(name, value, element = document.documentElement) {
element.style.setProperty(`--${name}`, value);
}
function removeCSSVar(name, element = document.documentElement) {
element.style.removeProperty(`--${name}`);
@ryanmorr
ryanmorr / debug.css
Created March 7, 2018 19:10
Debug layouts
* {
outline: 1px solid #fff !important;
background-color: rgba(0,2,54,.1) !important;
}
@ryanmorr
ryanmorr / is-node-list.js
Last active January 17, 2024 08:07
Detect a DOM nodelist or the like
function isNodeList(obj) {
const type = {}.toString.call(obj).slice(8, -1);
switch(type) {
case 'NodeList':
case 'HTMLCollection':
case 'HTMLOptionsCollection':
case 'HTMLFormControlsCollection':
case 'RadioNodeList':
case 'StyleSheetList':
return true;
@ryanmorr
ryanmorr / for-each-match.js
Last active April 1, 2024 20:26
Iterate through all the matches of a regular expression and call a function
function forEachMatch(regex, str, callback) {
if (regex.global) {
regex.lastIndex = 0;
}
let i = -1, match;
while ((match = regex.exec(str))) {
callback(match, i++, str, regex);
}
}
@ryanmorr
ryanmorr / proxy-detection.js
Created January 15, 2024 02:57
The only way to detect proxies without mutating the object
// Courtesy of: https://www.reddit.com/r/javascript/comments/4wrdxd/comment/d69j04s/
const proxies = new WeakSet();
function createProxy(target, handler) {
const proxy = new Proxy(target, handler);
proxies.add(proxy);
return proxy;
}
function isProxy(obj) {
@ryanmorr
ryanmorr / for-each-child.js
Last active January 15, 2024 06:49
Fastest way to iterate through each child node of an element and call a function
// Traversing with firstChild/nextSibling is much faster than childNodes: https://jsperf.app/nextsibling-vs-childnodes
function forEachChild(element, callback) {
let node = element.firstChild;
while (node) {
callback(node);
node = node.nextSibling;
}
}
@ryanmorr
ryanmorr / touch-detection.js
Last active March 30, 2024 06:51
Determine if the user has a touch-enabled device
// An aggressive means to detect if the user's device is touch only
// Probably bad practice: https://css-tricks.com/interaction-media-features-and-their-potential-for-incorrect-assumptions/
function isTouch() {
return matchMedia('(hover: none) and (pointer: coarse)').matches;
}
// A more passive approach is to detect if the user's device is merely touch-enabled
function hasTouch() {
return matchMedia('(any-pointer:coarse)').matches;
}
@ryanmorr
ryanmorr / env.js
Created January 15, 2024 07:03
Are we on the client or the server?
function isBrowser() {
return typeof window != 'undefined' && typeof window.document != 'undefined';
}
function isServer() {
return typeof process != 'undefined' && {}.toString.call(process) == '[object process]';
}
@ryanmorr
ryanmorr / css-json.js
Created January 15, 2024 07:11
Define JSON data within CSS
// I have no idea how practical this is, but I can't help but appreciate hacks like this
// Found it here: https://github.com/uikit/uikit/blob/fc644b5107c47c7242436c782dd935a374ab399e/src/js/util/style.js#L65
const vars = {};
function getCSSVar(name) {
if (!(name in vars)) {
const el = document.createElement('div');
document.documentElement.appendChild(el);
el.classList.add(`var-${name}`);