diff options
| author | 2023-12-15 10:08:56 +0800 | |
|---|---|---|
| committer | 2023-12-15 10:08:56 +0800 | |
| commit | d697a1774ad8571e9314e3bd85aa141170587d19 (patch) | |
| tree | cd3c3d84e3288db1f8e574a0b4dfb85e2e40f764 /src/templates/assets/javascripts/browser | |
| parent | 4943d5eff52a75caaccda6a1d84183032f06be26 (diff) | |
| parent | 4dafb0f0a81255193f2a44df5d203239325e2236 (diff) | |
| download | infini-d697a1774ad8571e9314e3bd85aa141170587d19.tar.gz infini-d697a1774ad8571e9314e3bd85aa141170587d19.zip | |
Merge branch 'master' into master
Diffstat (limited to 'src/templates/assets/javascripts/browser')
27 files changed, 0 insertions, 2082 deletions
diff --git a/src/templates/assets/javascripts/browser/document/index.ts b/src/templates/assets/javascripts/browser/document/index.ts deleted file mode 100644 index 354c9b5c..00000000 --- a/src/templates/assets/javascripts/browser/document/index.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -import { - ReplaySubject, - Subject, - fromEvent -} from "rxjs" - -/* ---------------------------------------------------------------------------- - * Functions - * ------------------------------------------------------------------------- */ - -/** - * Watch document - * - * Documents are implemented as subjects, so all downstream observables are - * automatically updated when a new document is emitted. - * - * @returns Document subject - */ -export function watchDocument(): Subject<Document> { - const document$ = new ReplaySubject<Document>(1) - fromEvent(document, "DOMContentLoaded", { once: true }) - .subscribe(() => document$.next(document)) - - /* Return document */ - return document$ -} diff --git a/src/templates/assets/javascripts/browser/element/_/.eslintrc b/src/templates/assets/javascripts/browser/element/_/.eslintrc deleted file mode 100644 index 16973760..00000000 --- a/src/templates/assets/javascripts/browser/element/_/.eslintrc +++ /dev/null @@ -1,6 +0,0 @@ -{ - "rules": { - "jsdoc/require-jsdoc": "off", - "jsdoc/require-returns-check": "off" - } -} diff --git a/src/templates/assets/javascripts/browser/element/_/index.ts b/src/templates/assets/javascripts/browser/element/_/index.ts deleted file mode 100644 index b7beb462..00000000 --- a/src/templates/assets/javascripts/browser/element/_/index.ts +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -/* ---------------------------------------------------------------------------- - * Functions - * ------------------------------------------------------------------------- */ - -/** - * Retrieve all elements matching the query selector - * - * @template T - Element type - * - * @param selector - Query selector - * @param node - Node of reference - * - * @returns Elements - */ -export function getElements<T extends keyof HTMLElementTagNameMap>( - selector: T, node?: ParentNode -): HTMLElementTagNameMap[T][] - -export function getElements<T extends HTMLElement>( - selector: string, node?: ParentNode -): T[] - -export function getElements<T extends HTMLElement>( - selector: string, node: ParentNode = document -): T[] { - return Array.from(node.querySelectorAll<T>(selector)) -} - -/** - * Retrieve an element matching a query selector or throw a reference error - * - * Note that this function assumes that the element is present. If unsure if an - * element is existent, use the `getOptionalElement` function instead. - * - * @template T - Element type - * - * @param selector - Query selector - * @param node - Node of reference - * - * @returns Element - */ -export function getElement<T extends keyof HTMLElementTagNameMap>( - selector: T, node?: ParentNode -): HTMLElementTagNameMap[T] - -export function getElement<T extends HTMLElement>( - selector: string, node?: ParentNode -): T - -export function getElement<T extends HTMLElement>( - selector: string, node: ParentNode = document -): T { - const el = getOptionalElement<T>(selector, node) - if (typeof el === "undefined") - throw new ReferenceError( - `Missing element: expected "${selector}" to be present` - ) - - /* Return element */ - return el -} - -/* ------------------------------------------------------------------------- */ - -/** - * Retrieve an optional element matching the query selector - * - * @template T - Element type - * - * @param selector - Query selector - * @param node - Node of reference - * - * @returns Element or nothing - */ -export function getOptionalElement<T extends keyof HTMLElementTagNameMap>( - selector: T, node?: ParentNode -): HTMLElementTagNameMap[T] | undefined - -export function getOptionalElement<T extends HTMLElement>( - selector: string, node?: ParentNode -): T | undefined - -export function getOptionalElement<T extends HTMLElement>( - selector: string, node: ParentNode = document -): T | undefined { - return node.querySelector<T>(selector) || undefined -} - -/** - * Retrieve the currently active element - * - * @returns Element or nothing - */ -export function getActiveElement(): HTMLElement | undefined { - return document.activeElement instanceof HTMLElement - ? document.activeElement || undefined - : undefined -} diff --git a/src/templates/assets/javascripts/browser/element/focus/index.ts b/src/templates/assets/javascripts/browser/element/focus/index.ts deleted file mode 100644 index f31fe276..00000000 --- a/src/templates/assets/javascripts/browser/element/focus/index.ts +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -import { - Observable, - debounceTime, - distinctUntilChanged, - fromEvent, - map, - merge, - shareReplay, - startWith -} from "rxjs" - -import { getActiveElement } from "../_" - -/* ---------------------------------------------------------------------------- - * Data - * ------------------------------------------------------------------------- */ - -/** - * Focus observable - * - * Previously, this observer used `focus` and `blur` events to determine whether - * an element is focused, but this doesn't work if there are focusable elements - * within the elements itself. A better solutions are `focusin` and `focusout` - * events, which bubble up the tree and allow for more fine-grained control. - * - * `debounceTime` is necessary, because when a focus change happens inside an - * element, the observable would first emit `false` and then `true` again. - */ -const observer$ = merge( - fromEvent(document.body, "focusin"), - fromEvent(document.body, "focusout") -) - .pipe( - debounceTime(1), - startWith(undefined), - map(() => getActiveElement() || document.body), - shareReplay(1) - ) - -/* ---------------------------------------------------------------------------- - * Functions - * ------------------------------------------------------------------------- */ - -/** - * Watch element focus - * - * @param el - Element - * - * @returns Element focus observable - */ -export function watchElementFocus( - el: HTMLElement -): Observable<boolean> { - return observer$ - .pipe( - map(active => el.contains(active)), - distinctUntilChanged() - ) -} diff --git a/src/templates/assets/javascripts/browser/element/index.ts b/src/templates/assets/javascripts/browser/element/index.ts deleted file mode 100644 index 50ce84b2..00000000 --- a/src/templates/assets/javascripts/browser/element/index.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -export * from "./_" -export * from "./focus" -export * from "./offset" -export * from "./size" -export * from "./visibility" diff --git a/src/templates/assets/javascripts/browser/element/offset/_/index.ts b/src/templates/assets/javascripts/browser/element/offset/_/index.ts deleted file mode 100644 index 6dd229d5..00000000 --- a/src/templates/assets/javascripts/browser/element/offset/_/index.ts +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -import { - Observable, - animationFrameScheduler, - auditTime, - fromEvent, - map, - merge, - startWith -} from "rxjs" - -/* ---------------------------------------------------------------------------- - * Types - * ------------------------------------------------------------------------- */ - -/** - * Element offset - */ -export interface ElementOffset { - x: number /* Horizontal offset */ - y: number /* Vertical offset */ -} - -/* ---------------------------------------------------------------------------- - * Functions - * ------------------------------------------------------------------------- */ - -/** - * Retrieve element offset - * - * @param el - Element - * - * @returns Element offset - */ -export function getElementOffset( - el: HTMLElement -): ElementOffset { - return { - x: el.offsetLeft, - y: el.offsetTop - } -} - -/* ------------------------------------------------------------------------- */ - -/** - * Watch element offset - * - * @param el - Element - * - * @returns Element offset observable - */ -export function watchElementOffset( - el: HTMLElement -): Observable<ElementOffset> { - return merge( - fromEvent(window, "load"), - fromEvent(window, "resize") - ) - .pipe( - auditTime(0, animationFrameScheduler), - map(() => getElementOffset(el)), - startWith(getElementOffset(el)) - ) -} diff --git a/src/templates/assets/javascripts/browser/element/offset/content/index.ts b/src/templates/assets/javascripts/browser/element/offset/content/index.ts deleted file mode 100644 index 557301a6..00000000 --- a/src/templates/assets/javascripts/browser/element/offset/content/index.ts +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -import { - Observable, - animationFrameScheduler, - auditTime, - fromEvent, - map, - merge, - startWith -} from "rxjs" - -import { ElementOffset } from "../_" - -/* ---------------------------------------------------------------------------- - * Functions - * ------------------------------------------------------------------------- */ - -/** - * Retrieve element content offset (= scroll offset) - * - * @param el - Element - * - * @returns Element content offset - */ -export function getElementContentOffset( - el: HTMLElement -): ElementOffset { - return { - x: el.scrollLeft, - y: el.scrollTop - } -} - -/* ------------------------------------------------------------------------- */ - -/** - * Watch element content offset - * - * @param el - Element - * - * @returns Element content offset observable - */ -export function watchElementContentOffset( - el: HTMLElement -): Observable<ElementOffset> { - return merge( - fromEvent(el, "scroll"), - fromEvent(window, "resize") - ) - .pipe( - auditTime(0, animationFrameScheduler), - map(() => getElementContentOffset(el)), - startWith(getElementContentOffset(el)) - ) -} diff --git a/src/templates/assets/javascripts/browser/element/offset/index.ts b/src/templates/assets/javascripts/browser/element/offset/index.ts deleted file mode 100644 index 602ff2cf..00000000 --- a/src/templates/assets/javascripts/browser/element/offset/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -export * from "./_" -export * from "./content" diff --git a/src/templates/assets/javascripts/browser/element/size/_/index.ts b/src/templates/assets/javascripts/browser/element/size/_/index.ts deleted file mode 100644 index 35a5e68b..00000000 --- a/src/templates/assets/javascripts/browser/element/size/_/index.ts +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -import { - NEVER, - Observable, - Subject, - defer, - filter, - finalize, - map, - merge, - of, - shareReplay, - startWith, - switchMap, - tap -} from "rxjs" - -import { watchScript } from "../../../script" - -/* ---------------------------------------------------------------------------- - * Types - * ------------------------------------------------------------------------- */ - -/** - * Element offset - */ -export interface ElementSize { - width: number /* Element width */ - height: number /* Element height */ -} - -/* ---------------------------------------------------------------------------- - * Data - * ------------------------------------------------------------------------- */ - -/** - * Resize observer entry subject - */ -const entry$ = new Subject<ResizeObserverEntry>() - -/** - * Resize observer observable - * - * This observable will create a `ResizeObserver` on the first subscription - * and will automatically terminate it when there are no more subscribers. - * It's quite important to centralize observation in a single `ResizeObserver`, - * as the performance difference can be quite dramatic, as the link shows. - * - * If the browser doesn't have a `ResizeObserver` implementation available, a - * polyfill is automatically downloaded from unpkg.com. This is also compatible - * with the built-in privacy plugin, which will download the polyfill and put - * it alongside the built site for self-hosting. - * - * @see https://bit.ly/3iIYfEm - Google Groups on performance - */ -const observer$ = defer(() => ( - typeof ResizeObserver === "undefined" - ? watchScript("https://unpkg.com/resize-observer-polyfill") - : of(undefined) -)) - .pipe( - map(() => new ResizeObserver(entries => { - for (const entry of entries) - entry$.next(entry) - })), - switchMap(observer => merge(NEVER, of(observer)) - .pipe( - finalize(() => observer.disconnect()) - ) - ), - shareReplay(1) - ) - -/* ---------------------------------------------------------------------------- - * Functions - * ------------------------------------------------------------------------- */ - -/** - * Retrieve element size - * - * @param el - Element - * - * @returns Element size - */ -export function getElementSize( - el: HTMLElement -): ElementSize { - return { - width: el.offsetWidth, - height: el.offsetHeight - } -} - -/* ------------------------------------------------------------------------- */ - -/** - * Watch element size - * - * This function returns an observable that subscribes to a single internal - * instance of `ResizeObserver` upon subscription, and emit resize events until - * termination. Note that this function should not be called with the same - * element twice, as the first unsubscription will terminate observation. - * - * Sadly, we can't use the `DOMRect` objects returned by the observer, because - * we need the emitted values to be consistent with `getElementSize`, which will - * return the used values (rounded) and not actual values (unrounded). Thus, we - * use the `offset*` properties. See the linked GitHub issue. - * - * @see https://bit.ly/3m0k3he - GitHub issue - * - * @param el - Element - * - * @returns Element size observable - */ -export function watchElementSize( - el: HTMLElement -): Observable<ElementSize> { - return observer$ - .pipe( - tap(observer => observer.observe(el)), - switchMap(observer => entry$ - .pipe( - filter(({ target }) => target === el), - finalize(() => observer.unobserve(el)), - map(() => getElementSize(el)) - ) - ), - startWith(getElementSize(el)) - ) -} diff --git a/src/templates/assets/javascripts/browser/element/size/content/index.ts b/src/templates/assets/javascripts/browser/element/size/content/index.ts deleted file mode 100644 index 5ed388cf..00000000 --- a/src/templates/assets/javascripts/browser/element/size/content/index.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -import { ElementSize } from "../_" - -/* ---------------------------------------------------------------------------- - * Functions - * ------------------------------------------------------------------------- */ - -/** - * Retrieve element content size (= scroll width and height) - * - * @param el - Element - * - * @returns Element content size - */ -export function getElementContentSize( - el: HTMLElement -): ElementSize { - return { - width: el.scrollWidth, - height: el.scrollHeight - } -} - -/** - * Retrieve the overflowing container of an element, if any - * - * @param el - Element - * - * @returns Overflowing container or nothing - */ -export function getElementContainer( - el: HTMLElement -): HTMLElement | undefined { - let parent = el.parentElement - while (parent) - if ( - el.scrollWidth <= parent.scrollWidth && - el.scrollHeight <= parent.scrollHeight - ) - parent = (el = parent).parentElement - else - break - - /* Return overflowing container */ - return parent ? el : undefined -} diff --git a/src/templates/assets/javascripts/browser/element/size/index.ts b/src/templates/assets/javascripts/browser/element/size/index.ts deleted file mode 100644 index 602ff2cf..00000000 --- a/src/templates/assets/javascripts/browser/element/size/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -export * from "./_" -export * from "./content" diff --git a/src/templates/assets/javascripts/browser/element/visibility/index.ts b/src/templates/assets/javascripts/browser/element/visibility/index.ts deleted file mode 100644 index 1ffe0b8d..00000000 --- a/src/templates/assets/javascripts/browser/element/visibility/index.ts +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -import { - NEVER, - Observable, - Subject, - defer, - distinctUntilChanged, - filter, - finalize, - map, - merge, - of, - shareReplay, - switchMap, - tap -} from "rxjs" - -import { - getElementContentSize, - getElementSize, - watchElementContentOffset -} from "~/browser" - -/* ---------------------------------------------------------------------------- - * Data - * ------------------------------------------------------------------------- */ - -/** - * Intersection observer entry subject - */ -const entry$ = new Subject<IntersectionObserverEntry>() - -/** - * Intersection observer observable - * - * This observable will create an `IntersectionObserver` on first subscription - * and will automatically terminate it when there are no more subscribers. - * - * @see https://bit.ly/3iIYfEm - Google Groups on performance - */ -const observer$ = defer(() => of( - new IntersectionObserver(entries => { - for (const entry of entries) - entry$.next(entry) - }, { - threshold: 0 - }) -)) - .pipe( - switchMap(observer => merge(NEVER, of(observer)) - .pipe( - finalize(() => observer.disconnect()) - ) - ), - shareReplay(1) - ) - -/* ---------------------------------------------------------------------------- - * Functions - * ------------------------------------------------------------------------- */ - -/** - * Watch element visibility - * - * @param el - Element - * - * @returns Element visibility observable - */ -export function watchElementVisibility( - el: HTMLElement -): Observable<boolean> { - return observer$ - .pipe( - tap(observer => observer.observe(el)), - switchMap(observer => entry$ - .pipe( - filter(({ target }) => target === el), - finalize(() => observer.unobserve(el)), - map(({ isIntersecting }) => isIntersecting) - ) - ) - ) -} - -/** - * Watch element boundary - * - * This function returns an observable which emits whether the bottom content - * boundary (= scroll offset) of an element is within a certain threshold. - * - * @param el - Element - * @param threshold - Threshold - * - * @returns Element boundary observable - */ -export function watchElementBoundary( - el: HTMLElement, threshold = 16 -): Observable<boolean> { - return watchElementContentOffset(el) - .pipe( - map(({ y }) => { - const visible = getElementSize(el) - const content = getElementContentSize(el) - return y >= ( - content.height - visible.height - threshold - ) - }), - distinctUntilChanged() - ) -} diff --git a/src/templates/assets/javascripts/browser/index.ts b/src/templates/assets/javascripts/browser/index.ts deleted file mode 100644 index f1ee2bae..00000000 --- a/src/templates/assets/javascripts/browser/index.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -export * from "./document" -export * from "./element" -export * from "./keyboard" -export * from "./location" -export * from "./media" -export * from "./request" -export * from "./script" -export * from "./toggle" -export * from "./viewport" -export * from "./worker" diff --git a/src/templates/assets/javascripts/browser/keyboard/index.ts b/src/templates/assets/javascripts/browser/keyboard/index.ts deleted file mode 100644 index 783f2cda..00000000 --- a/src/templates/assets/javascripts/browser/keyboard/index.ts +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -import { - EMPTY, - Observable, - filter, - fromEvent, - map, - merge, - share, - startWith, - switchMap -} from "rxjs" - -import { getActiveElement } from "../element" -import { getToggle } from "../toggle" - -/* ---------------------------------------------------------------------------- - * Types - * ------------------------------------------------------------------------- */ - -/** - * Keyboard mode - */ -export type KeyboardMode = - | "global" /* Global */ - | "search" /* Search is open */ - -/* ------------------------------------------------------------------------- */ - -/** - * Keyboard - */ -export interface Keyboard { - mode: KeyboardMode /* Keyboard mode */ - type: string /* Key type */ - claim(): void /* Key claim */ -} - -/* ---------------------------------------------------------------------------- - * Helper functions - * ------------------------------------------------------------------------- */ - -/** - * Check whether an element may receive keyboard input - * - * @param el - Element - * @param type - Key type - * - * @returns Test result - */ -function isSusceptibleToKeyboard( - el: HTMLElement, type: string -): boolean { - switch (el.constructor) { - - /* Input elements */ - case HTMLInputElement: - /* @ts-expect-error - omit unnecessary type cast */ - if (el.type === "radio") - return /^Arrow/.test(type) - else - return true - - /* Select element and textarea */ - case HTMLSelectElement: - case HTMLTextAreaElement: - return true - - /* Everything else */ - default: - return el.isContentEditable - } -} - -/* ---------------------------------------------------------------------------- - * Functions - * ------------------------------------------------------------------------- */ - -/** - * Watch composition events - * - * @returns Composition observable - */ -export function watchComposition(): Observable<boolean> { - return merge( - fromEvent(window, "compositionstart").pipe(map(() => true)), - fromEvent(window, "compositionend").pipe(map(() => false)) - ) - .pipe( - startWith(false) - ) -} - -/** - * Watch keyboard - * - * @returns Keyboard observable - */ -export function watchKeyboard(): Observable<Keyboard> { - const keyboard$ = fromEvent<KeyboardEvent>(window, "keydown") - .pipe( - filter(ev => !(ev.metaKey || ev.ctrlKey)), - map(ev => ({ - mode: getToggle("search") ? "search" : "global", - type: ev.key, - claim() { - ev.preventDefault() - ev.stopPropagation() - } - } as Keyboard)), - filter(({ mode, type }) => { - if (mode === "global") { - const active = getActiveElement() - if (typeof active !== "undefined") - return !isSusceptibleToKeyboard(active, type) - } - return true - }), - share() - ) - - /* Don't emit during composition events - see https://bit.ly/3te3Wl8 */ - return watchComposition() - .pipe( - switchMap(active => !active ? keyboard$ : EMPTY) - ) -} diff --git a/src/templates/assets/javascripts/browser/location/_/index.ts b/src/templates/assets/javascripts/browser/location/_/index.ts deleted file mode 100644 index 2672fa74..00000000 --- a/src/templates/assets/javascripts/browser/location/_/index.ts +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -import { Subject } from "rxjs" - -import { feature } from "~/_" -import { h } from "~/utilities" - -/* ---------------------------------------------------------------------------- - * Functions - * ------------------------------------------------------------------------- */ - -/** - * Retrieve location - * - * This function returns a `URL` object (and not `Location`) to normalize the - * typings across the application. Furthermore, locations need to be tracked - * without setting them and `Location` is a singleton which represents the - * current location. - * - * @returns URL - */ -export function getLocation(): URL { - return new URL(location.href) -} - -/** - * Set location - * - * If instant navigation is enabled, this function creates a temporary anchor - * element, sets the `href` attribute, appends it to the body, clicks it, and - * then removes it again. The event will bubble up the DOM and trigger be - * intercepted by the instant loading business logic. - * - * Note that we must append and remove the anchor element, or the event will - * not bubble up the DOM, making it impossible to intercept it. - * - * @param url - URL to navigate to - * @param navigate - Force navigation - */ -export function setLocation( - url: URL | HTMLLinkElement, navigate = false -): void { - if (feature("navigation.instant") && !navigate) { - const el = h("a", { href: url.href }) - document.body.appendChild(el) - el.click() - el.remove() - - // If we're not using instant navigation, and the page should not be reloaded - // just instruct the browser to navigate to the given URL - } else { - location.href = url.href - } -} - -/* ------------------------------------------------------------------------- */ - -/** - * Watch location - * - * @returns Location subject - */ -export function watchLocation(): Subject<URL> { - return new Subject<URL>() -} diff --git a/src/templates/assets/javascripts/browser/location/hash/index.ts b/src/templates/assets/javascripts/browser/location/hash/index.ts deleted file mode 100644 index 5d3a134a..00000000 --- a/src/templates/assets/javascripts/browser/location/hash/index.ts +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -import { - Observable, - filter, - fromEvent, - map, - merge, - shareReplay, - startWith -} from "rxjs" - -import { getOptionalElement } from "~/browser" -import { h } from "~/utilities" - -/* ---------------------------------------------------------------------------- - * Functions - * ------------------------------------------------------------------------- */ - -/** - * Retrieve location hash - * - * @returns Location hash - */ -export function getLocationHash(): string { - return location.hash.slice(1) -} - -/** - * Set location hash - * - * Setting a new fragment identifier via `location.hash` will have no effect - * if the value doesn't change. When a new fragment identifier is set, we want - * the browser to target the respective element at all times, which is why we - * use this dirty little trick. - * - * @param hash - Location hash - */ -export function setLocationHash(hash: string): void { - const el = h("a", { href: hash }) - el.addEventListener("click", ev => ev.stopPropagation()) - el.click() -} - -/* ------------------------------------------------------------------------- */ - -/** - * Watch location hash - * - * @param location$ - Location observable - * - * @returns Location hash observable - */ -export function watchLocationHash( - location$: Observable<URL> -): Observable<string> { - return merge( - fromEvent<HashChangeEvent>(window, "hashchange"), - location$ - ) - .pipe( - map(getLocationHash), - startWith(getLocationHash()), - filter(hash => hash.length > 0), - shareReplay(1) - ) -} - -/** - * Watch location target - * - * @param location$ - Location observable - * - * @returns Location target observable - */ -export function watchLocationTarget( - location$: Observable<URL> -): Observable<HTMLElement> { - return watchLocationHash(location$) - .pipe( - map(id => getOptionalElement(`[id="${id}"]`)!), - filter(el => typeof el !== "undefined") - ) -} diff --git a/src/templates/assets/javascripts/browser/location/index.ts b/src/templates/assets/javascripts/browser/location/index.ts deleted file mode 100644 index d77a5444..00000000 --- a/src/templates/assets/javascripts/browser/location/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -export * from "./_" -export * from "./hash" diff --git a/src/templates/assets/javascripts/browser/media/index.ts b/src/templates/assets/javascripts/browser/media/index.ts deleted file mode 100644 index dd7400d4..00000000 --- a/src/templates/assets/javascripts/browser/media/index.ts +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -import { - EMPTY, - Observable, - fromEvent, - fromEventPattern, - map, - merge, - startWith, - switchMap -} from "rxjs" - -/* ---------------------------------------------------------------------------- - * Functions - * ------------------------------------------------------------------------- */ - -/** - * Watch media query - * - * Note that although `MediaQueryList.addListener` is deprecated we have to - * use it, because it's the only way to ensure proper downward compatibility. - * - * @see https://bit.ly/3dUBH2m - GitHub issue - * - * @param query - Media query - * - * @returns Media observable - */ -export function watchMedia(query: string): Observable<boolean> { - const media = matchMedia(query) - return fromEventPattern<boolean>(next => ( - media.addListener(() => next(media.matches)) - )) - .pipe( - startWith(media.matches) - ) -} - -/** - * Watch print mode - * - * @returns Print observable - */ -export function watchPrint(): Observable<boolean> { - const media = matchMedia("print") - return merge( - fromEvent(window, "beforeprint").pipe(map(() => true)), - fromEvent(window, "afterprint").pipe(map(() => false)) - ) - .pipe( - startWith(media.matches) - ) -} - -/* ------------------------------------------------------------------------- */ - -/** - * Toggle an observable with a media observable - * - * @template T - Data type - * - * @param query$ - Media observable - * @param factory - Observable factory - * - * @returns Toggled observable - */ -export function at<T>( - query$: Observable<boolean>, factory: () => Observable<T> -): Observable<T> { - return query$ - .pipe( - switchMap(active => active ? factory() : EMPTY) - ) -} diff --git a/src/templates/assets/javascripts/browser/request/index.ts b/src/templates/assets/javascripts/browser/request/index.ts deleted file mode 100644 index 74a56a64..00000000 --- a/src/templates/assets/javascripts/browser/request/index.ts +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -import { - Observable, - Subject, - map, - shareReplay, - switchMap -} from "rxjs" - -/* ---------------------------------------------------------------------------- - * Helper types - * ------------------------------------------------------------------------- */ - -/** - * Options - */ -interface Options { - progress$?: Subject<number> // Progress subject -} - -/* ---------------------------------------------------------------------------- - * Functions - * ------------------------------------------------------------------------- */ - -/** - * Fetch the given URL - * - * If the request fails (e.g. when dispatched from `file://` locations), the - * observable will complete without emitting a value. - * - * @param url - Request URL - * @param options - Options - * - * @returns Response observable - */ -export function request( - url: URL | string, options?: Options -): Observable<Blob> { - return new Observable<Blob>(observer => { - const req = new XMLHttpRequest() - req.open("GET", `${url}`) - req.responseType = "blob" - - // Handle response - req.addEventListener("load", () => { - if (req.status >= 200 && req.status < 300) { - observer.next(req.response) - observer.complete() - } else { - observer.error(new Error(req.statusText)) - } - }) - - // Handle network errors - req.addEventListener("error", () => { - observer.error(new Error("Network Error")) - }) - - // Handle aborted requests - req.addEventListener("abort", () => { - observer.error(new Error("Request aborted")) - }) - - // Handle download progress - if (typeof options?.progress$ !== "undefined") { - req.addEventListener("progress", event => { - options.progress$!.next((event.loaded / event.total) * 100) - }) - - // Immediately set progress to 5% to indicate that we're loading - options.progress$.next(5) - } - - // Send request - req.send() - }) -} - -/* ------------------------------------------------------------------------- */ - -/** - * Fetch JSON from the given URL - * - * @template T - Data type - * - * @param url - Request URL - * @param options - Options - * - * @returns Data observable - */ -export function requestJSON<T>( - url: URL | string, options?: Options -): Observable<T> { - return request(url, options) - .pipe( - switchMap(res => res.text()), - map(body => JSON.parse(body) as T), - shareReplay(1) - ) -} - -/** - * Fetch XML from the given URL - * - * @param url - Request URL - * @param options - Options - * - * @returns Data observable - */ -export function requestXML( - url: URL | string, options?: Options -): Observable<Document> { - const dom = new DOMParser() - return request(url, options) - .pipe( - switchMap(res => res.text()), - map(res => dom.parseFromString(res, "text/xml")), - shareReplay(1) - ) -} diff --git a/src/templates/assets/javascripts/browser/script/index.ts b/src/templates/assets/javascripts/browser/script/index.ts deleted file mode 100644 index ef5c89e6..00000000 --- a/src/templates/assets/javascripts/browser/script/index.ts +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -import { - Observable, - defer, - finalize, - fromEvent, - map, - merge, - switchMap, - take, - throwError -} from "rxjs" - -import { h } from "~/utilities" - -/* ---------------------------------------------------------------------------- - * Functions - * ------------------------------------------------------------------------- */ - -/** - * Create and load a `script` element - * - * This function returns an observable that will emit when the script was - * successfully loaded, or throw an error if it wasn't. - * - * @param src - Script URL - * - * @returns Script observable - */ -export function watchScript(src: string): Observable<void> { - const script = h("script", { src }) - return defer(() => { - document.head.appendChild(script) - return merge( - fromEvent(script, "load"), - fromEvent(script, "error") - .pipe( - switchMap(() => ( - throwError(() => new ReferenceError(`Invalid script: ${src}`)) - )) - ) - ) - .pipe( - map(() => undefined), - finalize(() => document.head.removeChild(script)), - take(1) - ) - }) -} diff --git a/src/templates/assets/javascripts/browser/toggle/index.ts b/src/templates/assets/javascripts/browser/toggle/index.ts deleted file mode 100644 index 0be4b29d..00000000 --- a/src/templates/assets/javascripts/browser/toggle/index.ts +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -import { - Observable, - fromEvent, - map, - startWith -} from "rxjs" - -import { getElement } from "../element" - -/* ---------------------------------------------------------------------------- - * Types - * ------------------------------------------------------------------------- */ - -/** - * Toggle - */ -export type Toggle = - | "drawer" /* Toggle for drawer */ - | "search" /* Toggle for search */ - -/* ---------------------------------------------------------------------------- - * Data - * ------------------------------------------------------------------------- */ - -/** - * Toggle map - */ -const toggles: Record<Toggle, HTMLInputElement> = { - drawer: getElement("[data-md-toggle=drawer]"), - search: getElement("[data-md-toggle=search]") -} - -/* ---------------------------------------------------------------------------- - * Functions - * ------------------------------------------------------------------------- */ - -/** - * Retrieve the value of a toggle - * - * @param name - Toggle - * - * @returns Toggle value - */ -export function getToggle(name: Toggle): boolean { - return toggles[name].checked -} - -/** - * Set toggle - * - * Simulating a click event seems to be the most cross-browser compatible way - * of changing the value while also emitting a `change` event. Before, Material - * used `CustomEvent` to programmatically change the value of a toggle, but this - * is a much simpler and cleaner solution which doesn't require a polyfill. - * - * @param name - Toggle - * @param value - Toggle value - */ -export function setToggle(name: Toggle, value: boolean): void { - if (toggles[name].checked !== value) - toggles[name].click() -} - -/* ------------------------------------------------------------------------- */ - -/** - * Watch toggle - * - * @param name - Toggle - * - * @returns Toggle value observable - */ -export function watchToggle(name: Toggle): Observable<boolean> { - const el = toggles[name] - return fromEvent(el, "change") - .pipe( - map(() => el.checked), - startWith(el.checked) - ) -} diff --git a/src/templates/assets/javascripts/browser/viewport/_/index.ts b/src/templates/assets/javascripts/browser/viewport/_/index.ts deleted file mode 100644 index 09c45f32..00000000 --- a/src/templates/assets/javascripts/browser/viewport/_/index.ts +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -import { - Observable, - combineLatest, - map, - shareReplay -} from "rxjs" - -import { - ViewportOffset, - watchViewportOffset -} from "../offset" -import { - ViewportSize, - watchViewportSize -} from "../size" - -/* ---------------------------------------------------------------------------- - * Types - * ------------------------------------------------------------------------- */ - -/** - * Viewport - */ -export interface Viewport { - offset: ViewportOffset /* Viewport offset */ - size: ViewportSize /* Viewport size */ -} - -/* ---------------------------------------------------------------------------- - * Functions - * ------------------------------------------------------------------------- */ - -/** - * Watch viewport - * - * @returns Viewport observable - */ -export function watchViewport(): Observable<Viewport> { - return combineLatest([ - watchViewportOffset(), - watchViewportSize() - ]) - .pipe( - map(([offset, size]) => ({ offset, size })), - shareReplay(1) - ) -} diff --git a/src/templates/assets/javascripts/browser/viewport/at/index.ts b/src/templates/assets/javascripts/browser/viewport/at/index.ts deleted file mode 100644 index 8769cf3b..00000000 --- a/src/templates/assets/javascripts/browser/viewport/at/index.ts +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -import { - Observable, - combineLatest, - distinctUntilKeyChanged, - map -} from "rxjs" - -import { Header } from "~/components" - -import { getElementOffset } from "../../element" -import { Viewport } from "../_" - -/* ---------------------------------------------------------------------------- - * Helper types - * ------------------------------------------------------------------------- */ - -/** - * Watch options - */ -interface WatchOptions { - viewport$: Observable<Viewport> /* Viewport observable */ - header$: Observable<Header> /* Header observable */ -} - -/* ---------------------------------------------------------------------------- - * Functions - * ------------------------------------------------------------------------- */ - -/** - * Watch viewport relative to element - * - * @param el - Element - * @param options - Options - * - * @returns Viewport observable - */ -export function watchViewportAt( - el: HTMLElement, { viewport$, header$ }: WatchOptions -): Observable<Viewport> { - const size$ = viewport$ - .pipe( - distinctUntilKeyChanged("size") - ) - - /* Compute element offset */ - const offset$ = combineLatest([size$, header$]) - .pipe( - map(() => getElementOffset(el)) - ) - - /* Compute relative viewport, return hot observable */ - return combineLatest([header$, viewport$, offset$]) - .pipe( - map(([{ height }, { offset, size }, { x, y }]) => ({ - offset: { - x: offset.x - x, - y: offset.y - y + height - }, - size - })) - ) -} diff --git a/src/templates/assets/javascripts/browser/viewport/index.ts b/src/templates/assets/javascripts/browser/viewport/index.ts deleted file mode 100644 index b3d135e9..00000000 --- a/src/templates/assets/javascripts/browser/viewport/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -export * from "./_" -export * from "./at" -export * from "./offset" -export * from "./size" diff --git a/src/templates/assets/javascripts/browser/viewport/offset/index.ts b/src/templates/assets/javascripts/browser/viewport/offset/index.ts deleted file mode 100644 index 63d37dd2..00000000 --- a/src/templates/assets/javascripts/browser/viewport/offset/index.ts +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -import { - Observable, - fromEvent, - map, - merge, - startWith -} from "rxjs" - -/* ---------------------------------------------------------------------------- - * Types - * ------------------------------------------------------------------------- */ - -/** - * Viewport offset - */ -export interface ViewportOffset { - x: number /* Horizontal offset */ - y: number /* Vertical offset */ -} - -/* ---------------------------------------------------------------------------- - * Functions - * ------------------------------------------------------------------------- */ - -/** - * Retrieve viewport offset - * - * On iOS Safari, viewport offset can be negative due to overflow scrolling. - * As this may induce strange behaviors downstream, we'll just limit it to 0. - * - * @returns Viewport offset - */ -export function getViewportOffset(): ViewportOffset { - return { - x: Math.max(0, scrollX), - y: Math.max(0, scrollY) - } -} - -/* ------------------------------------------------------------------------- */ - -/** - * Watch viewport offset - * - * @returns Viewport offset observable - */ -export function watchViewportOffset(): Observable<ViewportOffset> { - return merge( - fromEvent(window, "scroll", { passive: true }), - fromEvent(window, "resize", { passive: true }) - ) - .pipe( - map(getViewportOffset), - startWith(getViewportOffset()) - ) -} diff --git a/src/templates/assets/javascripts/browser/viewport/size/index.ts b/src/templates/assets/javascripts/browser/viewport/size/index.ts deleted file mode 100644 index 06694888..00000000 --- a/src/templates/assets/javascripts/browser/viewport/size/index.ts +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -import { - Observable, - fromEvent, - map, - startWith -} from "rxjs" - -/* ---------------------------------------------------------------------------- - * Types - * ------------------------------------------------------------------------- */ - -/** - * Viewport size - */ -export interface ViewportSize { - width: number /* Viewport width */ - height: number /* Viewport height */ -} - -/* ---------------------------------------------------------------------------- - * Functions - * ------------------------------------------------------------------------- */ - -/** - * Retrieve viewport size - * - * @returns Viewport size - */ -export function getViewportSize(): ViewportSize { - return { - width: innerWidth, - height: innerHeight - } -} - -/* ------------------------------------------------------------------------- */ - -/** - * Watch viewport size - * - * @returns Viewport size observable - */ -export function watchViewportSize(): Observable<ViewportSize> { - return fromEvent(window, "resize", { passive: true }) - .pipe( - map(getViewportSize), - startWith(getViewportSize()) - ) -} diff --git a/src/templates/assets/javascripts/browser/worker/index.ts b/src/templates/assets/javascripts/browser/worker/index.ts deleted file mode 100644 index 12e4e63b..00000000 --- a/src/templates/assets/javascripts/browser/worker/index.ts +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -import { - Observable, - Subject, - endWith, - fromEvent, - ignoreElements, - mergeWith, - share, - takeUntil -} from "rxjs" - -/* ---------------------------------------------------------------------------- - * Types - * ------------------------------------------------------------------------- */ - -/** - * Worker message - */ -export interface WorkerMessage { - type: unknown /* Message type */ - data?: unknown /* Message data */ -} - -/* ---------------------------------------------------------------------------- - * Helper functions - * ------------------------------------------------------------------------- */ - -/** - * Create an observable for receiving from a web worker - * - * @template T - Data type - * - * @param worker - Web worker - * - * @returns Message observable - */ -function recv<T>(worker: Worker): Observable<T> { - return fromEvent<MessageEvent<T>, T>(worker, "message", ev => ev.data) -} - -/** - * Create a subject for sending to a web worker - * - * @template T - Data type - * - * @param worker - Web worker - * - * @returns Message subject - */ -function send<T>(worker: Worker): Subject<T> { - const send$ = new Subject<T>() - send$.subscribe(data => worker.postMessage(data)) - - /* Return message subject */ - return send$ -} - -/* ---------------------------------------------------------------------------- - * Functions - * ------------------------------------------------------------------------- */ - -/** - * Create a bidirectional communication channel to a web worker - * - * @template T - Data type - * - * @param url - Worker URL - * @param worker - Worker - * - * @returns Worker subject - */ -export function watchWorker<T extends WorkerMessage>( - url: string, worker = new Worker(url) -): Subject<T> { - const recv$ = recv<T>(worker) - const send$ = send<T>(worker) - - /* Create worker subject and forward messages */ - const worker$ = new Subject<T>() - worker$.subscribe(send$) - - /* Return worker subject */ - const done$ = send$.pipe(ignoreElements(), endWith(true)) - return worker$ - .pipe( - ignoreElements(), - mergeWith(recv$.pipe(takeUntil(done$))), - share() - ) as Subject<T> -} |
