Add jsExtension snippet
This commit is contained in:
96
javascript/js-extension/README.md
Normal file
96
javascript/js-extension/README.md
Normal file
@ -0,0 +1,96 @@
|
||||
# js-extension (JavaScript)
|
||||
|
||||
A tiny, dependency‑free utility class with a few DOM and string helpers that I often reach for in small projects and prototypes.
|
||||
|
||||
It includes:
|
||||
- `addGlobalEventListener` — delegated events with a CSS selector
|
||||
- `createElement` — quick DOM element creation with attributes, class, dataset, and text
|
||||
- `qs` / `qsa` — short aliases for `querySelector` / `querySelectorAll` with optional parent
|
||||
- `strToHtml` — convert an HTML string to a `DocumentFragment`
|
||||
- `isJson` — quick check if a string parses as JSON
|
||||
- `sleep` — simple delay (`Promise`-based)
|
||||
|
||||
## Quick usage
|
||||
|
||||
Minimal examples showing what the helpers do. Adjust to your environment as needed.
|
||||
|
||||
```js
|
||||
// Assume jsExtension is available in scope
|
||||
|
||||
// 1) Delegated event listener
|
||||
jsExtension.addGlobalEventListener("click", "[data-action=remove]", (e) => {
|
||||
const btn = e.target.closest("[data-action=remove]");
|
||||
btn?.closest(".item")?.remove();
|
||||
});
|
||||
|
||||
// 2) Create element with attributes, class, dataset, and text
|
||||
const card = jsExtension.createElement("div", {
|
||||
class: "card",
|
||||
id: "card-1",
|
||||
dataset: { id: "1", type: "example" },
|
||||
"aria-label": "Example card",
|
||||
text: "Hello!",
|
||||
});
|
||||
|
||||
// 3) Shorthand query helpers
|
||||
const firstItem = jsExtension.qs(".item");
|
||||
const allItems = jsExtension.qsa(".item");
|
||||
|
||||
// 4) String to HTML fragment
|
||||
const frag = jsExtension.strToHtml(`
|
||||
<ul>
|
||||
<li>One</li>
|
||||
<li>Two</li>
|
||||
</ul>
|
||||
`);
|
||||
document.body.appendChild(frag);
|
||||
|
||||
// 5) JSON check
|
||||
jsExtension.isJson('{"a":1}'); // true
|
||||
jsExtension.isJson('{a:1}'); // false
|
||||
|
||||
// 6) Sleep helper
|
||||
await jsExtension.sleep(300);
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### `addGlobalEventListener(type, selector, callback, options?, parent=document)`
|
||||
Adds a single delegated listener on `parent` and runs `callback` when the event target matches `selector` (or is inside an element that matches).
|
||||
|
||||
- `type`: string event type, e.g. `"click"`
|
||||
- `selector`: CSS selector to match or `closest()` to
|
||||
- `callback`: function receiving the event
|
||||
- `options`: optional `addEventListener` options
|
||||
- `parent`: `HTMLElement | Document` (defaults to `document`)
|
||||
|
||||
### `createElement(type, options={}) => HTMLElement`
|
||||
Creates an element and applies the provided options.
|
||||
Supported option keys:
|
||||
- `class`: string — added via `classList.add`
|
||||
- `dataset`: object — assigned to `element.dataset[key] = value`
|
||||
- `text`: string — sets `textContent`
|
||||
- any other key — assigned as attribute: `setAttribute(key, value)`
|
||||
|
||||
### `qs(selector, parent=document) => Element|null`
|
||||
Shorthand for `parent.querySelector(selector)`. Returns `null` if `parent` is not a `Document`/`HTMLElement`.
|
||||
|
||||
### `qsa(selector, parent=document) => NodeList<Element>`
|
||||
Shorthand for `parent.querySelectorAll(selector)`. Falls back to `document.querySelectorAll` when `parent` is not a `Document`/`HTMLElement`.
|
||||
|
||||
### `strToHtml(str) => DocumentFragment`
|
||||
Converts an HTML string into a `DocumentFragment` using `Range#createContextualFragment`.
|
||||
|
||||
### `isJson(str) => boolean`
|
||||
Returns `true` if `JSON.parse(str)` succeeds; otherwise `false`.
|
||||
|
||||
### `sleep(time) => Promise<void>`
|
||||
Resolves after `time` milliseconds using `setTimeout`.
|
||||
|
||||
## Notes
|
||||
- DOM helpers assume a browser environment (i.e., `document` is available).
|
||||
- `addGlobalEventListener` uses event delegation; attach it once at a suitable ancestor.
|
||||
|
||||
## License
|
||||
|
||||
See the repository-level `LICENSE` file.
|
||||
102
javascript/js-extension/js-extension.js
Normal file
102
javascript/js-extension/js-extension.js
Normal file
@ -0,0 +1,102 @@
|
||||
export default class jsExtension {
|
||||
/**
|
||||
* @param {string} type
|
||||
* @param {string} selector
|
||||
* @param {Function} callback
|
||||
* @param options
|
||||
* @param {HTMLElement|Document} parent
|
||||
*/
|
||||
static addGlobalEventListener(type, selector, callback, options, parent = document) {
|
||||
parent.addEventListener(type, (eventListener) => {
|
||||
const target = eventListener.target;
|
||||
|
||||
if (!(target instanceof Element)) return;
|
||||
|
||||
if (target.matches(selector) || target.closest(selector)) {
|
||||
callback(eventListener);
|
||||
}
|
||||
}, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} type
|
||||
* @param {Object} options
|
||||
* @returns {HTMLElement}
|
||||
*/
|
||||
static createElement(type, options = {}) {
|
||||
const htmlElement = document.createElement(type);
|
||||
|
||||
for(const [_key, _value] of /** @type {[string, string][]} */Object.entries(options)) {
|
||||
|
||||
if(_key === "class") {
|
||||
htmlElement.classList.add(_value);
|
||||
break;
|
||||
}
|
||||
|
||||
if(_key === "dataset") {
|
||||
Object.entries(_value).forEach(([dataKey, dataValue]) => {
|
||||
htmlElement.dataset[dataKey] = dataValue;
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
if(_key === "text") {
|
||||
htmlElement.textContent = _value;
|
||||
break;
|
||||
}
|
||||
|
||||
htmlElement.setAttribute(_key, _value);
|
||||
}
|
||||
|
||||
return htmlElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} selector
|
||||
* @param {HTMLElement|Document} parent
|
||||
* @returns {Element|null}
|
||||
*/
|
||||
static qs(selector, parent = document) {
|
||||
return parent instanceof Document || parent instanceof HTMLElement
|
||||
? parent.querySelector(selector)
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} selector
|
||||
* @param {HTMLElement|Document} parent
|
||||
* @returns {NodeList<Element>}
|
||||
*/
|
||||
static qsa(selector, parent = document) {
|
||||
return parent instanceof Document || parent instanceof HTMLElement
|
||||
? parent.querySelectorAll(selector)
|
||||
: document.querySelectorAll(selector);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} str
|
||||
* @return {DocumentFragment}
|
||||
*/
|
||||
static strToHtml(str) {
|
||||
return document.createRange().createContextualFragment(str.trim());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param str
|
||||
* @returns {boolean}
|
||||
*/
|
||||
static isJson(str) {
|
||||
try { JSON.parse(str); } catch(e) { return false; }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} time
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
static sleep(time) {
|
||||
return new Promise(resolve => setTimeout(resolve, time));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user