Refactored cache observable factory and documented utilities

This commit is contained in:
squidfunk 2020-02-19 10:18:33 +01:00
parent 57817eac99
commit 74b02ad382
5 changed files with 42 additions and 27 deletions

View File

@ -56,7 +56,7 @@ export function getElementOrThrow<T extends HTMLElement>(
const el = getElement<T>(selector, node) const el = getElement<T>(selector, node)
if (typeof el === "undefined") if (typeof el === "undefined")
throw new ReferenceError( throw new ReferenceError(
`Missing element: expected "${selector}" to match an element` `Missing element: expected "${selector}" to be present`
) )
return el return el
} }

View File

@ -85,7 +85,7 @@ export function patchDetails(
el.setAttribute("open", "") el.setAttribute("open", "")
}) })
/* Open details before anchor jump */ /* Open parent details before anchor jump */
merge(hash$, of(location.hash)) merge(hash$, of(location.hash))
.pipe( .pipe(
filter(hash => !!hash.length), filter(hash => !!hash.length),

View File

@ -20,7 +20,7 @@
* IN THE SOFTWARE. * IN THE SOFTWARE.
*/ */
import { Observable, of } from "rxjs" import { Observable, defer, of } from "rxjs"
import { map } from "rxjs/operators" import { map } from "rxjs/operators"
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
@ -46,7 +46,10 @@ export function not(
/** /**
* Cache the last value emitted by an observable in session storage * Cache the last value emitted by an observable in session storage
* *
* Note that the value must be serializable as `JSON`. * If the key is not found in session storage, the factory is executed and the
* latest value emitted will automatically be persisted to sessions storage.
* Note that the values emitted by the returned observable must be serializable
* as `JSON`, or data will be lost.
* *
* @template T - Value type * @template T - Value type
* *
@ -58,23 +61,25 @@ export function not(
export function cache<T>( export function cache<T>(
key: string, factory: () => Observable<T> key: string, factory: () => Observable<T>
): Observable<T> { ): Observable<T> {
const data = sessionStorage.getItem(key) return defer(() => {
if (data) { const data = sessionStorage.getItem(key)
return of(JSON.parse(data) as T) if (data) {
return of(JSON.parse(data) as T)
/* Retrieve value from observable factory and write to storage */ /* Retrieve value from observable factory and write to storage */
} else { } else {
const value$ = factory() const value$ = factory()
value$ value$
.subscribe(value => { .subscribe(value => {
try { try {
sessionStorage.setItem(key, JSON.stringify(value)) sessionStorage.setItem(key, JSON.stringify(value))
} catch (err) { } catch (err) {
/* Just swallow */ /* Uncritical, just swallow */
} }
}) })
/* Return value observable */ /* Return value observable */
return value$ return value$
} }
})
} }

View File

@ -30,6 +30,9 @@ import { filter, map, withLatestFrom } from "rxjs/operators"
/** /**
* Toggle emission with another observable * Toggle emission with another observable
* *
* While this could also be implemented using window operators, it may lead to
* an unnecessary increase in bundle size, so we use operators we use anyway.
*
* @template T - Value type * @template T - Value type
* *
* @param toggle$ - Toggle observable * @param toggle$ - Toggle observable

View File

@ -82,7 +82,14 @@ export function truncate(value: string, n: number): string {
* Round a number for display with source facts * Round a number for display with source facts
* *
* This is a reverse engineered implementation of GitHub's weird rounding * This is a reverse engineered implementation of GitHub's weird rounding
* algorithm for stars, forks and all other numbers. Probably incorrect. * algorithm for stars, forks and all other numbers. While all numbers below
* `1,000` are returned as-is, bigger numbers are converted to fixed numbers
* in the following way:
*
* - `1,049` => `1k`
* - `1,050` => `1,1k`
* - `1,949` => `1,9k`
* - `1,950` => `2k`
* *
* @param value - Original value * @param value - Original value
* *
@ -104,13 +111,13 @@ export function round(value: number): string {
* *
* @param value - Value to be hashed * @param value - Value to be hashed
* *
* @return Hash * @return Hash as 32bit integer
*/ */
export function hash(value: string): number { export function hash(value: string): number {
let k = 0 let h = 0
for (let i = 0, len = value.length; i < len; i++) { for (let i = 0, len = value.length; i < len; i++) {
k = ((k << 5) - k) + value.charCodeAt(i) h = ((h << 5) - h) + value.charCodeAt(i)
k |= 0 // Convert to 32bit integer h |= 0 // Convert to 32bit integer
} }
return k return h
} }