Added method to retrieve element or throw

This commit is contained in:
squidfunk 2020-02-14 09:52:22 +01:00
parent 718b51bac9
commit 8c92565b7b
6 changed files with 50 additions and 29 deletions

View File

@ -24,8 +24,7 @@ import { Observable, OperatorFunction, pipe } from "rxjs"
import { import {
distinctUntilKeyChanged, distinctUntilKeyChanged,
shareReplay, shareReplay,
switchMap, switchMap
tap
} from "rxjs/operators" } from "rxjs/operators"
import { import {

View File

@ -32,7 +32,7 @@
* @param selector - Query selector * @param selector - Query selector
* @param node - Node of reference * @param node - Node of reference
* *
* @return Element * @return Element or nothing
*/ */
export function getElement<T extends HTMLElement>( export function getElement<T extends HTMLElement>(
selector: string, node: ParentNode = document selector: string, node: ParentNode = document
@ -40,6 +40,38 @@ export function getElement<T extends HTMLElement>(
return node.querySelector<T>(selector) || 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
*
* @return Element
*/
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 match an element`
)
return el
}
/**
* Retrieve the currently active element
*
* @return Element
*/
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
* *
@ -55,16 +87,3 @@ export function getElements<T extends HTMLElement>(
): T[] { ): T[] {
return Array.from(node.querySelectorAll<T>(selector)) return Array.from(node.querySelectorAll<T>(selector))
} }
/* ------------------------------------------------------------------------- */
/**
* Retrieve the currently active element
*
* @return Element
*/
export function getActiveElement(): HTMLElement | undefined {
return document.activeElement instanceof HTMLElement
? document.activeElement
: undefined
}

View File

@ -44,7 +44,10 @@ import {
setOverflowScrolling setOverflowScrolling
} from "actions" } from "actions"
import { getElement } from "../../agent" import {
getElement,
getElementOrThrow
} from "../../agent"
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* Types * Types
@ -67,7 +70,7 @@ export interface NavigationLayer {
* *
* On iOS we want to add `-webkit-overflow-scrolling: touch` for the menus * On iOS we want to add `-webkit-overflow-scrolling: touch` for the menus
* contained in the drawer, but as the navigational layers are nested, we can * contained in the drawer, but as the navigational layers are nested, we can
* only add it to the navigation layer or extremely weird cropping will occur. * only add it to the topmost layer or extremely weird cropping will occur.
* This implementation keeps track of the previous and current layer. * This implementation keeps track of the previous and current layer.
* *
* @param els - Navigation elements * @param els - Navigation elements
@ -81,19 +84,19 @@ export function watchNavigationLayer(
for (const el of els) { for (const el of els) {
const label = getElement<HTMLLabelElement>("label", el) const label = getElement<HTMLLabelElement>("label", el)
if (typeof label !== "undefined") { if (typeof label !== "undefined") {
const input = getElement<HTMLInputElement>(`#${label.htmlFor}`)! const input = getElementOrThrow<HTMLInputElement>(`#${label.htmlFor}`)
table.set(input, el) table.set(input, el)
} }
} }
/* Determine active layer */ /* Determine topmost layer */
const layer$ = merge( const layer$ = merge(
...[...table.keys()].map(input => fromEvent(input, "change")) ...[...table.keys()].map(input => fromEvent(input, "change"))
) )
.pipe( .pipe(
map(() => getElement(".md-nav__list", table.get( map(() => getElementOrThrow(".md-nav__list", table.get(
findLast(({ checked }) => checked, [...table.keys()])! findLast(({ checked }) => checked, [...table.keys()])!
))!) )))
) )
/* Return previous and next layer */ /* Return previous and next layer */
@ -139,7 +142,7 @@ export function paintNavigationLayer(
finalize(() => { finalize(() => {
for (const el of els) for (const el of els)
resetOverflowScrolling( resetOverflowScrolling(
getElement(".md-nav__list", el)! getElementOrThrow(".md-nav__list", el)
) )
}) })
) )

View File

@ -45,7 +45,7 @@ import {
import { SearchResult } from "modules" import { SearchResult } from "modules"
import { renderSearchResult } from "templates" import { renderSearchResult } from "templates"
import { getElement } from "../../agent" import { getElementOrThrow } from "../../agent"
import { SearchQuery } from "../query" import { SearchQuery } from "../query"
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
@ -75,8 +75,8 @@ interface PaintOptions {
export function paintSearchResult( export function paintSearchResult(
el: HTMLElement, { query$, fetch$ }: PaintOptions el: HTMLElement, { query$, fetch$ }: PaintOptions
): MonoTypeOperatorFunction<SearchResult[]> { ): MonoTypeOperatorFunction<SearchResult[]> {
const list = getElement(".md-search-result__list", el)! const list = getElementOrThrow(".md-search-result__list", el)
const meta = getElement(".md-search-result__meta", el)! const meta = getElementOrThrow(".md-search-result__meta", el)
return pipe( return pipe(
/* Paint search result metadata */ /* Paint search result metadata */

View File

@ -20,7 +20,7 @@
* IN THE SOFTWARE. * IN THE SOFTWARE.
*/ */
import { getElement } from "observables" import { getElementOrThrow } from "observables"
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* Data * Data
@ -45,7 +45,7 @@ let lang: Record<string, string>
*/ */
export function translate(key: string, value?: string): string { export function translate(key: string, value?: string): string {
if (typeof lang === "undefined") { if (typeof lang === "undefined") {
const el = getElement("#__lang")! const el = getElementOrThrow("#__lang")
lang = JSON.parse(el.innerText) lang = JSON.parse(el.innerText)
} }
if (typeof lang[key] === "undefined") { if (typeof lang[key] === "undefined") {

View File

@ -301,7 +301,7 @@ $codehilite-whitespace: transparent;
// When pymdownx.superfences is enabled but codehilite is disabled, // When pymdownx.superfences is enabled but codehilite is disabled,
// pymdownx.highlight will be used. When this happens, the outer // pymdownx.highlight will be used. When this happens, the outer
// container and tables get this class names by default. // container and tables get this class names by default
.highlight { .highlight {
@extend .codehilite; @extend .codehilite;
} }