Refactored project structure
This commit is contained in:
parent
ad1b964aaa
commit
88ba609ee1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -34,7 +34,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block styles %}
|
{% block styles %}
|
||||||
<link rel="stylesheet" href="{{ 'assets/stylesheets/main.b5f74394.min.css' | url }}">
|
<link rel="stylesheet" href="{{ 'assets/stylesheets/main.b29cf17d.min.css' | url }}">
|
||||||
{% if config.theme.palette %}
|
{% if config.theme.palette %}
|
||||||
{% set palette = config.theme.palette %}
|
{% set palette = config.theme.palette %}
|
||||||
<link rel="stylesheet" href="{{ 'assets/stylesheets/palette.9204c3b2.min.css' | url }}">
|
<link rel="stylesheet" href="{{ 'assets/stylesheets/palette.9204c3b2.min.css' | url }}">
|
||||||
|
|
@ -211,7 +211,7 @@
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
<script src="{{ 'assets/javascripts/bundle.0d86bc28.min.js' | url }}"></script>
|
<script src="{{ 'assets/javascripts/bundle.4fa4ff07.min.js' | url }}"></script>
|
||||||
{% for path in config["extra_javascript"] %}
|
{% for path in config["extra_javascript"] %}
|
||||||
<script src="{{ path | url }}"></script>
|
<script src="{{ path | url }}"></script>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -16,5 +16,5 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
{{ super() }}
|
{{ super() }}
|
||||||
<script src="{{ 'overrides/assets/javascripts/bundle.2a83b894.min.js' | url }}"></script>
|
<script src="{{ 'overrides/assets/javascripts/bundle.5ee92cf1.min.js' | url }}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
* IN THE SOFTWARE.
|
* IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { getElementOrThrow, getLocation } from "~/browser"
|
import { getElement, getLocation } from "~/browser"
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
* Types
|
* Types
|
||||||
|
|
@ -99,7 +99,7 @@ export interface Config {
|
||||||
/**
|
/**
|
||||||
* Retrieve global configuration and make base URL absolute
|
* Retrieve global configuration and make base URL absolute
|
||||||
*/
|
*/
|
||||||
const script = getElementOrThrow("#__config")
|
const script = getElement("#__config")
|
||||||
const config: Config = JSON.parse(script.textContent!)
|
const config: Config = JSON.parse(script.textContent!)
|
||||||
config.base = `${new URL(config.base, getLocation())}`
|
config.base = `${new URL(config.base, getLocation())}`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,7 @@
|
||||||
import {
|
import {
|
||||||
ReplaySubject,
|
ReplaySubject,
|
||||||
Subject,
|
Subject,
|
||||||
fromEvent,
|
fromEvent
|
||||||
mapTo
|
|
||||||
} from "rxjs"
|
} from "rxjs"
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
|
|
@ -40,12 +39,9 @@ import {
|
||||||
* @returns Document subject
|
* @returns Document subject
|
||||||
*/
|
*/
|
||||||
export function watchDocument(): Subject<Document> {
|
export function watchDocument(): Subject<Document> {
|
||||||
const document$ = new ReplaySubject<Document>()
|
const document$ = new ReplaySubject<Document>(1)
|
||||||
fromEvent(document, "DOMContentLoaded")
|
fromEvent(document, "DOMContentLoaded", { once: true })
|
||||||
.pipe(
|
.subscribe(() => document$.next(document))
|
||||||
mapTo(document)
|
|
||||||
)
|
|
||||||
.subscribe(document$)
|
|
||||||
|
|
||||||
/* Return document */
|
/* Return document */
|
||||||
return document$
|
return document$
|
||||||
|
|
|
||||||
|
|
@ -24,72 +24,6 @@
|
||||||
* Functions
|
* Functions
|
||||||
* ------------------------------------------------------------------------- */
|
* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve an element matching the query selector
|
|
||||||
*
|
|
||||||
* @template T - Element type
|
|
||||||
*
|
|
||||||
* @param selector - Query selector
|
|
||||||
* @param node - Node of reference
|
|
||||||
*
|
|
||||||
* @returns Element or nothing
|
|
||||||
*/
|
|
||||||
export function getElement<T extends keyof HTMLElementTagNameMap>(
|
|
||||||
selector: T, node?: ParentNode
|
|
||||||
): HTMLElementTagNameMap[T] | undefined
|
|
||||||
|
|
||||||
export function getElement<T extends HTMLElement>(
|
|
||||||
selector: string, node?: ParentNode
|
|
||||||
): T | undefined
|
|
||||||
|
|
||||||
export function getElement<T extends HTMLElement>(
|
|
||||||
selector: string, node: ParentNode = document
|
|
||||||
): T | undefined {
|
|
||||||
return node.querySelector<T>(selector) || undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve an element matching a query selector or throw a reference error
|
|
||||||
*
|
|
||||||
* @template T - Element type
|
|
||||||
*
|
|
||||||
* @param selector - Query selector
|
|
||||||
* @param node - Node of reference
|
|
||||||
*
|
|
||||||
* @returns Element
|
|
||||||
*/
|
|
||||||
export function getElementOrThrow<T extends keyof HTMLElementTagNameMap>(
|
|
||||||
selector: T, node?: ParentNode
|
|
||||||
): HTMLElementTagNameMap[T]
|
|
||||||
|
|
||||||
export function getElementOrThrow<T extends HTMLElement>(
|
|
||||||
selector: string, node?: ParentNode
|
|
||||||
): T
|
|
||||||
|
|
||||||
export function getElementOrThrow<T extends HTMLElement>(
|
|
||||||
selector: string, node: ParentNode = document
|
|
||||||
): T {
|
|
||||||
const el = getElement<T>(selector, node)
|
|
||||||
if (typeof el === "undefined")
|
|
||||||
throw new ReferenceError(
|
|
||||||
`Missing element: expected "${selector}" to be present`
|
|
||||||
)
|
|
||||||
|
|
||||||
/* Return element */
|
|
||||||
return el
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the currently active element
|
|
||||||
*
|
|
||||||
* @returns Element or nothing
|
|
||||||
*/
|
|
||||||
export function getActiveElement(): HTMLElement | undefined {
|
|
||||||
return document.activeElement instanceof HTMLElement
|
|
||||||
? document.activeElement
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve all elements matching the query selector
|
* Retrieve all elements matching the query selector
|
||||||
*
|
*
|
||||||
|
|
@ -114,16 +48,73 @@ export function getElements<T extends HTMLElement>(
|
||||||
return Array.from(node.querySelectorAll<T>(selector))
|
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
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replace an element with the given list of nodes
|
* Retrieve an optional element matching the query selector
|
||||||
*
|
*
|
||||||
* @param el - Element
|
* @template T - Element type
|
||||||
* @param nodes - Replacement nodes
|
*
|
||||||
|
* @param selector - Query selector
|
||||||
|
* @param node - Node of reference
|
||||||
|
*
|
||||||
|
* @returns Element or nothing
|
||||||
*/
|
*/
|
||||||
export function replaceElement(
|
export function getOptionalElement<T extends keyof HTMLElementTagNameMap>(
|
||||||
el: HTMLElement, ...nodes: Node[]
|
selector: T, node?: ParentNode
|
||||||
): void {
|
): HTMLElementTagNameMap[T] | undefined
|
||||||
el.replaceWith(...nodes)
|
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,3 +25,4 @@ export * from "./focus"
|
||||||
export * from "./offset"
|
export * from "./offset"
|
||||||
export * from "./selection"
|
export * from "./selection"
|
||||||
export * from "./size"
|
export * from "./size"
|
||||||
|
export * from "./visibility"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2021 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
|
||||||
|
* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 fromEvent(window, "resize")
|
||||||
|
.pipe(
|
||||||
|
map(() => getElementOffset(el)),
|
||||||
|
startWith(getElementOffset(el))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2021 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"
|
||||||
|
|
||||||
|
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(
|
||||||
|
map(() => getElementContentOffset(el)),
|
||||||
|
startWith(getElementContentOffset(el))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -20,95 +20,5 @@
|
||||||
* IN THE SOFTWARE.
|
* IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
export * from "./_"
|
||||||
Observable,
|
export * from "./content"
|
||||||
distinctUntilChanged,
|
|
||||||
fromEvent,
|
|
||||||
map,
|
|
||||||
merge,
|
|
||||||
startWith
|
|
||||||
} from "rxjs"
|
|
||||||
|
|
||||||
import {
|
|
||||||
getElementContentSize,
|
|
||||||
getElementSize
|
|
||||||
} from "../size"
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
|
||||||
* 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.scrollLeft,
|
|
||||||
y: el.scrollTop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Watch element offset
|
|
||||||
*
|
|
||||||
* @param el - Element
|
|
||||||
*
|
|
||||||
* @returns Element offset observable
|
|
||||||
*/
|
|
||||||
export function watchElementOffset(
|
|
||||||
el: HTMLElement
|
|
||||||
): Observable<ElementOffset> {
|
|
||||||
return merge(
|
|
||||||
fromEvent(el, "scroll"),
|
|
||||||
fromEvent(window, "resize")
|
|
||||||
)
|
|
||||||
.pipe(
|
|
||||||
map(() => getElementOffset(el)),
|
|
||||||
startWith(getElementOffset(el))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Watch element threshold
|
|
||||||
*
|
|
||||||
* This function returns an observable which emits whether the bottom scroll
|
|
||||||
* offset of an elements is within a certain threshold.
|
|
||||||
*
|
|
||||||
* @param el - Element
|
|
||||||
* @param threshold - Threshold
|
|
||||||
*
|
|
||||||
* @returns Element threshold observable
|
|
||||||
*/
|
|
||||||
export function watchElementThreshold(
|
|
||||||
el: HTMLElement, threshold = 16
|
|
||||||
): Observable<boolean> {
|
|
||||||
return watchElementOffset(el)
|
|
||||||
.pipe(
|
|
||||||
map(({ y }) => {
|
|
||||||
const visible = getElementSize(el)
|
|
||||||
const content = getElementContentSize(el)
|
|
||||||
return y >= (
|
|
||||||
content.height - visible.height - threshold
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
distinctUntilChanged()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,138 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2021 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,
|
||||||
|
of,
|
||||||
|
shareReplay,
|
||||||
|
startWith,
|
||||||
|
switchMap,
|
||||||
|
tap
|
||||||
|
} from "rxjs"
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------------
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @see https://bit.ly/3iIYfEm - Google Groups on performance
|
||||||
|
*/
|
||||||
|
const observer$ = defer(() => of(
|
||||||
|
new ResizeObserver(entries => {
|
||||||
|
for (const entry of entries)
|
||||||
|
entry$.next(entry)
|
||||||
|
})
|
||||||
|
))
|
||||||
|
.pipe(
|
||||||
|
switchMap(observer => NEVER.pipe(startWith(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))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2021 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -20,133 +20,5 @@
|
||||||
* IN THE SOFTWARE.
|
* IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
export * from "./_"
|
||||||
NEVER,
|
export * from "./content"
|
||||||
Observable,
|
|
||||||
Subject,
|
|
||||||
defer,
|
|
||||||
filter,
|
|
||||||
finalize,
|
|
||||||
map,
|
|
||||||
of,
|
|
||||||
shareReplay,
|
|
||||||
startWith,
|
|
||||||
switchMap,
|
|
||||||
tap
|
|
||||||
} from "rxjs"
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* @see https://bit.ly/3iIYfEm - Google Groups on performance
|
|
||||||
*/
|
|
||||||
const observer$ = defer(() => of(
|
|
||||||
new ResizeObserver(entries => {
|
|
||||||
for (const entry of entries)
|
|
||||||
entry$.next(entry)
|
|
||||||
})
|
|
||||||
))
|
|
||||||
.pipe(
|
|
||||||
switchMap(resize => NEVER.pipe(startWith(resize))
|
|
||||||
.pipe(
|
|
||||||
finalize(() => resize.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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve element content size, i.e. including overflowing content
|
|
||||||
*
|
|
||||||
* @param el - Element
|
|
||||||
*
|
|
||||||
* @returns Element size
|
|
||||||
*/
|
|
||||||
export function getElementContentSize(el: HTMLElement): ElementSize {
|
|
||||||
return {
|
|
||||||
width: el.scrollWidth,
|
|
||||||
height: el.scrollHeight
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2021 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,
|
||||||
|
of,
|
||||||
|
shareReplay,
|
||||||
|
startWith,
|
||||||
|
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: 1
|
||||||
|
})
|
||||||
|
))
|
||||||
|
.pipe(
|
||||||
|
switchMap(observer => NEVER.pipe(startWith(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 threshold 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()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -29,7 +29,7 @@ import {
|
||||||
startWith
|
startWith
|
||||||
} from "rxjs"
|
} from "rxjs"
|
||||||
|
|
||||||
import { getElement } from "~/browser"
|
import { getOptionalElement } from "~/browser"
|
||||||
import { h } from "~/utilities"
|
import { h } from "~/utilities"
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
|
|
@ -86,7 +86,7 @@ export function watchLocationHash(): Observable<string> {
|
||||||
export function watchLocationTarget(): Observable<HTMLElement> {
|
export function watchLocationTarget(): Observable<HTMLElement> {
|
||||||
return watchLocationHash()
|
return watchLocationHash()
|
||||||
.pipe(
|
.pipe(
|
||||||
map(id => getElement(`[id="${id}"]`)!),
|
map(id => getOptionalElement(`[id="${id}"]`)!),
|
||||||
filter(el => typeof el !== "undefined")
|
filter(el => typeof el !== "undefined")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ import {
|
||||||
startWith
|
startWith
|
||||||
} from "rxjs"
|
} from "rxjs"
|
||||||
|
|
||||||
import { getElementOrThrow } from "../element"
|
import { getElement } from "../element"
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
* Types
|
* Types
|
||||||
|
|
@ -48,8 +48,8 @@ export type Toggle =
|
||||||
* Toggle map
|
* Toggle map
|
||||||
*/
|
*/
|
||||||
const toggles: Record<Toggle, HTMLInputElement> = {
|
const toggles: Record<Toggle, HTMLInputElement> = {
|
||||||
drawer: getElementOrThrow("[data-md-toggle=drawer]"),
|
drawer: getElement("[data-md-toggle=drawer]"),
|
||||||
search: getElementOrThrow("[data-md-toggle=search]")
|
search: getElement("[data-md-toggle=search]")
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import {
|
||||||
|
|
||||||
import { Header } from "~/components"
|
import { Header } from "~/components"
|
||||||
|
|
||||||
|
import { getElementOffset } from "../../element"
|
||||||
import {
|
import {
|
||||||
ViewportOffset,
|
ViewportOffset,
|
||||||
watchViewportOffset
|
watchViewportOffset
|
||||||
|
|
@ -102,10 +103,7 @@ export function watchViewportAt(
|
||||||
/* Compute element offset */
|
/* Compute element offset */
|
||||||
const offset$ = combineLatest([size$, header$])
|
const offset$ = combineLatest([size$, header$])
|
||||||
.pipe(
|
.pipe(
|
||||||
map((): ViewportOffset => ({
|
map(() => getElementOffset(el))
|
||||||
x: el.offsetLeft,
|
|
||||||
y: el.offsetTop
|
|
||||||
}))
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/* Compute relative viewport, return hot observable */
|
/* Compute relative viewport, return hot observable */
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,8 @@ export interface ViewportOffset {
|
||||||
*/
|
*/
|
||||||
export function getViewportOffset(): ViewportOffset {
|
export function getViewportOffset(): ViewportOffset {
|
||||||
return {
|
return {
|
||||||
x: Math.max(0, pageXOffset),
|
x: Math.max(0, scrollX),
|
||||||
y: Math.max(0, pageYOffset)
|
y: Math.max(0, scrollY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ import {
|
||||||
import { configuration, feature } from "./_"
|
import { configuration, feature } from "./_"
|
||||||
import {
|
import {
|
||||||
at,
|
at,
|
||||||
getElement,
|
getOptionalElement,
|
||||||
requestJSON,
|
requestJSON,
|
||||||
setToggle,
|
setToggle,
|
||||||
watchDocument,
|
watchDocument,
|
||||||
|
|
@ -96,6 +96,7 @@ const keyboard$ = watchKeyboard()
|
||||||
const viewport$ = watchViewport()
|
const viewport$ = watchViewport()
|
||||||
const tablet$ = watchMedia("(min-width: 960px)")
|
const tablet$ = watchMedia("(min-width: 960px)")
|
||||||
const screen$ = watchMedia("(min-width: 1220px)")
|
const screen$ = watchMedia("(min-width: 1220px)")
|
||||||
|
const hover$ = watchMedia("(hover)")
|
||||||
const print$ = watchPrint()
|
const print$ = watchPrint()
|
||||||
|
|
||||||
/* Retrieve search index, if search is enabled */
|
/* Retrieve search index, if search is enabled */
|
||||||
|
|
@ -139,7 +140,7 @@ keyboard$
|
||||||
/* Go to previous page */
|
/* Go to previous page */
|
||||||
case "p":
|
case "p":
|
||||||
case ",":
|
case ",":
|
||||||
const prev = getElement("[href][rel=prev]")
|
const prev = getOptionalElement("[href][rel=prev]")
|
||||||
if (typeof prev !== "undefined")
|
if (typeof prev !== "undefined")
|
||||||
prev.click()
|
prev.click()
|
||||||
break
|
break
|
||||||
|
|
@ -147,7 +148,7 @@ keyboard$
|
||||||
/* Go to next page */
|
/* Go to next page */
|
||||||
case "n":
|
case "n":
|
||||||
case ".":
|
case ".":
|
||||||
const next = getElement("[href][rel=next]")
|
const next = getOptionalElement("[href][rel=next]")
|
||||||
if (typeof next !== "undefined")
|
if (typeof next !== "undefined")
|
||||||
next.click()
|
next.click()
|
||||||
break
|
break
|
||||||
|
|
@ -197,7 +198,7 @@ const content$ = defer(() => merge(
|
||||||
|
|
||||||
/* Content */
|
/* Content */
|
||||||
...getComponentElements("content")
|
...getComponentElements("content")
|
||||||
.map(el => mountContent(el, { target$, viewport$, print$ })),
|
.map(el => mountContent(el, { target$, viewport$, hover$, print$ })),
|
||||||
|
|
||||||
/* Search highlighting */
|
/* Search highlighting */
|
||||||
...getComponentElements("content")
|
...getComponentElements("content")
|
||||||
|
|
@ -250,8 +251,9 @@ window.location$ = location$ /* Location subject */
|
||||||
window.target$ = target$ /* Location target observable */
|
window.target$ = target$ /* Location target observable */
|
||||||
window.keyboard$ = keyboard$ /* Keyboard observable */
|
window.keyboard$ = keyboard$ /* Keyboard observable */
|
||||||
window.viewport$ = viewport$ /* Viewport observable */
|
window.viewport$ = viewport$ /* Viewport observable */
|
||||||
window.tablet$ = tablet$ /* Tablet observable */
|
window.tablet$ = tablet$ /* Media tablet observable */
|
||||||
window.screen$ = screen$ /* Screen observable */
|
window.screen$ = screen$ /* Media screen observable */
|
||||||
window.print$ = print$ /* Print observable */
|
window.hover$ = hover$ /* Media hover observable */
|
||||||
|
window.print$ = print$ /* Media print observable */
|
||||||
window.alert$ = alert$ /* Alert subject */
|
window.alert$ = alert$ /* Alert subject */
|
||||||
window.component$ = component$ /* Component observable */
|
window.component$ = component$ /* Component observable */
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
* IN THE SOFTWARE.
|
* IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { getElementOrThrow, getElements } from "~/browser"
|
import { getElement, getElements } from "~/browser"
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
* Types
|
* Types
|
||||||
|
|
@ -114,7 +114,7 @@ interface ComponentTypeMap {
|
||||||
export function getComponentElement<T extends ComponentType>(
|
export function getComponentElement<T extends ComponentType>(
|
||||||
type: T, node: ParentNode = document
|
type: T, node: ParentNode = document
|
||||||
): ComponentTypeMap[T] {
|
): ComponentTypeMap[T] {
|
||||||
return getElementOrThrow(`[data-md-component=${type}]`, node)
|
return getElement(`[data-md-component=${type}]`, node)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,8 @@ export type Content =
|
||||||
interface MountOptions {
|
interface MountOptions {
|
||||||
target$: Observable<HTMLElement> /* Location target observable */
|
target$: Observable<HTMLElement> /* Location target observable */
|
||||||
viewport$: Observable<Viewport> /* Viewport observable */
|
viewport$: Observable<Viewport> /* Viewport observable */
|
||||||
print$: Observable<boolean> /* Print observable */
|
hover$: Observable<boolean> /* Media hover observable */
|
||||||
|
print$: Observable<boolean> /* Media print observable */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
|
|
@ -72,13 +73,13 @@ interface MountOptions {
|
||||||
* @returns Content component observable
|
* @returns Content component observable
|
||||||
*/
|
*/
|
||||||
export function mountContent(
|
export function mountContent(
|
||||||
el: HTMLElement, { target$, viewport$, print$ }: MountOptions
|
el: HTMLElement, { target$, viewport$, hover$, print$ }: MountOptions
|
||||||
): Observable<Component<Content>> {
|
): Observable<Component<Content>> {
|
||||||
return merge(
|
return merge(
|
||||||
|
|
||||||
/* Code blocks */
|
/* Code blocks */
|
||||||
...getElements("pre > code", el)
|
...getElements("pre > code", el)
|
||||||
.map(child => mountCodeBlock(child, { viewport$, print$ })),
|
.map(child => mountCodeBlock(child, { viewport$, hover$, print$ })),
|
||||||
|
|
||||||
/* Data tables */
|
/* Data tables */
|
||||||
...getElements("table:not([class])", el)
|
...getElements("table:not([class])", el)
|
||||||
|
|
|
||||||
|
|
@ -41,14 +41,17 @@ import {
|
||||||
} from "rxjs"
|
} from "rxjs"
|
||||||
|
|
||||||
import { feature } from "~/_"
|
import { feature } from "~/_"
|
||||||
import { resetFocusable, setFocusable } from "~/actions"
|
import {
|
||||||
|
resetFocusable,
|
||||||
|
setFocusable
|
||||||
|
} from "~/actions"
|
||||||
import {
|
import {
|
||||||
Viewport,
|
Viewport,
|
||||||
getElement,
|
getElement,
|
||||||
getElementContentSize,
|
getElementContentSize,
|
||||||
getElementOrThrow,
|
|
||||||
getElementSize,
|
getElementSize,
|
||||||
getElements,
|
getElements,
|
||||||
|
getOptionalElement,
|
||||||
watchMedia
|
watchMedia
|
||||||
} from "~/browser"
|
} from "~/browser"
|
||||||
import {
|
import {
|
||||||
|
|
@ -174,7 +177,7 @@ export function watchCodeBlock(
|
||||||
container.insertAdjacentElement("afterend", list)
|
container.insertAdjacentElement("afterend", list)
|
||||||
for (const annotation of annotations) {
|
for (const annotation of annotations) {
|
||||||
const id = parseInt(annotation.getAttribute("data-index")!, 10)
|
const id = parseInt(annotation.getAttribute("data-index")!, 10)
|
||||||
const typeset = getElement(":scope .md-typeset", annotation)!
|
const typeset = getOptionalElement(":scope .md-typeset", annotation)!
|
||||||
items[id - 1].append(...Array.from(typeset.childNodes))
|
items[id - 1].append(...Array.from(typeset.childNodes))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -182,7 +185,7 @@ export function watchCodeBlock(
|
||||||
for (const annotation of annotations) {
|
for (const annotation of annotations) {
|
||||||
const id = parseInt(annotation.getAttribute("data-index")!, 10)
|
const id = parseInt(annotation.getAttribute("data-index")!, 10)
|
||||||
const nodes = items[id - 1].childNodes
|
const nodes = items[id - 1].childNodes
|
||||||
getElementOrThrow(":scope .md-typeset", annotation)
|
getElement(":scope .md-typeset", annotation)
|
||||||
.append(...Array.from(nodes))
|
.append(...Array.from(nodes))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -239,7 +242,7 @@ export function mountCodeBlock(
|
||||||
take(1),
|
take(1),
|
||||||
takeWhile(({ annotations }) => !!annotations?.length),
|
takeWhile(({ annotations }) => !!annotations?.length),
|
||||||
map(({ annotations }) => annotations!
|
map(({ annotations }) => annotations!
|
||||||
.map(annotation => getElementOrThrow(".md-tooltip", annotation))
|
.map(annotation => getElement(".md-tooltip", annotation))
|
||||||
),
|
),
|
||||||
combineLatestWith(viewport$
|
combineLatestWith(viewport$
|
||||||
.pipe(
|
.pipe(
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ export interface Details {
|
||||||
*/
|
*/
|
||||||
interface WatchOptions {
|
interface WatchOptions {
|
||||||
target$: Observable<HTMLElement> /* Location target observable */
|
target$: Observable<HTMLElement> /* Location target observable */
|
||||||
print$: Observable<boolean> /* Print observable */
|
print$: Observable<boolean> /* Media print observable */
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -62,7 +62,7 @@ interface WatchOptions {
|
||||||
*/
|
*/
|
||||||
interface MountOptions {
|
interface MountOptions {
|
||||||
target$: Observable<HTMLElement> /* Location target observable */
|
target$: Observable<HTMLElement> /* Location target observable */
|
||||||
print$: Observable<boolean> /* Print observable */
|
print$: Observable<boolean> /* Media print observable */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@
|
||||||
|
|
||||||
import { Observable, of } from "rxjs"
|
import { Observable, of } from "rxjs"
|
||||||
|
|
||||||
import { replaceElement } from "~/browser"
|
|
||||||
import { renderTable } from "~/templates"
|
import { renderTable } from "~/templates"
|
||||||
import { h } from "~/utilities"
|
import { h } from "~/utilities"
|
||||||
|
|
||||||
|
|
@ -63,8 +62,8 @@ const sentinel = h("table")
|
||||||
export function mountDataTable(
|
export function mountDataTable(
|
||||||
el: HTMLElement
|
el: HTMLElement
|
||||||
): Observable<Component<DataTable>> {
|
): Observable<Component<DataTable>> {
|
||||||
replaceElement(el, sentinel)
|
el.replaceWith(sentinel)
|
||||||
replaceElement(sentinel, renderTable(el))
|
sentinel.replaceWith(renderTable(el))
|
||||||
|
|
||||||
/* Create and return component */
|
/* Create and return component */
|
||||||
return of({ ref: el })
|
return of({ ref: el })
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
NEVER,
|
|
||||||
Observable,
|
Observable,
|
||||||
Subject,
|
Subject,
|
||||||
finalize,
|
finalize,
|
||||||
|
|
@ -33,7 +32,7 @@ import {
|
||||||
} from "rxjs"
|
} from "rxjs"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getElementOrThrow,
|
getElement,
|
||||||
getElements
|
getElements
|
||||||
} from "~/browser"
|
} from "~/browser"
|
||||||
|
|
||||||
|
|
@ -64,17 +63,14 @@ export interface ContentTabs {
|
||||||
export function watchContentTabs(
|
export function watchContentTabs(
|
||||||
el: HTMLElement
|
el: HTMLElement
|
||||||
): Observable<ContentTabs> {
|
): Observable<ContentTabs> {
|
||||||
if (!el.classList.contains("tabbed-alternate"))
|
return merge(...getElements(":scope > input", el)
|
||||||
return NEVER
|
.map(input => fromEvent(input, "change").pipe(mapTo(input.id)))
|
||||||
else
|
)
|
||||||
return merge(...getElements(":scope > input", el)
|
.pipe(
|
||||||
.map(input => fromEvent(input, "change").pipe(mapTo(input.id)))
|
map(id => ({
|
||||||
|
active: getElement<HTMLLabelElement>(`label[for=${id}]`)
|
||||||
|
}))
|
||||||
)
|
)
|
||||||
.pipe(
|
|
||||||
map(id => ({
|
|
||||||
active: getElementOrThrow<HTMLLabelElement>(`label[for=${id}]`)
|
|
||||||
}))
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,10 @@ import {
|
||||||
} from "rxjs"
|
} from "rxjs"
|
||||||
|
|
||||||
import { feature } from "~/_"
|
import { feature } from "~/_"
|
||||||
import { resetHeaderState, setHeaderState } from "~/actions"
|
import {
|
||||||
|
resetHeaderState,
|
||||||
|
setHeaderState
|
||||||
|
} from "~/actions"
|
||||||
import {
|
import {
|
||||||
Viewport,
|
Viewport,
|
||||||
watchElementSize,
|
watchElementSize,
|
||||||
|
|
|
||||||
|
|
@ -38,8 +38,8 @@ import {
|
||||||
} from "~/actions"
|
} from "~/actions"
|
||||||
import {
|
import {
|
||||||
Viewport,
|
Viewport,
|
||||||
getElement,
|
|
||||||
getElementSize,
|
getElementSize,
|
||||||
|
getOptionalElement,
|
||||||
watchViewportAt
|
watchViewportAt
|
||||||
} from "~/browser"
|
} from "~/browser"
|
||||||
|
|
||||||
|
|
@ -131,7 +131,7 @@ export function mountHeaderTitle(
|
||||||
})
|
})
|
||||||
|
|
||||||
/* Obtain headline, if any */
|
/* Obtain headline, if any */
|
||||||
const headline = getElement<HTMLHeadingElement>("article h1")
|
const headline = getOptionalElement<HTMLHeadingElement>("article h1")
|
||||||
if (typeof headline === "undefined")
|
if (typeof headline === "undefined")
|
||||||
return NEVER
|
return NEVER
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,10 @@ import {
|
||||||
switchMap
|
switchMap
|
||||||
} from "rxjs"
|
} from "rxjs"
|
||||||
|
|
||||||
import { Viewport, watchElementSize } from "~/browser"
|
import {
|
||||||
|
Viewport,
|
||||||
|
watchElementSize
|
||||||
|
} from "~/browser"
|
||||||
|
|
||||||
import { Header } from "../header"
|
import { Header } from "../header"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,10 +53,19 @@ import {
|
||||||
getComponentElement,
|
getComponentElement,
|
||||||
getComponentElements
|
getComponentElements
|
||||||
} from "../../_"
|
} from "../../_"
|
||||||
import { SearchQuery, mountSearchQuery } from "../query"
|
import {
|
||||||
|
SearchQuery,
|
||||||
|
mountSearchQuery
|
||||||
|
} from "../query"
|
||||||
import { mountSearchResult } from "../result"
|
import { mountSearchResult } from "../result"
|
||||||
import { SearchShare, mountSearchShare } from "../share"
|
import {
|
||||||
import { SearchSuggest, mountSearchSuggest } from "../suggest"
|
SearchShare,
|
||||||
|
mountSearchShare
|
||||||
|
} from "../share"
|
||||||
|
import {
|
||||||
|
SearchSuggest,
|
||||||
|
mountSearchSuggest
|
||||||
|
} from "../suggest"
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
* Types
|
* Types
|
||||||
|
|
|
||||||
|
|
@ -46,8 +46,8 @@ import {
|
||||||
setSearchResultMeta
|
setSearchResultMeta
|
||||||
} from "~/actions"
|
} from "~/actions"
|
||||||
import {
|
import {
|
||||||
getElementOrThrow,
|
getElement,
|
||||||
watchElementThreshold
|
watchElementBoundary
|
||||||
} from "~/browser"
|
} from "~/browser"
|
||||||
import {
|
import {
|
||||||
SearchResult,
|
SearchResult,
|
||||||
|
|
@ -91,14 +91,14 @@ export function mountSearchResult(
|
||||||
el: HTMLElement, { rx$ }: SearchWorker, { query$ }: MountOptions
|
el: HTMLElement, { rx$ }: SearchWorker, { query$ }: MountOptions
|
||||||
): Observable<Component<SearchResult>> {
|
): Observable<Component<SearchResult>> {
|
||||||
const internal$ = new Subject<SearchResult>()
|
const internal$ = new Subject<SearchResult>()
|
||||||
const boundary$ = watchElementThreshold(el.parentElement!)
|
const boundary$ = watchElementBoundary(el.parentElement!)
|
||||||
.pipe(
|
.pipe(
|
||||||
filter(Boolean)
|
filter(Boolean)
|
||||||
)
|
)
|
||||||
|
|
||||||
/* Retrieve nested components */
|
/* Retrieve nested components */
|
||||||
const meta = getElementOrThrow(":scope > :first-child", el)
|
const meta = getElement(":scope > :first-child", el)
|
||||||
const list = getElementOrThrow(":scope > :last-child", el)
|
const list = getElement(":scope > :last-child", el)
|
||||||
|
|
||||||
/* Wait until search is ready */
|
/* Wait until search is ready */
|
||||||
const ready$ = rx$
|
const ready$ = rx$
|
||||||
|
|
|
||||||
|
|
@ -98,9 +98,10 @@ interface MountOptions {
|
||||||
export function watchSidebar(
|
export function watchSidebar(
|
||||||
el: HTMLElement, { viewport$, main$ }: WatchOptions
|
el: HTMLElement, { viewport$, main$ }: WatchOptions
|
||||||
): Observable<Sidebar> {
|
): Observable<Sidebar> {
|
||||||
|
const parent = el.parentElement!
|
||||||
const adjust =
|
const adjust =
|
||||||
el.parentElement!.offsetTop -
|
parent.offsetTop -
|
||||||
el.parentElement!.parentElement!.offsetTop
|
parent.parentElement!.offsetTop
|
||||||
|
|
||||||
/* Compute the sidebar's available height and if it should be locked */
|
/* Compute the sidebar's available height and if it should be locked */
|
||||||
return combineLatest([main$, viewport$])
|
return combineLatest([main$, viewport$])
|
||||||
|
|
|
||||||
|
|
@ -34,11 +34,17 @@ import {
|
||||||
tap
|
tap
|
||||||
} from "rxjs"
|
} from "rxjs"
|
||||||
|
|
||||||
import { setSourceFacts, setSourceState } from "~/actions"
|
import {
|
||||||
|
setSourceFacts,
|
||||||
|
setSourceState
|
||||||
|
} from "~/actions"
|
||||||
import { renderSourceFacts } from "~/templates"
|
import { renderSourceFacts } from "~/templates"
|
||||||
|
|
||||||
import { Component } from "../../_"
|
import { Component } from "../../_"
|
||||||
import { SourceFacts, fetchSourceFacts } from "../facts"
|
import {
|
||||||
|
SourceFacts,
|
||||||
|
fetchSourceFacts
|
||||||
|
} from "../facts"
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
* Types
|
* Types
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,10 @@ import {
|
||||||
} from "rxjs"
|
} from "rxjs"
|
||||||
|
|
||||||
import { feature } from "~/_"
|
import { feature } from "~/_"
|
||||||
import { resetTabsState, setTabsState } from "~/actions"
|
import {
|
||||||
|
resetTabsState,
|
||||||
|
setTabsState
|
||||||
|
} from "~/actions"
|
||||||
import {
|
import {
|
||||||
Viewport,
|
Viewport,
|
||||||
watchElementSize,
|
watchElementSize,
|
||||||
|
|
|
||||||
|
|
@ -48,9 +48,9 @@ import {
|
||||||
} from "~/actions"
|
} from "~/actions"
|
||||||
import {
|
import {
|
||||||
Viewport,
|
Viewport,
|
||||||
getElement,
|
|
||||||
getElements,
|
getElements,
|
||||||
getLocation,
|
getLocation,
|
||||||
|
getOptionalElement,
|
||||||
watchElementSize
|
watchElementSize
|
||||||
} from "~/browser"
|
} from "~/browser"
|
||||||
|
|
||||||
|
|
@ -122,7 +122,7 @@ export function watchTableOfContents(
|
||||||
const anchors = getElements<HTMLAnchorElement>("[href^=\\#]", el)
|
const anchors = getElements<HTMLAnchorElement>("[href^=\\#]", el)
|
||||||
for (const anchor of anchors) {
|
for (const anchor of anchors) {
|
||||||
const id = decodeURIComponent(anchor.hash.substring(1))
|
const id = decodeURIComponent(anchor.hash.substring(1))
|
||||||
const target = getElement(`[id="${id}"]`)
|
const target = getOptionalElement(`[id="${id}"]`)
|
||||||
if (typeof target !== "undefined")
|
if (typeof target !== "undefined")
|
||||||
table.set(anchor, target)
|
table.set(anchor, target)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,10 @@ import {
|
||||||
setBackToTopState,
|
setBackToTopState,
|
||||||
setFocusable
|
setFocusable
|
||||||
} from "~/actions"
|
} from "~/actions"
|
||||||
import { Viewport, setElementFocus } from "~/browser"
|
import {
|
||||||
|
Viewport,
|
||||||
|
setElementFocus
|
||||||
|
} from "~/browser"
|
||||||
|
|
||||||
import { Component } from "../_"
|
import { Component } from "../_"
|
||||||
import { Header } from "../header"
|
import { Header } from "../header"
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ import { Observable, Subject } from "rxjs"
|
||||||
|
|
||||||
import { translation } from "~/_"
|
import { translation } from "~/_"
|
||||||
import {
|
import {
|
||||||
getElementOrThrow,
|
getElement,
|
||||||
getElements
|
getElements
|
||||||
} from "~/browser"
|
} from "~/browser"
|
||||||
|
|
||||||
|
|
@ -85,7 +85,7 @@ export function setupClipboardJS(
|
||||||
new ClipboardJS("[data-clipboard-target], [data-clipboard-text]", {
|
new ClipboardJS("[data-clipboard-target], [data-clipboard-text]", {
|
||||||
text: el => (
|
text: el => (
|
||||||
el.getAttribute("data-clipboard-text")! ||
|
el.getAttribute("data-clipboard-text")! ||
|
||||||
extract(getElementOrThrow(
|
extract(getElement(
|
||||||
el.getAttribute("data-clipboard-target")!
|
el.getAttribute("data-clipboard-target")!
|
||||||
))
|
))
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -47,9 +47,8 @@ import { configuration, feature } from "~/_"
|
||||||
import {
|
import {
|
||||||
Viewport,
|
Viewport,
|
||||||
ViewportOffset,
|
ViewportOffset,
|
||||||
getElement,
|
|
||||||
getElements,
|
getElements,
|
||||||
replaceElement,
|
getOptionalElement,
|
||||||
request,
|
request,
|
||||||
requestXML,
|
requestXML,
|
||||||
setLocation,
|
setLocation,
|
||||||
|
|
@ -166,7 +165,7 @@ export function setupInstantLoading(
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hack: ensure absolute favicon link to omit 404s when switching */
|
/* Hack: ensure absolute favicon link to omit 404s when switching */
|
||||||
const favicon = getElement<HTMLLinkElement>("link[rel=icon]")
|
const favicon = getOptionalElement<HTMLLinkElement>("link[rel=icon]")
|
||||||
if (typeof favicon !== "undefined")
|
if (typeof favicon !== "undefined")
|
||||||
favicon.href = favicon.href
|
favicon.href = favicon.href
|
||||||
|
|
||||||
|
|
@ -286,13 +285,13 @@ export function setupInstantLoading(
|
||||||
? ["[data-md-component=tabs]"]
|
? ["[data-md-component=tabs]"]
|
||||||
: []
|
: []
|
||||||
]) {
|
]) {
|
||||||
const source = getElement(selector)
|
const source = getOptionalElement(selector)
|
||||||
const target = getElement(selector, replacement)
|
const target = getOptionalElement(selector, replacement)
|
||||||
if (
|
if (
|
||||||
typeof source !== "undefined" &&
|
typeof source !== "undefined" &&
|
||||||
typeof target !== "undefined"
|
typeof target !== "undefined"
|
||||||
) {
|
) {
|
||||||
replaceElement(source, target)
|
source.replaceWith(target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -308,7 +307,7 @@ export function setupInstantLoading(
|
||||||
if (el.src) {
|
if (el.src) {
|
||||||
for (const name of el.getAttributeNames())
|
for (const name of el.getAttributeNames())
|
||||||
script.setAttribute(name, el.getAttribute(name)!)
|
script.setAttribute(name, el.getAttribute(name)!)
|
||||||
replaceElement(el, script)
|
el.replaceWith(script)
|
||||||
|
|
||||||
/* Complete when script is loaded */
|
/* Complete when script is loaded */
|
||||||
return new Observable(observer => {
|
return new Observable(observer => {
|
||||||
|
|
@ -318,7 +317,7 @@ export function setupInstantLoading(
|
||||||
/* Complete immediately */
|
/* Complete immediately */
|
||||||
} else {
|
} else {
|
||||||
script.textContent = el.textContent
|
script.textContent = el.textContent
|
||||||
replaceElement(el, script)
|
el.replaceWith(script)
|
||||||
return EMPTY
|
return EMPTY
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import { combineLatest, map } from "rxjs"
|
||||||
|
|
||||||
import { configuration } from "~/_"
|
import { configuration } from "~/_"
|
||||||
import {
|
import {
|
||||||
getElementOrThrow,
|
getElement,
|
||||||
requestJSON
|
requestJSON
|
||||||
} from "~/browser"
|
} from "~/browser"
|
||||||
import { getComponentElements } from "~/components"
|
import { getComponentElements } from "~/components"
|
||||||
|
|
@ -60,7 +60,7 @@ export function setupVersionSelector(): void {
|
||||||
/* Render version selector and warning */
|
/* Render version selector and warning */
|
||||||
combineLatest([versions$, current$])
|
combineLatest([versions$, current$])
|
||||||
.subscribe(([versions, current]) => {
|
.subscribe(([versions, current]) => {
|
||||||
const topic = getElementOrThrow(".md-header__topic")
|
const topic = getElement(".md-header__topic")
|
||||||
topic.appendChild(renderVersionSelector(versions, current))
|
topic.appendChild(renderVersionSelector(versions, current))
|
||||||
|
|
||||||
/* Check if version state was already determined */
|
/* Check if version state was already determined */
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ import { getElements } from "~/browser"
|
||||||
*/
|
*/
|
||||||
interface PatchOptions {
|
interface PatchOptions {
|
||||||
document$: Observable<Document> /* Document observable */
|
document$: Observable<Document> /* Document observable */
|
||||||
tablet$: Observable<boolean> /* Tablet breakpoint observable */
|
tablet$: Observable<boolean> /* Media tablet observable */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,14 @@ import {
|
||||||
withLatestFrom
|
withLatestFrom
|
||||||
} from "rxjs"
|
} from "rxjs"
|
||||||
|
|
||||||
import { resetScrollLock, setScrollLock } from "~/actions"
|
import {
|
||||||
import { Viewport, watchToggle } from "~/browser"
|
resetScrollLock,
|
||||||
|
setScrollLock
|
||||||
|
} from "~/actions"
|
||||||
|
import {
|
||||||
|
Viewport,
|
||||||
|
watchToggle
|
||||||
|
} from "~/browser"
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
* Helper types
|
* Helper types
|
||||||
|
|
@ -44,7 +50,7 @@ import { Viewport, watchToggle } from "~/browser"
|
||||||
*/
|
*/
|
||||||
interface PatchOptions {
|
interface PatchOptions {
|
||||||
viewport$: Observable<Viewport> /* Viewport observable */
|
viewport$: Observable<Viewport> /* Viewport observable */
|
||||||
tablet$: Observable<boolean> /* Tablet breakpoint observable */
|
tablet$: Observable<boolean> /* Media tablet observable */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ import { h } from "~/utilities"
|
||||||
* ------------------------------------------------------------------------- */
|
* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render a 'copy-to-clipboard' button
|
* Render a a code annotation
|
||||||
*
|
*
|
||||||
* @param id - Unique identifier
|
* @param id - Unique identifier
|
||||||
* @param content - Annotation content
|
* @param content - Annotation content
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
* IN THE SOFTWARE.
|
* IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { getElementOrThrow, getElements } from "~/browser"
|
import { getElement, getElements } from "~/browser"
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
* Types
|
* Types
|
||||||
|
|
@ -84,7 +84,7 @@ interface ComponentTypeMap {
|
||||||
export function getComponentElement<T extends ComponentType>(
|
export function getComponentElement<T extends ComponentType>(
|
||||||
type: T, node: ParentNode = document
|
type: T, node: ParentNode = document
|
||||||
): ComponentTypeMap[T] {
|
): ComponentTypeMap[T] {
|
||||||
return getElementOrThrow(`[data-mdx-component=${type}]`, node)
|
return getElement(`[data-mdx-component=${type}]`, node)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,8 @@ import {
|
||||||
setSearchResultMeta
|
setSearchResultMeta
|
||||||
} from "~/actions"
|
} from "~/actions"
|
||||||
import {
|
import {
|
||||||
getElementOrThrow,
|
getElement,
|
||||||
watchElementThreshold
|
watchElementBoundary
|
||||||
} from "~/browser"
|
} from "~/browser"
|
||||||
|
|
||||||
import { Icon, renderIconSearchResult } from "_/templates"
|
import { Icon, renderIconSearchResult } from "_/templates"
|
||||||
|
|
@ -147,13 +147,13 @@ export function mountIconSearchResult(
|
||||||
el: HTMLElement, { index$, query$ }: MountOptions
|
el: HTMLElement, { index$, query$ }: MountOptions
|
||||||
): Observable<Component<IconSearchResult, HTMLElement>> {
|
): Observable<Component<IconSearchResult, HTMLElement>> {
|
||||||
const internal$ = new Subject<IconSearchResult>()
|
const internal$ = new Subject<IconSearchResult>()
|
||||||
const boundary$ = watchElementThreshold(el)
|
const boundary$ = watchElementBoundary(el)
|
||||||
.pipe(
|
.pipe(
|
||||||
filter(Boolean)
|
filter(Boolean)
|
||||||
)
|
)
|
||||||
|
|
||||||
/* Update search result metadata */
|
/* Update search result metadata */
|
||||||
const meta = getElementOrThrow(":scope > :first-child", el)
|
const meta = getElement(":scope > :first-child", el)
|
||||||
internal$
|
internal$
|
||||||
.pipe(
|
.pipe(
|
||||||
observeOn(animationFrameScheduler),
|
observeOn(animationFrameScheduler),
|
||||||
|
|
@ -167,7 +167,7 @@ export function mountIconSearchResult(
|
||||||
})
|
})
|
||||||
|
|
||||||
/* Update icon search result list */
|
/* Update icon search result list */
|
||||||
const list = getElementOrThrow(":scope > :last-child", el)
|
const list = getElement(":scope > :last-child", el)
|
||||||
internal$
|
internal$
|
||||||
.pipe(
|
.pipe(
|
||||||
observeOn(animationFrameScheduler),
|
observeOn(animationFrameScheduler),
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
import { Observable, map } from "rxjs"
|
import { Observable, map } from "rxjs"
|
||||||
|
|
||||||
import { getElementOrThrow, requestJSON } from "~/browser"
|
import { getElement, requestJSON } from "~/browser"
|
||||||
|
|
||||||
import { renderPrivateSponsor, renderPublicSponsor } from "_/templates"
|
import { renderPrivateSponsor, renderPublicSponsor } from "_/templates"
|
||||||
|
|
||||||
|
|
@ -121,7 +121,7 @@ export function mountSponsorship(
|
||||||
el.removeAttribute("hidden")
|
el.removeAttribute("hidden")
|
||||||
|
|
||||||
/* Render public sponsors with avatar and links */
|
/* Render public sponsors with avatar and links */
|
||||||
const list = getElementOrThrow(":scope > :first-child", el)
|
const list = getElement(":scope > :first-child", el)
|
||||||
for (const sponsor of sponsorship.sponsors)
|
for (const sponsor of sponsorship.sponsors)
|
||||||
if (sponsor.type === "public")
|
if (sponsor.type === "public")
|
||||||
list.appendChild(renderPublicSponsor(sponsor.user))
|
list.appendChild(renderPublicSponsor(sponsor.user))
|
||||||
|
|
|
||||||
|
|
@ -182,6 +182,7 @@ export function transformScript(
|
||||||
map: Buffer.from(data, "base64")
|
map: Buffer.from(data, "base64")
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
|
catchError(() => NEVER),
|
||||||
switchMap(({ js, map }) => {
|
switchMap(({ js, map }) => {
|
||||||
const file = digest(options.to, js)
|
const file = digest(options.to, js)
|
||||||
return concat(
|
return concat(
|
||||||
|
|
|
||||||
|
|
@ -106,9 +106,10 @@ declare global {
|
||||||
var target$: Observable<HTMLElement> /* Location target observable */
|
var target$: Observable<HTMLElement> /* Location target observable */
|
||||||
var keyboard$: Observable<Keyboard> /* Keyboard observable */
|
var keyboard$: Observable<Keyboard> /* Keyboard observable */
|
||||||
var viewport$: Observable<Viewport> /* Viewport obsevable */
|
var viewport$: Observable<Viewport> /* Viewport obsevable */
|
||||||
var tablet$: Observable<boolean> /* Tablet breakpoint observable */
|
var tablet$: Observable<boolean> /* Media tablet observable */
|
||||||
var screen$: Observable<boolean> /* Screen breakpoint observable */
|
var screen$: Observable<boolean> /* Media screen observable */
|
||||||
var print$: Observable<boolean> /* Print observable */
|
var hover$: Observable<boolean> /* Media hover observable */
|
||||||
|
var print$: Observable<boolean> /* Media print observable */
|
||||||
var alert$: Subject<string> /* Alert subject */
|
var alert$: Subject<string> /* Alert subject */
|
||||||
var component$: Observable<Component>/* Component observable */
|
var component$: Observable<Component>/* Component observable */
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue