mirror of
https://github.com/squidfunk/mkdocs-material.git
synced 2024-06-14 11:52:32 +03:00
Implemented instant loading
This commit is contained in:
parent
3aa251fb03
commit
ae1ed3d924
24
material/assets/javascripts/bundle.1defb77e.min.js
vendored
Normal file
24
material/assets/javascripts/bundle.1defb77e.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
material/assets/javascripts/bundle.1defb77e.min.js.map
Normal file
1
material/assets/javascripts/bundle.1defb77e.min.js.map
Normal file
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
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"assets/javascripts/bundle.js": "assets/javascripts/bundle.4cda9c77.min.js",
|
"assets/javascripts/bundle.js": "assets/javascripts/bundle.1defb77e.min.js",
|
||||||
"assets/javascripts/bundle.js.map": "assets/javascripts/bundle.4cda9c77.min.js.map",
|
"assets/javascripts/bundle.js.map": "assets/javascripts/bundle.1defb77e.min.js.map",
|
||||||
"assets/javascripts/worker/search.js": "assets/javascripts/worker/search.926ffd9e.min.js",
|
"assets/javascripts/worker/search.js": "assets/javascripts/worker/search.926ffd9e.min.js",
|
||||||
"assets/javascripts/worker/search.js.map": "assets/javascripts/worker/search.926ffd9e.min.js.map",
|
"assets/javascripts/worker/search.js.map": "assets/javascripts/worker/search.926ffd9e.min.js.map",
|
||||||
"assets/stylesheets/app-palette.scss": "assets/stylesheets/app-palette.3f90c815.min.css",
|
"assets/stylesheets/app-palette.scss": "assets/stylesheets/app-palette.3f90c815.min.css",
|
||||||
|
@ -190,7 +190,7 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
<script src="{{ 'assets/javascripts/bundle.4cda9c77.min.js' | url }}"></script>
|
<script src="{{ 'assets/javascripts/bundle.1defb77e.min.js' | url }}"></script>
|
||||||
<script id="__lang" type="application/json">
|
<script id="__lang" type="application/json">
|
||||||
{%- set translations = {} -%}
|
{%- set translations = {} -%}
|
||||||
{%- for key in [
|
{%- for key in [
|
||||||
@ -209,7 +209,17 @@
|
|||||||
{%- endfor -%}
|
{%- endfor -%}
|
||||||
{{ translations | tojson }}
|
{{ translations | tojson }}
|
||||||
</script>
|
</script>
|
||||||
<script>app=initialize({base:"{{ base_url }}",worker:{search:"{{ 'assets/javascripts/worker/search.926ffd9e.min.js' | url }}"}})</script>
|
<script>
|
||||||
|
app = initialize({
|
||||||
|
base: "{{ base_url }}",
|
||||||
|
worker: {
|
||||||
|
search: "{{ 'assets/javascripts/worker/search.926ffd9e.min.js' | url }}"
|
||||||
|
},
|
||||||
|
feature: {
|
||||||
|
instant: {{ feature.instant | tojson }}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</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 %}
|
||||||
|
@ -32,6 +32,10 @@ feature:
|
|||||||
# of tabs, especially useful for larger documentation projects
|
# of tabs, especially useful for larger documentation projects
|
||||||
tabs: false
|
tabs: false
|
||||||
|
|
||||||
|
# Instant loading will instruct the application to intercept all internal
|
||||||
|
# links, load and inject the HTML into the page and rebind all handlers
|
||||||
|
instant: false
|
||||||
|
|
||||||
# Sets the primary and accent color palettes as defined in the Material Design
|
# Sets the primary and accent color palettes as defined in the Material Design
|
||||||
# documentation - possible values can be looked up in the getting started guide
|
# documentation - possible values can be looked up in the getting started guide
|
||||||
palette:
|
palette:
|
||||||
|
@ -22,4 +22,4 @@
|
|||||||
mkdocs>=1.0
|
mkdocs>=1.0
|
||||||
Pygments>=2.4
|
Pygments>=2.4
|
||||||
markdown>=3.2
|
markdown>=3.2
|
||||||
pymdown-extensions>=7.0b1
|
pymdown-extensions>=7.0b2
|
||||||
|
@ -22,7 +22,14 @@
|
|||||||
|
|
||||||
import { keys } from "ramda"
|
import { keys } from "ramda"
|
||||||
import { NEVER, Observable, of } from "rxjs"
|
import { NEVER, Observable, of } from "rxjs"
|
||||||
import { map, scan, shareReplay, switchMap } from "rxjs/operators"
|
import {
|
||||||
|
distinctUntilChanged,
|
||||||
|
map,
|
||||||
|
scan,
|
||||||
|
shareReplay,
|
||||||
|
switchMap,
|
||||||
|
tap
|
||||||
|
} from "rxjs/operators"
|
||||||
|
|
||||||
import { getElement } from "observables"
|
import { getElement } from "observables"
|
||||||
|
|
||||||
@ -92,7 +99,7 @@ let components$: Observable<ComponentMap>
|
|||||||
export function watchComponentMap(
|
export function watchComponentMap(
|
||||||
names: Component[], { document$ }: WatchOptions
|
names: Component[], { document$ }: WatchOptions
|
||||||
): Observable<ComponentMap> {
|
): Observable<ComponentMap> {
|
||||||
components$ = document$
|
return components$ = document$
|
||||||
.pipe(
|
.pipe(
|
||||||
|
|
||||||
/* Build component map */
|
/* Build component map */
|
||||||
@ -124,12 +131,9 @@ export function watchComponentMap(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return prev
|
return prev
|
||||||
})
|
}),
|
||||||
)
|
|
||||||
|
|
||||||
/* Return component map as hot observable */
|
/* Convert to hot observable */
|
||||||
return components$
|
|
||||||
.pipe(
|
|
||||||
shareReplay(1)
|
shareReplay(1)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -152,6 +156,7 @@ export function useComponent<T extends HTMLElement>(
|
|||||||
typeof components[name] !== "undefined"
|
typeof components[name] !== "undefined"
|
||||||
? of(components[name] as T)
|
? of(components[name] as T)
|
||||||
: NEVER
|
: NEVER
|
||||||
))
|
)),
|
||||||
|
distinctUntilChanged()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Observable, OperatorFunction, pipe } from "rxjs"
|
import { Observable, OperatorFunction, pipe } from "rxjs"
|
||||||
import { shareReplay, switchMap } from "rxjs/operators"
|
import { switchMap } from "rxjs/operators"
|
||||||
|
|
||||||
import { Header, Viewport, watchHeader } from "observables"
|
import { Header, Viewport, watchHeader } from "observables"
|
||||||
|
|
||||||
@ -51,7 +51,6 @@ export function mountHeader(
|
|||||||
{ viewport$ }: MountOptions
|
{ viewport$ }: MountOptions
|
||||||
): OperatorFunction<HTMLElement, Header> {
|
): OperatorFunction<HTMLElement, Header> {
|
||||||
return pipe(
|
return pipe(
|
||||||
switchMap(el => watchHeader(el, { viewport$ })),
|
switchMap(el => watchHeader(el, { viewport$ }))
|
||||||
shareReplay(1)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -21,12 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Observable, OperatorFunction, pipe } from "rxjs"
|
import { Observable, OperatorFunction, pipe } from "rxjs"
|
||||||
import {
|
import { filter, map, switchMap } from "rxjs/operators"
|
||||||
filter,
|
|
||||||
map,
|
|
||||||
shareReplay,
|
|
||||||
switchMap
|
|
||||||
} from "rxjs/operators"
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Header,
|
Header,
|
||||||
@ -74,8 +69,7 @@ export function mountHeaderTitle(
|
|||||||
map(({ offset: { y } }) => y >= hx.offsetHeight),
|
map(({ offset: { y } }) => y >= hx.offsetHeight),
|
||||||
paintHeaderTitle(el)
|
paintHeaderTitle(el)
|
||||||
)
|
)
|
||||||
),
|
)
|
||||||
shareReplay(1)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Observable, OperatorFunction, pipe } from "rxjs"
|
import { Observable, OperatorFunction, pipe } from "rxjs"
|
||||||
import { map, shareReplay, switchMap } from "rxjs/operators"
|
import { map, switchMap } from "rxjs/operators"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Header,
|
Header,
|
||||||
@ -73,7 +73,6 @@ export function mountHero(
|
|||||||
paintHideable(el, 20),
|
paintHideable(el, 20),
|
||||||
map(hidden => ({ hidden }))
|
map(hidden => ({ hidden }))
|
||||||
)
|
)
|
||||||
),
|
)
|
||||||
shareReplay(1)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -21,11 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Observable, OperatorFunction, pipe } from "rxjs"
|
import { Observable, OperatorFunction, pipe } from "rxjs"
|
||||||
import {
|
import { distinctUntilKeyChanged, switchMap } from "rxjs/operators"
|
||||||
distinctUntilKeyChanged,
|
|
||||||
shareReplay,
|
|
||||||
switchMap
|
|
||||||
} from "rxjs/operators"
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Header,
|
Header,
|
||||||
@ -81,7 +77,6 @@ export function mountMain(
|
|||||||
return main$
|
return main$
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
),
|
)
|
||||||
shareReplay(1)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Observable, OperatorFunction, pipe } from "rxjs"
|
import { Observable, OperatorFunction, pipe } from "rxjs"
|
||||||
import { map, shareReplay, switchMap } from "rxjs/operators"
|
import { map, switchMap } from "rxjs/operators"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Header,
|
Header,
|
||||||
@ -115,7 +115,6 @@ export function mountNavigation(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
),
|
)
|
||||||
shareReplay(1)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Observable, OperatorFunction, combineLatest, pipe } from "rxjs"
|
import { Observable, OperatorFunction, combineLatest, pipe } from "rxjs"
|
||||||
import { map, shareReplay, switchMap } from "rxjs/operators"
|
import { map, switchMap } from "rxjs/operators"
|
||||||
|
|
||||||
import { SearchResult } from "integrations/search"
|
import { SearchResult } from "integrations/search"
|
||||||
import { SearchQuery } from "observables"
|
import { SearchQuery } from "observables"
|
||||||
@ -68,8 +68,7 @@ export function mountSearch(
|
|||||||
return pipe(
|
return pipe(
|
||||||
switchMap(() => combineLatest([query$, result$, reset$])
|
switchMap(() => combineLatest([query$, result$, reset$])
|
||||||
.pipe(
|
.pipe(
|
||||||
map(([query, result]) => ({ query, result })),
|
map(([query, result]) => ({ query, result }))
|
||||||
shareReplay(1)
|
|
||||||
))
|
))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,6 @@ import {
|
|||||||
filter,
|
filter,
|
||||||
map,
|
map,
|
||||||
pluck,
|
pluck,
|
||||||
shareReplay,
|
|
||||||
switchMap
|
switchMap
|
||||||
} from "rxjs/operators"
|
} from "rxjs/operators"
|
||||||
|
|
||||||
@ -90,7 +89,6 @@ export function mountSearchResult(
|
|||||||
pluck("data"),
|
pluck("data"),
|
||||||
paintSearchResult(el, { query$, fetch$ })
|
paintSearchResult(el, { query$, fetch$ })
|
||||||
)
|
)
|
||||||
}),
|
})
|
||||||
shareReplay(1)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Observable, OperatorFunction, of, pipe } from "rxjs"
|
import { Observable, OperatorFunction, of, pipe } from "rxjs"
|
||||||
import { map, shareReplay, switchMap } from "rxjs/operators"
|
import { map, switchMap } from "rxjs/operators"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Header,
|
Header,
|
||||||
@ -87,7 +87,6 @@ export function mountTabs(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
),
|
)
|
||||||
shareReplay(1)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ import {
|
|||||||
of,
|
of,
|
||||||
pipe
|
pipe
|
||||||
} from "rxjs"
|
} from "rxjs"
|
||||||
import { map, shareReplay, switchMap } from "rxjs/operators"
|
import { map, switchMap } from "rxjs/operators"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AnchorList,
|
AnchorList,
|
||||||
@ -129,7 +129,6 @@ export function mountTableOfContents(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
),
|
)
|
||||||
shareReplay(1)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,10 @@ import { values } from "ramda"
|
|||||||
import {
|
import {
|
||||||
merge,
|
merge,
|
||||||
combineLatest,
|
combineLatest,
|
||||||
animationFrameScheduler
|
animationFrameScheduler,
|
||||||
|
fromEvent,
|
||||||
|
of,
|
||||||
|
NEVER
|
||||||
} from "rxjs"
|
} from "rxjs"
|
||||||
import {
|
import {
|
||||||
delay,
|
delay,
|
||||||
@ -41,7 +44,8 @@ import {
|
|||||||
observeOn,
|
observeOn,
|
||||||
take,
|
take,
|
||||||
mapTo,
|
mapTo,
|
||||||
shareReplay
|
shareReplay,
|
||||||
|
switchMapTo
|
||||||
} from "rxjs/operators"
|
} from "rxjs/operators"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -55,7 +59,8 @@ import {
|
|||||||
watchViewport,
|
watchViewport,
|
||||||
watchToggleMap,
|
watchToggleMap,
|
||||||
useToggle,
|
useToggle,
|
||||||
getElement
|
getElement,
|
||||||
|
watchDocumentSwitch
|
||||||
} from "./observables"
|
} from "./observables"
|
||||||
import { setupSearchWorker } from "./workers"
|
import { setupSearchWorker } from "./workers"
|
||||||
|
|
||||||
@ -108,9 +113,15 @@ export function initialize(config: unknown) {
|
|||||||
if (!isConfig(config))
|
if (!isConfig(config))
|
||||||
throw new SyntaxError(`Invalid configuration: ${JSON.stringify(config)}`)
|
throw new SyntaxError(`Invalid configuration: ${JSON.stringify(config)}`)
|
||||||
|
|
||||||
// pass config here!?
|
|
||||||
const document$ = watchDocument()
|
|
||||||
const location$ = watchLocation()
|
const location$ = watchLocation()
|
||||||
|
|
||||||
|
// instant loading
|
||||||
|
const switch$ = config.feature.instant
|
||||||
|
? watchDocumentSwitch({ location$ })
|
||||||
|
: NEVER
|
||||||
|
|
||||||
|
const load$ = watchDocument()
|
||||||
|
const document$ = merge(load$, switch$)
|
||||||
const hash$ = watchLocationHash()
|
const hash$ = watchLocationHash()
|
||||||
const viewport$ = watchViewport()
|
const viewport$ = watchViewport()
|
||||||
const tablet$ = watchMedia("(min-width: 960px)")
|
const tablet$ = watchMedia("(min-width: 960px)")
|
||||||
@ -147,12 +158,14 @@ export function initialize(config: unknown) {
|
|||||||
/* Create header observable */
|
/* Create header observable */
|
||||||
const header$ = useComponent("header")
|
const header$ = useComponent("header")
|
||||||
.pipe(
|
.pipe(
|
||||||
mountHeader({ viewport$ })
|
mountHeader({ viewport$ }),
|
||||||
|
shareReplay(1)
|
||||||
)
|
)
|
||||||
|
|
||||||
const main$ = useComponent("main")
|
const main$ = useComponent("main")
|
||||||
.pipe(
|
.pipe(
|
||||||
mountMain({ header$, viewport$ })
|
mountMain({ header$, viewport$ }),
|
||||||
|
shareReplay(1)
|
||||||
)
|
)
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
/* ----------------------------------------------------------------------- */
|
||||||
@ -167,47 +180,55 @@ export function initialize(config: unknown) {
|
|||||||
/* Mount search reset */
|
/* Mount search reset */
|
||||||
const reset$ = useComponent("search-reset")
|
const reset$ = useComponent("search-reset")
|
||||||
.pipe(
|
.pipe(
|
||||||
mountSearchReset()
|
mountSearchReset(),
|
||||||
|
shareReplay(1)
|
||||||
)
|
)
|
||||||
|
|
||||||
/* Mount search result */
|
/* Mount search result */
|
||||||
const result$ = useComponent("search-result")
|
const result$ = useComponent("search-result")
|
||||||
.pipe(
|
.pipe(
|
||||||
mountSearchResult(worker, { query$ })
|
mountSearchResult(worker, { query$ }),
|
||||||
|
shareReplay(1)
|
||||||
)
|
)
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
/* ----------------------------------------------------------------------- */
|
||||||
|
|
||||||
const search$ = useComponent("search")
|
const search$ = useComponent("search")
|
||||||
.pipe(
|
.pipe(
|
||||||
mountSearch({ query$, reset$, result$ })
|
mountSearch({ query$, reset$, result$ }),
|
||||||
|
shareReplay(1)
|
||||||
)
|
)
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
/* ----------------------------------------------------------------------- */
|
||||||
|
|
||||||
const navigation$ = useComponent("navigation")
|
const navigation$ = useComponent("navigation")
|
||||||
.pipe(
|
.pipe(
|
||||||
mountNavigation({ header$, main$, viewport$, screen$ })
|
mountNavigation({ header$, main$, viewport$, screen$ }),
|
||||||
|
shareReplay(1)
|
||||||
)
|
)
|
||||||
|
|
||||||
const toc$ = useComponent("toc")
|
const toc$ = useComponent("toc")
|
||||||
.pipe(
|
.pipe(
|
||||||
mountTableOfContents({ header$, main$, viewport$, tablet$ })
|
mountTableOfContents({ header$, main$, viewport$, tablet$ }),
|
||||||
|
shareReplay(1)
|
||||||
)
|
)
|
||||||
|
|
||||||
const tabs$ = useComponent("tabs")
|
const tabs$ = useComponent("tabs")
|
||||||
.pipe(
|
.pipe(
|
||||||
mountTabs({ header$, viewport$, screen$ })
|
mountTabs({ header$, viewport$, screen$ }),
|
||||||
|
shareReplay(1)
|
||||||
)
|
)
|
||||||
|
|
||||||
const hero$ = useComponent("hero")
|
const hero$ = useComponent("hero")
|
||||||
.pipe(
|
.pipe(
|
||||||
mountHero({ header$, viewport$ })
|
mountHero({ header$, viewport$ }),
|
||||||
|
shareReplay(1)
|
||||||
)
|
)
|
||||||
|
|
||||||
const title$ = useComponent("header-title")
|
const title$ = useComponent("header-title")
|
||||||
.pipe(
|
.pipe(
|
||||||
mountHeaderTitle({ header$, viewport$ })
|
mountHeaderTitle({ header$, viewport$ }),
|
||||||
|
shareReplay(1)
|
||||||
)
|
)
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
/* ----------------------------------------------------------------------- */
|
||||||
@ -278,6 +299,50 @@ export function initialize(config: unknown) {
|
|||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
/* ----------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
// instant loading
|
||||||
|
const instant$ = config.feature.instant ? load$ // TODO: just use document$ and take(1)
|
||||||
|
.pipe(
|
||||||
|
switchMap(({ body }) => fromEvent(body, "click")),
|
||||||
|
switchMap(ev => {
|
||||||
|
|
||||||
|
// two cases: search results which should always load from same domain
|
||||||
|
// and/or
|
||||||
|
if (ev.target && ev.target instanceof HTMLElement) {
|
||||||
|
const anchor = ev.target.closest("a")
|
||||||
|
if (anchor) {
|
||||||
|
if (/(:\/\/|^#)/.test(anchor.getAttribute("href")!) === false) {
|
||||||
|
ev.preventDefault()
|
||||||
|
|
||||||
|
// we must copy the value, or weird stuff will happen
|
||||||
|
const href = anchor.href
|
||||||
|
history.pushState(true, "", href)
|
||||||
|
return of(href)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NEVER
|
||||||
|
}),
|
||||||
|
shareReplay(1)
|
||||||
|
)
|
||||||
|
: NEVER
|
||||||
|
|
||||||
|
// deploy new location
|
||||||
|
instant$.subscribe(url => {
|
||||||
|
console.log(`Load ${url}`)
|
||||||
|
location$.next(url)
|
||||||
|
})
|
||||||
|
|
||||||
|
// scroll to top when document is loaded
|
||||||
|
instant$
|
||||||
|
.pipe(
|
||||||
|
switchMapTo(switch$), // TODO: just use document$ and skip(1)
|
||||||
|
)
|
||||||
|
.subscribe(() => {
|
||||||
|
window.scrollTo(0, 0) // TODO: or scroll element into view
|
||||||
|
})
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------- */
|
||||||
|
|
||||||
// if we use a single tab outside of search, unhide all permalinks.
|
// if we use a single tab outside of search, unhide all permalinks.
|
||||||
// TODO: experimental. necessary!?
|
// TODO: experimental. necessary!?
|
||||||
keyboard$
|
keyboard$
|
||||||
|
@ -26,7 +26,7 @@ import {
|
|||||||
distinctUntilChanged,
|
distinctUntilChanged,
|
||||||
map,
|
map,
|
||||||
pluck,
|
pluck,
|
||||||
shareReplay,
|
share,
|
||||||
skip,
|
skip,
|
||||||
startWith,
|
startWith,
|
||||||
switchMap
|
switchMap
|
||||||
@ -67,7 +67,7 @@ export function watchDocumentSwitch(
|
|||||||
return location$
|
return location$
|
||||||
.pipe(
|
.pipe(
|
||||||
startWith(getLocation()),
|
startWith(getLocation()),
|
||||||
map(url => url.replace(/#[^#]+$/, "")),
|
map(url => url.replace(/#[^#]*$/, "")),
|
||||||
distinctUntilChanged(),
|
distinctUntilChanged(),
|
||||||
skip(1),
|
skip(1),
|
||||||
|
|
||||||
@ -81,6 +81,6 @@ export function watchDocumentSwitch(
|
|||||||
pluck("response")
|
pluck("response")
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
shareReplay(1)
|
share()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,6 @@ import {
|
|||||||
map,
|
map,
|
||||||
observeOn,
|
observeOn,
|
||||||
scan,
|
scan,
|
||||||
shareReplay,
|
|
||||||
switchMap,
|
switchMap,
|
||||||
tap
|
tap
|
||||||
} from "rxjs/operators"
|
} from "rxjs/operators"
|
||||||
@ -184,8 +183,8 @@ export function watchAnchorList(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
/* Compute anchor list migrations */
|
/* Compute and return anchor list migrations */
|
||||||
const migration$ = partition$
|
return partition$
|
||||||
.pipe(
|
.pipe(
|
||||||
map(([prev, next]) => ({
|
map(([prev, next]) => ({
|
||||||
prev: prev.map(([path]) => path),
|
prev: prev.map(([path]) => path),
|
||||||
@ -202,12 +201,6 @@ export function watchAnchorList(
|
|||||||
}
|
}
|
||||||
}, { prev: [], next: [] })
|
}, { prev: [], next: [] })
|
||||||
)
|
)
|
||||||
|
|
||||||
/* Return anchor list migrations as hot observable */
|
|
||||||
return migration$
|
|
||||||
.pipe(
|
|
||||||
shareReplay(1)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
@ -21,12 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Observable, combineLatest } from "rxjs"
|
import { Observable, combineLatest } from "rxjs"
|
||||||
import {
|
import { distinctUntilChanged, map, pluck } from "rxjs/operators"
|
||||||
distinctUntilChanged,
|
|
||||||
map,
|
|
||||||
pluck,
|
|
||||||
shareReplay
|
|
||||||
} from "rxjs/operators"
|
|
||||||
|
|
||||||
import { Viewport } from "../../agent"
|
import { Viewport } from "../../agent"
|
||||||
import { Header } from "../../header"
|
import { Header } from "../../header"
|
||||||
@ -103,14 +98,13 @@ export function watchMain(
|
|||||||
distinctUntilChanged()
|
distinctUntilChanged()
|
||||||
)
|
)
|
||||||
|
|
||||||
/* Combine into a single hot observable */
|
/* Combine into a single observable */
|
||||||
return combineLatest([adjust$, height$, active$])
|
return combineLatest([adjust$, height$, active$])
|
||||||
.pipe(
|
.pipe(
|
||||||
map(([adjust, height, active]) => ({
|
map(([adjust, height, active]) => ({
|
||||||
offset: el.offsetTop - adjust,
|
offset: el.offsetTop - adjust,
|
||||||
height,
|
height,
|
||||||
active
|
active
|
||||||
})),
|
}))
|
||||||
shareReplay(1)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,6 @@ import {
|
|||||||
finalize,
|
finalize,
|
||||||
map,
|
map,
|
||||||
observeOn,
|
observeOn,
|
||||||
shareReplay,
|
|
||||||
tap,
|
tap,
|
||||||
withLatestFrom
|
withLatestFrom
|
||||||
} from "rxjs/operators"
|
} from "rxjs/operators"
|
||||||
@ -136,11 +135,10 @@ export function watchSidebar(
|
|||||||
distinctUntilChanged()
|
distinctUntilChanged()
|
||||||
)
|
)
|
||||||
|
|
||||||
/* Combine into single hot observable */
|
/* Combine into single observable */
|
||||||
return combineLatest([height$, lock$])
|
return combineLatest([height$, lock$])
|
||||||
.pipe(
|
.pipe(
|
||||||
map(([height, lock]) => ({ height, lock })),
|
map(([height, lock]) => ({ height, lock }))
|
||||||
shareReplay(1)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,6 @@ import {
|
|||||||
map,
|
map,
|
||||||
observeOn,
|
observeOn,
|
||||||
scan,
|
scan,
|
||||||
shareReplay,
|
|
||||||
tap
|
tap
|
||||||
} from "rxjs/operators"
|
} from "rxjs/operators"
|
||||||
|
|
||||||
@ -99,12 +98,11 @@ export function watchNavigationLayer(
|
|||||||
)))
|
)))
|
||||||
)
|
)
|
||||||
|
|
||||||
/* Return previous and next layer as hot observable */
|
/* Return previous and next layer */
|
||||||
return layer$
|
return layer$
|
||||||
.pipe(
|
.pipe(
|
||||||
map(next => ({ next })),
|
map(next => ({ next })),
|
||||||
scan(({ next: prev }, { next }) => ({ prev, next })),
|
scan(({ next: prev }, { next }) => ({ prev, next }))
|
||||||
shareReplay(1)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,6 @@ import {
|
|||||||
delay,
|
delay,
|
||||||
distinctUntilChanged,
|
distinctUntilChanged,
|
||||||
map,
|
map,
|
||||||
shareReplay,
|
|
||||||
startWith
|
startWith
|
||||||
} from "rxjs/operators"
|
} from "rxjs/operators"
|
||||||
|
|
||||||
@ -109,10 +108,9 @@ export function watchSearchQuery(
|
|||||||
/* Intercept focus events */
|
/* Intercept focus events */
|
||||||
const focus$ = watchElementFocus(el)
|
const focus$ = watchElementFocus(el)
|
||||||
|
|
||||||
/* Combine into a single hot observable */
|
/* Combine into a single observable */
|
||||||
return combineLatest([value$, focus$])
|
return combineLatest([value$, focus$])
|
||||||
.pipe(
|
.pipe(
|
||||||
map(([value, focus]) => ({ value, focus })),
|
map(([value, focus]) => ({ value, focus }))
|
||||||
shareReplay(1)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
import { NEVER, Observable, fromEvent, of } from "rxjs"
|
import { NEVER, Observable, fromEvent, of } from "rxjs"
|
||||||
import {
|
import {
|
||||||
|
distinctUntilChanged,
|
||||||
map,
|
map,
|
||||||
shareReplay,
|
shareReplay,
|
||||||
startWith,
|
startWith,
|
||||||
@ -84,7 +85,7 @@ let toggles$: Observable<ToggleMap>
|
|||||||
export function watchToggleMap(
|
export function watchToggleMap(
|
||||||
names: Toggle[], { document$ }: WatchOptions
|
names: Toggle[], { document$ }: WatchOptions
|
||||||
): Observable<ToggleMap> {
|
): Observable<ToggleMap> {
|
||||||
toggles$ = document$
|
return toggles$ = document$
|
||||||
.pipe(
|
.pipe(
|
||||||
|
|
||||||
/* Ignore document switches */
|
/* Ignore document switches */
|
||||||
@ -97,12 +98,9 @@ export function watchToggleMap(
|
|||||||
...toggles,
|
...toggles,
|
||||||
...typeof el !== "undefined" ? { [name]: el } : {}
|
...typeof el !== "undefined" ? { [name]: el } : {}
|
||||||
}
|
}
|
||||||
}, {}))
|
}, {})),
|
||||||
)
|
|
||||||
|
|
||||||
/* Return toggle map as hot observable */
|
/* Convert to hot observable */
|
||||||
return toggles$
|
|
||||||
.pipe(
|
|
||||||
shareReplay(1)
|
shareReplay(1)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -125,7 +123,8 @@ export function useToggle(
|
|||||||
typeof toggles[name] !== "undefined"
|
typeof toggles[name] !== "undefined"
|
||||||
? of(toggles[name]!)
|
? of(toggles[name]!)
|
||||||
: NEVER
|
: NEVER
|
||||||
))
|
)),
|
||||||
|
distinctUntilChanged()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ export function patchDetails(
|
|||||||
/* Open parent details and fix anchor jump */
|
/* Open parent details and fix anchor jump */
|
||||||
hash$
|
hash$
|
||||||
.pipe(
|
.pipe(
|
||||||
map(hash => getElement(hash)!),
|
map(id => getElement(`[id="${id}"]`)!),
|
||||||
filter(el => typeof el !== "undefined"),
|
filter(el => typeof el !== "undefined"),
|
||||||
tap(el => {
|
tap(el => {
|
||||||
const details = el.closest("details")
|
const details = el.closest("details")
|
||||||
|
@ -32,6 +32,9 @@ export interface Config {
|
|||||||
worker: {
|
worker: {
|
||||||
search: string /* Search worker URL */
|
search: string /* Search worker URL */
|
||||||
}
|
}
|
||||||
|
feature: {
|
||||||
|
instant: true /* Instant loading */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
|
@ -56,14 +56,18 @@ interface SetupOptions {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve URL
|
* Resolve URL
|
||||||
|
* * TODO: document what's going on here + cache results
|
||||||
*
|
*
|
||||||
* @param base - Base URL
|
* @param origin - Base URL
|
||||||
* @param paths - Further URL paths
|
* @param paths - Further URL paths
|
||||||
*
|
*
|
||||||
* @return Absolute URL
|
* @return Relative URL
|
||||||
*/
|
*/
|
||||||
function resolve(base: URL | string, ...paths: string[]) {
|
function resolve(origin: URL, ...paths: string[]) {
|
||||||
return [base, ...paths].join("")
|
const path = location.pathname
|
||||||
|
.replace(origin.pathname, "")
|
||||||
|
.replace(/[^\/]+/g, "..")
|
||||||
|
return [path, ...paths].join("")
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
@ -87,7 +91,7 @@ export function setupSearchWorker(
|
|||||||
url: string, { base, index }: SetupOptions
|
url: string, { base, index }: SetupOptions
|
||||||
): WorkerHandler<SearchMessage> {
|
): WorkerHandler<SearchMessage> {
|
||||||
const worker = new Worker(url)
|
const worker = new Worker(url)
|
||||||
const prefix = new URL(base, getLocation())
|
const origin = new URL(base, getLocation())
|
||||||
|
|
||||||
/* Create communication channels and resolve relative links */
|
/* Create communication channels and resolve relative links */
|
||||||
const tx$ = new Subject<SearchMessage>()
|
const tx$ = new Subject<SearchMessage>()
|
||||||
@ -96,9 +100,9 @@ export function setupSearchWorker(
|
|||||||
map(message => {
|
map(message => {
|
||||||
if (isSearchResultMessage(message)) {
|
if (isSearchResultMessage(message)) {
|
||||||
for (const { article, sections } of message.data) {
|
for (const { article, sections } of message.data) {
|
||||||
article.location = resolve(prefix, article.location)
|
article.location = resolve(origin, article.location)
|
||||||
for (const section of sections)
|
for (const section of sections)
|
||||||
section.location = resolve(prefix, section.location)
|
section.location = resolve(origin, section.location)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return message
|
return message
|
||||||
@ -109,7 +113,7 @@ export function setupSearchWorker(
|
|||||||
const index$ = typeof index !== "undefined"
|
const index$ = typeof index !== "undefined"
|
||||||
? from(index)
|
? from(index)
|
||||||
: ajax({
|
: ajax({
|
||||||
url: resolve(prefix, "search/search_index.json"),
|
url: resolve(origin, "search/search_index.json"),
|
||||||
responseType: "json",
|
responseType: "json",
|
||||||
withCredentials: true
|
withCredentials: true
|
||||||
})
|
})
|
||||||
|
@ -400,6 +400,9 @@
|
|||||||
base: "{{ base_url }}",
|
base: "{{ base_url }}",
|
||||||
worker: {
|
worker: {
|
||||||
search: "{{ 'assets/javascripts/worker/search.js' | url }}"
|
search: "{{ 'assets/javascripts/worker/search.js' | url }}"
|
||||||
|
},
|
||||||
|
feature: {
|
||||||
|
instant: {{ feature.instant | tojson }}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -32,6 +32,10 @@ feature:
|
|||||||
# of tabs, especially useful for larger documentation projects
|
# of tabs, especially useful for larger documentation projects
|
||||||
tabs: false
|
tabs: false
|
||||||
|
|
||||||
|
# Instant loading will instruct the application to intercept all internal
|
||||||
|
# links, load and inject the HTML into the page and rebind all handlers
|
||||||
|
instant: false
|
||||||
|
|
||||||
# Sets the primary and accent color palettes as defined in the Material Design
|
# Sets the primary and accent color palettes as defined in the Material Design
|
||||||
# documentation - possible values can be looked up in the getting started guide
|
# documentation - possible values can be looked up in the getting started guide
|
||||||
palette:
|
palette:
|
||||||
|
Loading…
Reference in New Issue
Block a user