diff options
Diffstat (limited to 'js')
-rw-r--r-- | js/MAP.md | 1 | ||||
-rw-r--r-- | js/bookmarklets/a11y.js | 1 | ||||
-rw-r--r-- | js/where/where.js | 41 | ||||
-rw-r--r-- | js/where/where.test.html | 62 |
4 files changed, 37 insertions, 68 deletions
diff --git a/js/MAP.md b/js/MAP.md index a766176..7de3f62 100644 --- a/js/MAP.md +++ b/js/MAP.md @@ -6,6 +6,7 @@ - `bird-words`, an exploration of Markov chain generation, sort of migrated to <https://git.sr.ht/~eli_oat/beak> - `blototboot`, irc bot and broken lisp interpreter +- `bookmarklets`, misc. bookmarklets for stuff and things - `canvas`, an exploration of the HTML canvas, lets you move a little sprite around a canvas - `dither`, Floyd-Steinberg dithering diff --git a/js/bookmarklets/a11y.js b/js/bookmarklets/a11y.js new file mode 100644 index 0000000..b05ae71 --- /dev/null +++ b/js/bookmarklets/a11y.js @@ -0,0 +1 @@ +javascript:(function(){if(window.focusHighlighter){console.log('Focus highlighter already active.');return;}window.focusHighlighter=true;const style=document.createElement('style');style.id='focus-highlighter-style';style.textContent='.focus-highlight{outline:2px solid red !important;outline-offset:2px !important;}';document.head.appendChild(style);function handleFocus(event){document.querySelectorAll('.focus-highlight').forEach(el=>el.classList.remove('focus-highlight'));if(event.target){event.target.classList.add('focus-highlight');console.log('Focused Element:',event.target);console.log('Tag Name:',event.target.tagName);console.log('Attributes:',Array.from(event.target.attributes).map(attr=>`${attr.name}="${attr.value}"`).join(', '));console.log('Accessible Name:',event.target.getAttribute('aria-label')||event.target.textContent.trim());}}window.addEventListener('focusin',handleFocus);console.log('Focus highlighter activated. Click the bookmarklet again to deactivate.');})(); \ No newline at end of file diff --git a/js/where/where.js b/js/where/where.js index cef80f3..60e3797 100644 --- a/js/where/where.js +++ b/js/where/where.js @@ -5,19 +5,17 @@ * @returns {Array} - Filtered array of objects */ const where = (collection, properties) => { - // null/undefined inputs + if (!collection || !properties) { return []; } - // Cache property paths and their split versions for performance const propertyPaths = Object.entries(properties).map(([key, value]) => ({ path: key, parts: key.split('.'), value })); - // An optimized nested value getter with memoization const getNestedValue = (() => { const cache = new WeakMap(); @@ -45,20 +43,17 @@ const where = (collection, properties) => { }; })(); - // An optimized equality comparison const isEqual = (value1, value2) => { - // Handle null/undefined cases first for faster returns + if (value2 === undefined) return true; if (value1 === value2) return true; if (value1 === null || value2 === null) return false; - // Array comparison if (Array.isArray(value1) && Array.isArray(value2)) { return value1.length === value2.length && value1.every((val, idx) => isEqual(val, value2[idx])); } - // Object comparison if (typeof value2 === 'object') { return Object.entries(value2).every(([key, val]) => value1 && isEqual(value1[key], val) @@ -68,13 +63,11 @@ const where = (collection, properties) => { return false; }; - // Property matcher const matchesProperties = item => propertyPaths.every(({ parts, value }) => isEqual(getNestedValue(item, parts), value) ); - // Input validation if (!Array.isArray(collection) || typeof properties !== 'object') { return []; } @@ -82,37 +75,7 @@ const where = (collection, properties) => { return collection.filter(matchesProperties); }; -// Example usage with nested structures: -/* -const data = [ - { - name: 'John', - age: 30, - preferences: { - theme: 'dark', - notifications: { email: true, sms: false } - } - }, - { - name: 'Jane', - age: 25, - preferences: { - theme: 'light', - notifications: { email: false, sms: true } - } - } -]; - -// Find users with specific preferences -const darkThemeUsers = where(data, { - preferences: { theme: 'dark' } -}); -// Find users with specific notification settings -const emailSubscribers = where(data, { - preferences: { notifications: { email: true } } -}); -*/ if (typeof module !== 'undefined' && module.exports) { module.exports = where; diff --git a/js/where/where.test.html b/js/where/where.test.html index 0b2fcf6..161ecf1 100644 --- a/js/where/where.test.html +++ b/js/where/where.test.html @@ -1,8 +1,9 @@ <!DOCTYPE html> <html lang="en"> <head> - <title>Where Function Tests</title> + <title>Where?</title> <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> body { font-family: monospace; @@ -37,14 +38,17 @@ </style> </head> <body> - <h1>Where Function Documentation & Tests</h1> + <h1>Where?</h1> <section> <h2>Overview</h2> <p> - The <code>where()</code> function provides SQL-like filtering for JavaScript arrays of objects. + This <code>where()</code> function aims to provide sql-like filtering for arrays of objects. It allows you to filter collections using simple or complex criteria, including nested properties. </p> + <p> + Could you usually use <code>Array.filter()</code> instead? Yes, almost always. But I think this is a bit prettier. + </p> </section> <section> @@ -52,26 +56,26 @@ <div class="example"> <pre> const users = [ - { name: 'John', age: 30 }, - { name: 'Jane', age: 25 }, - { name: 'Bob', age: 30 } + { name: 'Tziporah', age: 30 }, + { name: 'Bruce', age: 25 }, + { name: 'Ruth', age: 30 } ]; -// Find all users who are 30 years old +// Find everyone who is 30 years old const thirtyYearOlds = where(users, { age: 30 }); -// Result: [{ name: 'John', age: 30 }, { name: 'Bob', age: 30 }]</pre> +// Result: [{ name: 'Tziporah', age: 30 }, { name: 'Ruth', age: 30 }]</pre> </div> </section> <section> - <h2>Advanced Features</h2> + <h2>More Advanced Features</h2> <h3>1. Nested Object Properties</h3> <div class="example"> <pre> const users = [ { - name: 'John', + name: 'Bruce', preferences: { theme: 'dark', notifications: { email: true } @@ -79,7 +83,7 @@ const users = [ } ]; -// Find users with dark theme +// Find people with the dark theme enabled const darkThemeUsers = where(users, { preferences: { theme: 'dark' } });</pre> @@ -97,7 +101,7 @@ const darkThemeUsers = where(users, { <h3>3. Multiple Criteria</h3> <div class="example"> <pre> -// Find users who are 30 AND prefer dark theme +// Find folks who are 30 AND prefer dark theme const result = where(users, { age: 30, 'preferences.theme': 'dark' @@ -109,12 +113,12 @@ const result = where(users, { <pre> const users = [ { - name: 'John', + name: 'Jeremiah', hobbies: ['reading', 'music'] } ]; -// Find users with exact hobby matches +// Find people with exact hobby matches const readers = where(users, { hobbies: ['reading', 'music'] });</pre> @@ -122,14 +126,14 @@ const readers = where(users, { </section> <section> - <h2>Key Features</h2> + <h2>The Key Features</h2> <ul> - <li>Supports deep object comparison</li> + <li>Deep object comparison</li> <li>Handles null/undefined values</li> - <li>Supports both nested object and dot notation</li> + <li>Supports nested object and dot notation</li> <li>Exact array matching</li> <li>Multiple criteria (AND logic)</li> - <li>Memoized for performance</li> + <li>Memoized for performance 🏃♂️</li> </ul> </section> @@ -141,12 +145,12 @@ const readers = where(users, { <pre> const users = [ { - name: 'John', + name: 'Bruce', hobbies: ['reading', 'music', 'hiking'] } ]; -// This will NOT match John's hobbies +// This won't match Bruce's hobbies const result = where(users, { hobbies: ['reading', 'music'] }); // Returns [] @@ -157,7 +161,7 @@ const result = where(users, { <h3>2. OR Operations</h3> <div class="example"> <pre> -// This will NOT work for finding users aged 25 OR 30 +// This won't work for finding users aged 25 OR 30 const result = where(users, { age: [25, 30] // This looks for an exact array match }); @@ -174,7 +178,7 @@ const result = users.filter(user => // These operations are NOT supported: where(users, { age: (age) => age > 30, // Function predicates - salary: { $gt: 50000 }, // MongoDB-style operators + salary: { $gt: 50000 }, // MongoDB-style operators 🤮 'name.length': 4 // Property operations });</pre> </div> @@ -182,7 +186,7 @@ where(users, { <h3>4. Regular Expressions</h3> <div class="example"> <pre> -// RegExp matching is NOT supported +// RegExp matching also isn't implemented where(users, { email: /.*@gmail\.com$/ }); @@ -196,22 +200,22 @@ const gmailUsers = users.filter(user => <h3>5. When Not to Use</h3> <ul> <li><strong>Complex Filtering Logic:</strong> If you need OR conditions, ranges, or custom predicates</li> - <li><strong>Large Data Sets:</strong> When performance is critical and you need indexed operations</li> - <li><strong>Dynamic Queries:</strong> When query conditions need to be built dynamically with different operators</li> - <li><strong>Partial Matches:</strong> When you need partial array matches or string contains operations</li> + <li><strong>Large Data Sets:</strong> When performance is critical and you need indexed operations...probably don't use JavaScript</li> + <li><strong>Dynamic Queries:</strong> When query conditions need to be built from different operators on the fly</li> + <li><strong>Partial Matches:</strong> When you need partial array matches or when a string contains operations</li> </ul> <h3>6. Performance Considerations</h3> <div class="example"> <pre> -// Avoid deep nesting with large arrays +// Avoid deeply nesting with large arrays const deeplyNested = where(largeArray, { 'level1.level2.level3.level4.property': value }); -// Each level of nesting increases comparison complexity +// Each level of nesting increases complexity -// Better to use direct access if possible: +// Use direct access whenever possible: const result = largeArray.filter(item => item.level1?.level2?.level3?.level4?.property === value );</pre> |