Added back patched

This commit is contained in:
squidfunk
2021-02-12 16:22:06 +01:00
parent d664fafa6a
commit 44751785a0
22 changed files with 247 additions and 31 deletions

View File

@@ -58,6 +58,10 @@ import {
setupClipboardJS,
setupInstantLoading
} from "./integrations"
import {
patchIndeterminate,
patchScrollfix
} from "./patches"
/* ----------------------------------------------------------------------------
* Program
@@ -86,6 +90,10 @@ setupClipboardJS({ alert$ })
if (feature("navigation.instant"))
setupInstantLoading({ document$, location$, viewport$ })
/* Set up patches */
patchIndeterminate({ document$ })
patchScrollfix({ document$ })
/* Set up header observable */
const header$ = watchHeader(
getElementOrThrow("[data-md-component=header]"),

View File

@@ -21,6 +21,7 @@
*/
import {
EMPTY,
NEVER,
Observable,
Subject,
@@ -31,6 +32,7 @@ import {
import {
bufferCount,
catchError,
concatMap,
debounceTime,
distinctUntilChanged,
distinctUntilKeyChanged,
@@ -47,7 +49,9 @@ import { configuration } from "~/_"
import {
Viewport,
ViewportOffset,
createElement,
getElement,
getElementOrThrow,
getElements,
replaceElement,
request,
@@ -279,17 +283,44 @@ export function setupInstantLoading(
"[data-md-component=container]",
"[data-md-component=skip]"
]) {
const next = getElement(selector, replacement)
const prev = getElement(selector)
const source = getElement(selector)
const target = getElement(selector, replacement)
if (
typeof next !== "undefined" &&
typeof prev !== "undefined"
typeof source !== "undefined" &&
typeof target !== "undefined"
) {
replaceElement(prev, next)
replaceElement(source, target)
}
}
})
/* Re-evaluate scripts */
document$
.pipe(
skip(1),
map(() => getElementOrThrow("[data-md-component=container]")),
switchMap(el => of(...getElements("script", el))),
concatMap(el => {
const script = createElement("script")
if (el.src) {
script.src = el.src
replaceElement(el, script)
/* Complete when script is loaded */
return new Observable(observer => {
script.onload = () => observer.complete()
})
/* Complete immediately */
} else {
script.textContent = el.textContent!
replaceElement(el, script)
return EMPTY
}
})
)
.subscribe()
/* Debounce update of viewport offset */
viewport$
.pipe(

View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2016-2020 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 } from "rxjs"
import { getElements } from "~/browser"
/* ----------------------------------------------------------------------------
* Helper types
* ------------------------------------------------------------------------- */
/**
* Patch options
*/
interface PatchOptions {
document$: Observable<Document> /* Document observable */
}
/* ----------------------------------------------------------------------------
* Functions
* ------------------------------------------------------------------------- */
/**
* Patch indeterminate checkboxes
*
* @param options - Options
*/
export function patchIndeterminate(
{ document$ }: PatchOptions
): void {
document$.subscribe(() => {
for (const el of getElements<HTMLInputElement>(
"[data-md-state=indeterminate]"
)) {
el.setAttribute("data-md-state", "")
el.indeterminate = true
el.checked = false
}
})
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright (c) 2016-2020 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 "./indeterminate"
export * from "./scrollfix"

View File

@@ -0,0 +1,94 @@
/*
* Copyright (c) 2016-2020 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, of } from "rxjs"
import { mapTo, mergeMap, switchMap, tap } from "rxjs/operators"
import { getElements } from "~/browser"
/* ----------------------------------------------------------------------------
* Helper types
* ------------------------------------------------------------------------- */
/**
* Patch options
*/
interface PatchOptions {
document$: Observable<Document> /* Document observable */
}
/* ----------------------------------------------------------------------------
* Helper functions
* ------------------------------------------------------------------------- */
/**
* Check whether the given device is an Apple device
*
* @returns Test result
*/
function isAppleDevice(): boolean {
return /(iPad|iPhone|iPod)/.test(navigator.userAgent)
}
/* ----------------------------------------------------------------------------
* Functions
* ------------------------------------------------------------------------- */
/**
* Patch all elements with `data-md-scrollfix` attributes
*
* This is a year-old patch which ensures that overflow scrolling works at the
* top and bottom of containers on iOS by ensuring a `1px` scroll offset upon
* the start of a touch event.
*
* @see https://bit.ly/2SCtAOO - Original source
*
* @param options - Options
*/
export function patchScrollfix(
{ document$ }: PatchOptions
): void {
if (isAppleDevice()) {
document$
.pipe(
switchMap(() => of(...getElements("[data-md-scrollfix]"))),
tap(el => el.removeAttribute("data-md-scrollfix")),
mergeMap(el => fromEvent(el, "touchstart")
.pipe(
mapTo(el)
)
)
)
.subscribe(el => {
const top = el.scrollTop
/* We're at the top of the container */
if (top === 0) {
el.scrollTop = 1
/* We're at the bottom of the container */
} else if (top + el.offsetHeight === el.scrollHeight) {
el.scrollTop = top - 1
}
})
}
}