Refactored search initialization

This commit is contained in:
squidfunk 2021-02-07 17:18:10 +01:00
parent ae867d484b
commit 4744d5f3f0
12 changed files with 52 additions and 108 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

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,8 +1,8 @@
{ {
"assets/javascripts/bundle.js": "assets/javascripts/bundle.0168bc18.min.js", "assets/javascripts/bundle.js": "assets/javascripts/bundle.5c26acfa.min.js",
"assets/javascripts/bundle.js.map": "assets/javascripts/bundle.0168bc18.min.js.map", "assets/javascripts/bundle.js.map": "assets/javascripts/bundle.5c26acfa.min.js.map",
"assets/javascripts/vendor.js": "assets/javascripts/vendor.2c98d838.min.js", "assets/javascripts/vendor.js": "assets/javascripts/vendor.250c9a34.min.js",
"assets/javascripts/vendor.js.map": "assets/javascripts/vendor.2c98d838.min.js.map", "assets/javascripts/vendor.js.map": "assets/javascripts/vendor.250c9a34.min.js.map",
"assets/javascripts/worker/search.js": "assets/javascripts/worker/search.cc7c7442.min.js", "assets/javascripts/worker/search.js": "assets/javascripts/worker/search.cc7c7442.min.js",
"assets/javascripts/worker/search.js.map": "assets/javascripts/worker/search.cc7c7442.min.js.map", "assets/javascripts/worker/search.js.map": "assets/javascripts/worker/search.cc7c7442.min.js.map",
"assets/stylesheets/main.css": "assets/stylesheets/main.9c987ffa.min.css", "assets/stylesheets/main.css": "assets/stylesheets/main.9c987ffa.min.css",

View File

@ -216,8 +216,8 @@
</script> </script>
{% endblock %} {% endblock %}
{% block scripts %} {% block scripts %}
<script src="{{ 'assets/javascripts/vendor.2c98d838.min.js' | url }}"></script> <script src="{{ 'assets/javascripts/vendor.250c9a34.min.js' | url }}"></script>
<script src="{{ 'assets/javascripts/bundle.0168bc18.min.js' | url }}"></script> <script src="{{ 'assets/javascripts/bundle.5c26acfa.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 %}

View File

@ -20,45 +20,12 @@
* IN THE SOFTWARE. * IN THE SOFTWARE.
*/ */
import { import { Observable, merge } from "rxjs"
Observable, import { filter, sample, take } from "rxjs/operators"
Subject,
combineLatest,
fromEvent,
merge,
defer
} from "rxjs"
import {
delay,
distinctUntilChanged,
distinctUntilKeyChanged,
finalize,
map,
startWith,
takeLast,
takeUntil,
tap
} from "rxjs/operators"
import {
resetSearchQueryPlaceholder,
setSearchQueryPlaceholder
} from "~/actions"
import {
getElementOrThrow,
setElementFocus,
setToggle,
watchElementFocus
} from "~/browser"
import {
SearchTransformFn,
defaultTransform,
SearchWorker,
SearchQueryMessage,
SearchMessageType,
setupSearchWorker,
} from "~/integrations"
import { configuration } from "~/_" import { configuration } from "~/_"
import { getElementOrThrow } from "~/browser"
import { isSearchQueryMessage, isSearchReadyMessage, setupSearchWorker } from "~/integrations"
import { Component } from "../../_" import { Component } from "../../_"
import { mountSearchQuery, SearchQuery } from "../query" import { mountSearchQuery, SearchQuery } from "../query"
@ -80,10 +47,15 @@ export type Search =
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
/** /**
* Fetch search index
* *
* @param url - Search index URL
*
* @return Promise resolving with search index
*/ */
function fetchSearchIndex() { function fetchSearchIndex(url: string) {
return __search?.index || fetch(url, { credentials: "same-origin" })
.then(res => res.json())
} }
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
@ -100,48 +72,29 @@ function fetchSearchIndex() {
export function mountSearch( export function mountSearch(
el: HTMLElement el: HTMLElement
): Observable<Component<Search>> { ): Observable<Component<Search>> {
const searchQueryEl = getElementOrThrow<HTMLInputElement>("[data-md-component=search-query]", el)
const searchResultEl = getElementOrThrow("[data-md-component=search-result]", el)
const config = configuration() const config = configuration()
const worker = setupSearchWorker(config.search, fetchSearchIndex(
`${config.base}/search/search_index.json`
))
// TODO: determine correct BASE URL -> may change on instant loading! /* Re-emit query when search is ready */
const index$ = defer(() => fetch(`${config.base}/search/search_index.json`, { const { tx$, rx$ } = worker
credentials: "same-origin" tx$
}).then(res => res.json())) .pipe(
filter(isSearchQueryMessage),
// TODO: shouldnt be necessary, as it's done from config? sample(rx$.pipe(filter(isSearchReadyMessage))),
const worker$ = setupSearchWorker(config.search, { take(1)
index$ )
}) .subscribe(tx$.next.bind(tx$))
// TODO: hand transformFn to
// __search.transform -> search transform
// __search.index -> search index
const query$ = mountSearchQuery(searchQueryEl, worker$)
const result$ = mountSearchResult(searchResultEl, worker$, { query$ })
/* Obtain search query and result elements */
const query = getElementOrThrow("[data-md-component=search-query]", el)
const result = getElementOrThrow("[data-md-component=search-result]", el)
/* Create and return component */
const query$ = mountSearchQuery(query as HTMLInputElement, worker)
return merge( return merge(
query$, query$,
result$ mountSearchResult(result, worker, { query$ })
// /* Search query */
// ...getElements("[data-md-component=search-query]", el)
// .map(child => mountSearchQuery(child, worker$)),
// /* Search result */
// ...getElements("[data-md-component=search-query]", el)
// .map(child => mountSearchResult(child, worker$)),
) )
// /* Create and return component */
// return watchSearchQuery(el, transform)
// .pipe(
// tap(internal$),
// finalize(() => internal$.complete()),
// map(state => ({ ref: el, ...state }))
// )
} }

View File

@ -82,6 +82,9 @@ setupClipboardJS()
// TODO: watchElements + general mount function that takes a factory... // TODO: watchElements + general mount function that takes a factory...
// + a toggle function (optionally) // + a toggle function (optionally)
// TODO: catch errors on all components when mounting, so one error doesn't
// take down the whole site.
const app$ = merge( const app$ = merge(
/* Content */ /* Content */

View File

@ -20,8 +20,8 @@
* IN THE SOFTWARE. * IN THE SOFTWARE.
*/ */
import { Observable, Subject, asyncScheduler } from "rxjs" import { Subject, asyncScheduler, from } from "rxjs"
import { map, observeOn, share } from "rxjs/operators" import { delay, map, observeOn, share } from "rxjs/operators"
import { configuration, translation } from "~/_" import { configuration, translation } from "~/_"
import { WorkerHandler, watchWorker } from "~/browser" import { WorkerHandler, watchWorker } from "~/browser"
@ -43,17 +43,6 @@ import {
*/ */
export type SearchWorker = WorkerHandler<SearchMessage> export type SearchWorker = WorkerHandler<SearchMessage>
/* ----------------------------------------------------------------------------
* Helper types
* ------------------------------------------------------------------------- */
/**
* Setup options
*/
interface SetupOptions {
index$: Observable<SearchIndex> /* Search index observable */
}
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* Helper functions * Helper functions
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
@ -100,12 +89,12 @@ function setupSearchIndex(
* enable hacks like _localsearch_ via search index embedding as JSON. * enable hacks like _localsearch_ via search index embedding as JSON.
* *
* @param url - Worker URL * @param url - Worker URL
* @param options - Options * @param index - Promise resolving with search index
* *
* @return Search worker * @return Search worker
*/ */
export function setupSearchWorker( export function setupSearchWorker(
url: string, { index$ }: SetupOptions url: string, index: Promise<SearchIndex>
): SearchWorker { ): SearchWorker {
const config = configuration() const config = configuration()
const worker = new Worker(url) const worker = new Worker(url)
@ -126,13 +115,12 @@ export function setupSearchWorker(
) )
/* Set up search index */ /* Set up search index */
index$ from(index)
.pipe( .pipe(
map<SearchIndex, SearchSetupMessage>(data => ({ map<SearchIndex, SearchSetupMessage>(data => ({
type: SearchMessageType.SETUP, type: SearchMessageType.SETUP,
data: setupSearchIndex(data) data: setupSearchIndex(data)
})), }))
observeOn(asyncScheduler)
) )
.subscribe(tx$.next.bind(tx$)) .subscribe(tx$.next.bind(tx$))