This repository has been archived by the owner on Jan 29, 2021. It is now read-only.
forked from KayLeung/dropletOnce
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
914 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,296 @@ | ||
/* once - v3.0.0 - 2020-11-18 */ | ||
var t=/[\11\12\14\15\40]+/,e="data-once";function r(e){if("string"!=typeof e)throw new TypeError("The once id parameter must be a string");if(""===e||t.test(e))throw new RangeError("The once id parameter must not be empty or contain spaces");return e}function n(t){if(!(t instanceof Element))throw new TypeError("The element must be an instance of Element");return!0}function o(t,e,r){return Array.prototype.filter.call(t,(function(t){var o=n(t)&&t.matches(e);return o&&r&&r(t),o}))}function a(e){var r=e.value,n=e.add,o=e.remove,a=[];return r.trim().split(t).forEach((function(t){a.indexOf(t)<0&&t!==o&&a.push(t)})),n&&a.push(n),a.join(" ")}function u(t,n){var u=r(t);return o(n,':not([data-once~="'+u+'"])',(function(t){var r=u;t.hasAttribute(e)&&(r=a({value:t.getAttribute(e),add:u})),t.setAttribute(e,r)}))}u.remove=function(t,n){var u=r(t);return o(n,'[data-once~="'+u+'"]',(function(t){var r=a({value:t.getAttribute(e),remove:u});""===r?t.removeAttribute(e):t.setAttribute(e,r)}))},u.filter=function(t,e){return o(e,'[data-once~="'+r(t)+'"]')},u.find=function(t,e){void 0===e&&(e=document.documentElement);var o=r(t);return n(e)&&Array.prototype.slice.call(e.querySelectorAll('[data-once~="'+o+'"]'))};export default u; | ||
/* once - v3.1.0 - 2020-11-18 */ | ||
/** | ||
* Mark DOM elements as processed to prevent multiple initializations. | ||
* | ||
* @module once-dom | ||
* | ||
* @example <caption>Use as a module</caption> | ||
* <script type="module"> | ||
* import once from "https://unpkg.com/once-dom@latest/dist/once.esm.js"; | ||
* const elements = once("my-id", document.querySelectorAll("div")); | ||
* // Initialize elements. | ||
* elements.forEach(el => el.innerHTML = "processed"); | ||
* </script> | ||
* | ||
* @example <caption>Use as a regular script</caption> | ||
* <script src="https://unpkg.com/once-dom@latest/dist/once.min.js"></script> | ||
* <script> | ||
* const elements = once("my-id", document.querySelectorAll("div")); | ||
* // Initialize elements. | ||
* elements.forEach(el => el.innerHTML = "processed"); | ||
* </script> | ||
*/ | ||
|
||
/** | ||
* Illegal spaces in ids. | ||
* | ||
* @private | ||
* | ||
* @type {RegExp} | ||
*/ | ||
const wsRE = /[\11\12\14\15\40]+/; | ||
|
||
/** | ||
* Name of the HTML attribute containing an element's once ids. | ||
* | ||
* @private | ||
* | ||
* @type {string} | ||
*/ | ||
const attrName = 'data-once'; | ||
|
||
/** | ||
* Verify the validity of the once id. | ||
* | ||
* @private | ||
* | ||
* @param {string} id | ||
* The id passed by a call to a once() function. | ||
* | ||
* @return {string} | ||
* A valid id, used for indicating an element has been processed. | ||
* | ||
* @throws {TypeError|RangeError} | ||
*/ | ||
function checkId(id) { | ||
if (typeof id !== 'string') { | ||
throw new TypeError('The once id parameter must be a string'); | ||
} | ||
if (id === '' || wsRE.test(id)) { | ||
throw new RangeError( | ||
'The once id parameter must not be empty or contain spaces', | ||
); | ||
} | ||
return id; | ||
} | ||
|
||
/** | ||
* Verifies that an item is an instance of Element. | ||
* | ||
* This function is used during filtering to ensure only DOM elements are | ||
* processed. once() makes use of get/setAttribute, which are methods | ||
* inherited from the Element object, so only of Element can be used. | ||
* | ||
* @private | ||
* | ||
* @param {*} itemToCheck | ||
* The item to check. | ||
* | ||
* @return {bool} | ||
* True if the item is an instance of Element | ||
* | ||
* @throws {TypeError} | ||
*/ | ||
function checkElement(itemToCheck) { | ||
if (!(itemToCheck instanceof Element)) { | ||
throw new TypeError('The element must be an instance of Element'); | ||
} | ||
return true; | ||
} | ||
|
||
/** | ||
* A helper for applying DOM changes to a filtered set of elements. | ||
* | ||
* This makes it possible to filter items that are not instances of Element, | ||
* then modify their DOM attributes in a single array traversal. | ||
* | ||
* @private | ||
* | ||
* @param {NodeList|Array.<Element>} elements | ||
* A NodeList or array of elements passed by a call to a once() function. | ||
* @param {string} selector | ||
* A CSS selector to check against to each element in the array. | ||
* @param {function} [apply] | ||
* An optional function to apply on all matched elements. | ||
* | ||
* @return {Array.<Element>} | ||
* The array of elements that match the CSS selector. | ||
*/ | ||
function filterAndModify(elements, selector, apply) { | ||
return Array.prototype.filter.call(elements, element => { | ||
const selected = checkElement(element) && element.matches(selector); | ||
if (selected && apply) { | ||
apply(element); | ||
} | ||
return selected; | ||
}); | ||
} | ||
|
||
/** | ||
* Add or remove an item from a list of once values. | ||
* | ||
* This function removes duplicates while adding or removing a once id in a | ||
* single array traversal. | ||
* | ||
* @private | ||
* | ||
* @param {string} value | ||
* A space separated string of once ids from a data-drupal-once attribute. | ||
* @param {string} add | ||
* The once id to add to the list of values. | ||
* @param {string} remove | ||
* The once id to remove from the list of values. | ||
* | ||
* @return {string} | ||
* A space separated string of once ids, to be assigned to a | ||
* data-drupal-once attribute value. | ||
*/ | ||
function updateAttribute({ value, add, remove }) { | ||
const result = []; | ||
value | ||
.trim() | ||
.split(wsRE) | ||
.forEach(item => { | ||
if (result.indexOf(item) < 0 && item !== remove) { | ||
result.push(item); | ||
} | ||
}); | ||
if (add) { | ||
result.push(add); | ||
} | ||
return result.join(' '); | ||
} | ||
|
||
/** | ||
* Ensures a JavaScript callback is only executed once on a set of elements. | ||
* | ||
* Filters a NodeList or array of elements, removing those already processed | ||
* by a callback with a given id. | ||
* This method adds a `data-once` attribute on DOM elements. The value of | ||
* this attribute identifies if a given callback has been executed on that | ||
* element. | ||
* | ||
* @global | ||
* | ||
* @example | ||
* const elements = once( | ||
* 'my-once-id', | ||
* document.querySelectorAll('[data-myelement]'), | ||
* ); | ||
* | ||
* @param {string} id | ||
* The id of the once call. | ||
* @param {NodeList|Array.<Element>} elements | ||
* A NodeList or array of elements. | ||
* | ||
* @return {Array.<Element>} | ||
* An array of elements that have not yet been processed by a once call | ||
* with a given id. | ||
*/ | ||
function once(id, elements) { | ||
const dataId = checkId(id); | ||
return filterAndModify( | ||
elements, | ||
`:not([${attrName}~="${dataId}"])`, | ||
element => { | ||
let value = dataId; | ||
if (element.hasAttribute(attrName)) { | ||
value = updateAttribute({ | ||
value: element.getAttribute(attrName), | ||
add: dataId, | ||
}); | ||
} | ||
element.setAttribute(attrName, value); | ||
}, | ||
); | ||
} | ||
|
||
/** | ||
* Removes a once id from an element's data-drupal-once attribute value. | ||
* | ||
* If a once id is removed from an element's data-drupal-once attribute value, | ||
* the JavaScript callback associated with that id can be executed on that | ||
* element again. | ||
* | ||
* @method once.remove | ||
* | ||
* @example | ||
* const removedOnceElements = once.remove( | ||
* 'my-once-id', | ||
* document.querySelectorAll('[data-myelement]'), | ||
* ); | ||
* | ||
* @param {string} id | ||
* The id of a once call. | ||
* @param {NodeList|Array.<Element>} elements | ||
* A NodeList or array of elements to remove the once id from. | ||
* | ||
* @return {Array.<Element>} | ||
* A filtered array of elements that had been processed by the provided id, | ||
* and are now able to be processed again. | ||
*/ | ||
once.remove = (id, elements) => { | ||
const dataId = checkId(id); | ||
return filterAndModify(elements, `[${attrName}~="${dataId}"]`, element => { | ||
const value = updateAttribute({ | ||
value: element.getAttribute(attrName), | ||
remove: dataId, | ||
}); | ||
if (value === '') { | ||
element.removeAttribute(attrName); | ||
} else { | ||
element.setAttribute(attrName, value); | ||
} | ||
}); | ||
}; | ||
|
||
/** | ||
* Finds elements that have been processed by a given once id. | ||
* | ||
* Filters a NodeList or array, returning an array of the elements already | ||
* processed by the provided once id. | ||
* | ||
* @method once.filter | ||
* | ||
* @example | ||
* const filteredElements = once.filter( | ||
* 'my-once-id', | ||
* document.querySelectorAll('[data-myelement]'), | ||
* ); | ||
* | ||
* @param {string} id | ||
* The id of the once call. | ||
* @param {NodeList|Array.<Element>} elements | ||
* A NodeList or array of elements to be searched. | ||
* | ||
* @return {Array.<Element>} | ||
* A filtered array of elements that have already been processed by the | ||
* provided once id. | ||
*/ | ||
once.filter = (id, elements) => { | ||
const dataId = checkId(id); | ||
return filterAndModify(elements, `[${attrName}~="${dataId}"]`); | ||
}; | ||
|
||
/** | ||
* Finds elements that have been processed by a given once id. | ||
* | ||
* Query the 'context' element for elements that already have the | ||
* corresponding once id value. | ||
* | ||
* @method once.find | ||
* | ||
* @example | ||
* const oncedElements = once.find('my-once-id'); | ||
* | ||
* @param {string} id | ||
* The id of the once call. | ||
* @param {Element} [context=document.documentElement] | ||
* Scope of the search for matching elements. | ||
* | ||
* @return {Array.<Element>} | ||
* A filtered array of elements that have already been processed by the | ||
* provided once id. | ||
*/ | ||
once.find = (id, context = document.documentElement) => { | ||
const dataId = checkId(id); | ||
return ( | ||
checkElement(context) && | ||
// Ensure the return is an Array and not a NodeList. | ||
Array.prototype.slice.call( | ||
context.querySelectorAll(`[${attrName}~="${dataId}"]`), | ||
) | ||
); | ||
}; | ||
|
||
export default once; |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.