Skip to content

Instantly share code, notes, and snippets.

View ryanmorr's full-sized avatar

Ryan Morr ryanmorr

View GitHub Profile
@ryanmorr
ryanmorr / collection.js
Created September 28, 2025 22:04
A class for hashmaps that maintain order
class Collection {
#keys;
#values;
#map;
constructor(data) {
this.#keys = [];
this.#values = [];
this.#map = {}
if (data) {
@ryanmorr
ryanmorr / enum.js
Created September 28, 2025 20:23
Simple class for creating enums in JavaScript
class Enum {
constructor(...keys) {
keys.forEach((key) => {
this[key] = key;
});
Object.freeze(this);
}
*[Symbol.iterator]() {
for (let key of Object.keys(this)) {
@ryanmorr
ryanmorr / log-deprecations.js
Created September 28, 2025 19:52
Use ReportingObserver to log depreacted APIs and features to the console
function logReports(reports) {
console.warn('This page is using deprecated APIs or features:');
console.table(reports.map((report) => ({
url: report.url,
message: report.body.message,
line: report.body.lineNumber || '---',
column: report.body.columnNumber || '---',
anticipatedRemoval: report.body.anticipatedRemoval ? (new Date(report.body.anticipatedRemoval)).toLocaleDateString() : '---'
})));
}
@ryanmorr
ryanmorr / scrollable.css
Created September 28, 2025 19:27
Utility CSS classes to make a container scrollable with enhanced behavior
.scrollable {
/* Make a container scrollable */
overflow: auto;
/* Prevent scroll chaining to the parent element but still allows overscroll affordances*/
overscroll-behavior: contain;
/* Space is reserved for the scrollbar to prevent layout shifts when the scrollbar appears or disappears */
scrollbar-gutter: stable;
}
/* Alternative versions to restrict scrolling to the X or Y axes */
@ryanmorr
ryanmorr / load-css.js
Created September 28, 2025 18:58
Dynamically load a CSS stylesheet and return a promise
function loadCSS(path) {
return new Promise((resolve, reject) => {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = path;
link.onload = resolve;
link.onerror = reject;
document.head.appendChild(link);
});
@ryanmorr
ryanmorr / promise-detection.js
Created September 28, 2025 17:05
Promise detection and resolution
// Check if an object is a promise instance
function isPromise(obj) {
return obj instanceof Promise;
}
// Better yet, detect a thenable to support alternative implementations
function isThenable(obj) {
return obj && typeof obj.then === 'function';
}
@ryanmorr
ryanmorr / abortable-promise.js
Created September 28, 2025 16:06
Make a promise abortable via AbortController
function abortablePromise(executor) {
const controller = new AbortController();
const promise = new Promise((resolve, reject) => {
controller.signal.addEventListener('abort', () => reject(new Error('Aborted')));
executor(resolve, reject);
});
// Add abort method to promise instance
promise.abort = controller.abort.bind(controller);
return promise;
}
@ryanmorr
ryanmorr / event-promise.js
Created August 24, 2025 16:06
Promisify a DOM event listener for single use purposes
function eventPromise(element, type) {
return new Promise((resolve) => element.addEventListener(type, resolve, {once: true}));
}
@ryanmorr
ryanmorr / is-secure-context.js
Created August 9, 2025 19:08
Check if the user's browser is running in a secure context
// https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts
function isSecureContext() {
return window.isSecureContext ||
location.protocol === 'https:' ||
location.hostname === 'localhost' ||
location.hostname === '127.0.0.1';
}
@ryanmorr
ryanmorr / page-state.js
Last active August 10, 2025 19:01
Simple means to handling page state for both JavaScript and CSS
const el = document.documentElement;
let state = el.className || null;
function setPageState(val) {
if (state) {
el.classList.remove(state);
}
state = val;
el.classList.add(state);
}