Last active
August 27, 2017 19:06
-
-
Save BehindTheMath/538f898838987b6d458b3cad7d443298 to your computer and use it in GitHub Desktop.
QuerySelectorASAP
This file contains hidden or 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
| /** | |
| * Wraps <code>document.querySelector()</code> and <code>document.querySelectorAll()</code> to either: | |
| * | |
| * a) return the matching {@link Element} or {@link NodeListOf<Element>} as soon as possible: immediately if it's already | |
| * available in the DOM, or as soon as it's ready, by using <code>setInterval()</code>. | |
| * | |
| * or | |
| * | |
| * b) resolve when the specified element(s) are no longer present in the DOM. | |
| * | |
| * @param querySelector The querySelector to match | |
| * @param options an object with the following optional properties: | |
| * <pre> querySelectorAll</pre> Set true to use <code>document.querySelectorAll()</code> | |
| * <pre> negative</pre> Set to true to resolve when the specified query selector is no longer present in the DOM | |
| * <pre> timeout</pre> The interval in ms to recheck | |
| * <pre> maxIterations</pre> the maximum number of iterations to check | |
| * @returns A {@link Promise} which resolves with an {@link Element} or {@link NodeListOf<Element>} matching the specified query selector. | |
| */ | |
| function querySelectorASAP(querySelector: string, options: IQuerySelectorASAPOptions = {}): Promise<Element | NodeListOf<Element>> { | |
| return new Promise<Element | NodeListOf<Element>>((resolve, reject) => { | |
| const {querySelectorAll = false, negative = false, timeout = 100, maxIterations = (5000 / timeout)} = options; | |
| // First, check the current state | |
| let elementOrNodeListOfElements: Element | NodeListOf<Element> = querySelectorAll ? | |
| document.querySelectorAll(querySelector) : | |
| document.querySelector(querySelector); | |
| let found: boolean = elementOrNodeListOfElements !== null && (!querySelectorAll || (elementOrNodeListOfElements as NodeListOf<Element>).length >= 1); | |
| // If it's the desired state, resolve | |
| if (found === !negative) { | |
| resolve(!negative ? elementOrNodeListOfElements : null); | |
| } else { | |
| // If it's not found immediately, start looping to check for it | |
| let iterationCounter: number = 1; | |
| const interval: number = setInterval(() => { | |
| // On every loop, check for it | |
| elementOrNodeListOfElements = querySelectorAll ? | |
| document.querySelectorAll(querySelector) : | |
| document.querySelector(querySelector); | |
| found = (elementOrNodeListOfElements !== null) && (!querySelectorAll || (elementOrNodeListOfElements as NodeListOf<Element>).length >= 1); | |
| // If it's the desired state | |
| if (found === !negative) { | |
| // Stop looping | |
| clearInterval(interval); | |
| // Resolve | |
| resolve(!negative ? elementOrNodeListOfElements : null); | |
| } else { | |
| // If it's still not found, increment the counter to get ready for the next iteration | |
| iterationCounter++; | |
| // If it's past the maximum iterations | |
| if (iterationCounter > maxIterations) { | |
| // Stop checking | |
| clearInterval(interval); | |
| // Reject the Promise with an appropriate error message | |
| reject({ | |
| querySelector: querySelector, | |
| message: "Query selector was not found within the specified number of iterations." | |
| }); | |
| } | |
| } | |
| }, timeout); | |
| } | |
| }); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment