Fixed anchor jump from mobile search

This commit is contained in:
squidfunk 2020-02-16 00:23:50 +01:00
parent a539eab0b5
commit a399540940
18 changed files with 112 additions and 136 deletions

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

View File

@ -1,10 +1,10 @@
{
"assets/javascripts/bundle.js": "assets/javascripts/bundle.676c670f.min.js",
"assets/javascripts/bundle.js.map": "assets/javascripts/bundle.676c670f.min.js.map",
"assets/javascripts/bundle.js": "assets/javascripts/bundle.a0e3393a.min.js",
"assets/javascripts/bundle.js.map": "assets/javascripts/bundle.a0e3393a.min.js.map",
"assets/javascripts/worker/packer.js": "assets/javascripts/worker/packer.c14659e8.min.js",
"assets/javascripts/worker/packer.js.map": "assets/javascripts/worker/packer.c14659e8.min.js.map",
"assets/javascripts/worker/search.js": "assets/javascripts/worker/search.3144ce89.min.js",
"assets/javascripts/worker/search.js.map": "assets/javascripts/worker/search.3144ce89.min.js.map",
"assets/stylesheets/app-palette.scss": "assets/stylesheets/app-palette.8c25017f.min.css",
"assets/stylesheets/app.scss": "assets/stylesheets/app.a4472ab8.min.css"
"assets/stylesheets/app.scss": "assets/stylesheets/app.3d7b25ce.min.css"
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -43,7 +43,7 @@
{% endif %}
{% endblock %}
{% block styles %}
<link rel="stylesheet" href="{{ 'assets/stylesheets/app.a4472ab8.min.css' | url }}">
<link rel="stylesheet" href="{{ 'assets/stylesheets/app.3d7b25ce.min.css' | url }}">
{% if palette.primary or palette.accent %}
<link rel="stylesheet" href="{{ 'assets/stylesheets/app-palette.8c25017f.min.css' | url }}">
{% endif %}
@ -190,7 +190,7 @@
{% endblock %}
</div>
{% block scripts %}
<script src="{{ 'assets/javascripts/bundle.676c670f.min.js' | url }}"></script>
<script src="{{ 'assets/javascripts/bundle.a0e3393a.min.js' | url }}"></script>
<script id="__lang" type="application/json">
{%- set translations = {} -%}
{%- for key in [

View File

@ -19,7 +19,7 @@
<label class="md-nav__title" for="{{ path }}">
{{ nav_item.title }}
</label>
<ul class="md-nav__list">
<ul class="md-nav__list" data-md-scrollfix>
{% set base = path %}
{% for nav_item in nav_item.children %}
{% set path = base + "-" + loop.index | string %}

View File

@ -17,7 +17,7 @@
{% include "partials/source.html" %}
</div>
{% endif %}
<ul class="md-nav__list">
<ul class="md-nav__list" data-md-scrollfix>
{% for nav_item in nav %}
{% set path = "nav-" + loop.index | string %}
{% set level = 1 %}

View File

@ -13,7 +13,7 @@
</button>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
{{ lang.t("search.result.placeholder") }}

View File

@ -9,7 +9,7 @@
{% endif %}
{% if toc_ | first is defined %}
<label class="md-nav__title" for="__toc">{{ lang.t("toc.title") }}</label>
<ul class="md-nav__list">
<ul class="md-nav__list" data-md-scrollfix>
{% for toc_item in toc_ %}
{% include "partials/toc-item.html" %}
{% endfor %}

View File

@ -26,12 +26,13 @@
import "../stylesheets/app.scss"
import "../stylesheets/app-palette.scss"
import { values } from "ramda"
import { values, identity } from "ramda"
import {
EMPTY,
merge,
of,
NEVER
NEVER,
combineLatest
} from "rxjs"
import {
delay,
@ -53,6 +54,7 @@ import {
getElements,
watchMedia,
watchDocument,
watchLocation,
watchLocationHash,
watchViewport,
watchKeyboard,
@ -98,7 +100,7 @@ if (navigator.userAgent.match(/(iPad|iPhone|iPod)/g))
*/
function repository() {
const el = getElement<HTMLAnchorElement>(".md-source[href]") // TODO: dont use classes
console.log(el)
// console.log(el)
if (!el)
return EMPTY
@ -165,6 +167,7 @@ export function initialize(config: unknown) {
// pass config here!?
const document$ = watchDocument()
const location$ = watchLocation()
const hash$ = watchLocationHash()
const keyboard$ = watchKeyboard()
const viewport$ = watchViewport()
@ -251,7 +254,9 @@ export function initialize(config: unknown) {
)
})
)
.subscribe(console.log)
.subscribe()
// paintHeaderTitle <- same with shadow...
/* ----------------------------------------------------------------------- */
@ -274,23 +279,39 @@ export function initialize(config: unknown) {
/* ----------------------------------------------------------------------- */
// Close drawer and search on hash change
hash$.subscribe(() => {
hash$.subscribe(x => {
useToggle("drawer").subscribe(el => {
setToggle(el, false)
})
useToggle("search").subscribe(el => { // omit nested subscribes...
setToggle(el, false)
})
})
// TODO:
hash$
.pipe(
switchMap(hash => {
return useToggle("search")
.pipe(
filter(x => x.checked), // only active
tap(toggle => setToggle(toggle, false)),
delay(125), // ensure that it runs after the body scroll reset...
tap(() => {
location.hash = " "
location.hash = hash
}) // encapsulate this...
)
})
)
.subscribe()
/* ----------------------------------------------------------------------- */
// watchClipboard
mountClipboard({ document$ })
.subscribe(console.log)
.subscribe()
// TODO: WIP repo rendering
repository().subscribe(facts => {
@ -306,68 +327,65 @@ export function initialize(config: unknown) {
})
patchTables({ document$ })
.subscribe(console.log)
.subscribe()
patchDetails({ document$ })
.subscribe(console.log)
.subscribe()
// // TODO: must be reset when tablet/toggle is left
// const toggle$ = useToggle("search")
// toggle$
// .pipe(
// switchMap(watchToggle),
// skip(1),
// switchMap(toggle => viewport$
// .pipe(
// take(1),
// pluck("offset"),
// delay(toggle ? 400 : 100)
// )
// ),
// startWith({ x: 0, y: 0 }),
// bufferCount(2, 1),
// takeIf(not(tablet$)), // TODO: wrong position
// map(([offset]) => offset)
// )
// .subscribe(offset => {
// // TODO: this will also trigger if we started at the top.
// document.body.dataset.mdState = offset.y ? "" : "lock" // TODO: refactor
// setViewportOffset(offset)
// })
// scroll lock
let scroll = 0
combineLatest([
useToggle("search")
.pipe(
switchMap(watchToggle)
),
tablet$,
]).pipe(
tap(([toggle, tablet]) => {
if (toggle && !tablet) {
scroll = scrollY
setTimeout(() => {
requestAnimationFrame(() => {
document.body.style.position = 'fixed';
document.body.style.top = `-${scroll}px`;
// data.mdState = lock
})
}, 400)
} else {
// accidentally triggers on resize
// let lastOffset = 0
// tablet$.pipe(
// switchMap(active => {
// return !active ? watchToggle(search) : NEVER
// }),
// switchMap(toggle => {
// if (toggle) {
// console.log("ACTIVE")
// return of(document.body)
// .pipe(
// tap(() => lastOffset = window.pageYOffset),
// delay(400),
// tap(() => {
// window.scrollTo(0, 0),
// console.log("scrolled... to top, locked body")
// document.body.dataset.mdState = "lock"
// })
// )
// } else {
// console.log("INACTIVE")
// return of(document.body)
// .pipe(
// tap(() => document.body.dataset.mdState = ""),
// delay(100),
// tap(() => {
// window.scrollTo(0, lastOffset) // setViewportOffset !
// })
// )
// }
// })
// )
// .subscribe(x => console.log("SEARCHLOCK", x))
/* Scroll to former position, but wait for 100ms to prevent flashes on
iOS. A short timeout seems to do the trick */
setTimeout(() => {
requestAnimationFrame(() => {
document.body.style.position = '';
document.body.style.top = '';
if (scroll)
window.scrollTo(0, scroll)
})
}, 100)
}
})
)
.subscribe()
/* Force 1px scroll offset to trigger overflow scrolling */
if (true || navigator.userAgent.match(/(iPad|iPhone|iPod)/g)) {
const scrollable = document.querySelectorAll("[data-md-scrollfix]")
Array.prototype.forEach.call(scrollable, item => {
item.addEventListener("touchstart", () => {
const top = item.scrollTop
/* We're at the top of the container */
if (top === 0) {
item.scrollTop = 1
/* We're at the bottom of the container */
} else if (top + item.offsetHeight === item.scrollHeight) {
item.scrollTop = top - 1
}
})
})
}
/* ----------------------------------------------------------------------- */

View File

@ -20,55 +20,13 @@
* IN THE SOFTWARE.
*/
import {
EMPTY,
MonoTypeOperatorFunction,
Observable,
OperatorFunction,
combineLatest,
of,
pipe
} from "rxjs"
import {
filter,
map,
switchMap,
takeUntil,
withLatestFrom
} from "rxjs/operators"
import { MonoTypeOperatorFunction, Observable, pipe } from "rxjs"
import { filter, map, withLatestFrom } from "rxjs/operators"
/* ----------------------------------------------------------------------------
* Functions
* ------------------------------------------------------------------------- */
/**
* Toggle switch map with another observable
*
* @template T - Source value type
* @template U - Target value type
*
* @param toggle$ - Toggle observable
* @param project - Projection
*
* @return Operator function
*/
export function switchMapIf<T, U>(
toggle$: Observable<boolean>, project: (value: T) => Observable<U>
): OperatorFunction<T, U> {
const begin$ = toggle$.pipe(filter(value => value))
const end$ = toggle$.pipe(filter(value => !value))
return pipe(
switchMap(value => combineLatest([of(value), begin$])),
switchMap(([value, active]) => active
? project(value)
.pipe(
takeUntil(end$)
)
: EMPTY
)
)
}
/**
* Toggle emission with another observable
*

View File

@ -56,7 +56,7 @@
<label class="md-nav__title" for="{{ path }}">
{{ nav_item.title }}
</label>
<ul class="md-nav__list">
<ul class="md-nav__list" data-md-scrollfix>
<!-- Render nested item list -->
{% set base = path %}

View File

@ -52,7 +52,7 @@
{% endif %}
<!-- Render item list -->
<ul class="md-nav__list">
<ul class="md-nav__list" data-md-scrollfix>
{% for nav_item in nav %}
{% set path = "nav-" + loop.index | string %}
{% set level = 1 %}

View File

@ -50,7 +50,7 @@
</button>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
{{ lang.t("search.result.placeholder") }}

View File

@ -39,7 +39,7 @@
<!-- Render item list -->
{% if toc_ | first is defined %}
<label class="md-nav__title" for="__toc">{{ lang.t("toc.title") }}</label>
<ul class="md-nav__list">
<ul class="md-nav__list" data-md-scrollfix>
{% for toc_item in toc_ %}
{% include "partials/toc-item.html" %}
{% endfor %}