123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- import { transition } from "alpinejs/src/directives/x-transition"
- import { finishAndHideProgressBar, showAndStartProgressBar } from "./bar"
- import { fetchHtml } from "./fetch"
- import { updateCurrentPageHtmlInHistoryStateForLaterBackButtonClicks, updateUrlAndStoreLatestHtmlForFutureBackButtons, whenTheBackOrForwardButtonIsClicked } from "./history"
- import { extractDestinationFromLink, hijackNewLinksOnThePage, whenALinkIsClicked, whenALinkIsHovered } from "./links"
- import { swapCurrentPageWithNewHtml } from "./page"
- import { putPersistantElementsBack, storePersistantElementsForLater } from "./persist"
- import { getPretchedHtmlOr, prefetchHtml, storeThePrefetchedHtmlForWhenALinkIsClicked } from "./prefetch"
- import { restoreScrollPosition, storeScrollInformationInHtmlBeforeNavigatingAway } from "./scroll"
- let enablePrefetch = true
- let enablePersist = true
- let showProgressBar = false
- let restoreScroll = true
- let autofocus = false
- export default function (Alpine) {
- updateCurrentPageHtmlInHistoryStateForLaterBackButtonClicks()
- enablePrefetch && whenALinkIsHovered((el) => {
- let forDestination = extractDestinationFromLink(el)
- prefetchHtml(forDestination, html => {
- storeThePrefetchedHtmlForWhenALinkIsClicked(html, forDestination)
- })
- })
- whenALinkIsClicked((el) => {
- showProgressBar && showAndStartProgressBar()
- let fromDestination = extractDestinationFromLink(el)
- fetchHtmlOrUsePrefetchedHtml(fromDestination, html => {
- restoreScroll && storeScrollInformationInHtmlBeforeNavigatingAway()
- updateCurrentPageHtmlInHistoryStateForLaterBackButtonClicks()
- showProgressBar && finishAndHideProgressBar()
- preventAlpineFromPickingUpDomChanges(Alpine, andAfterAllThis => {
- enablePersist && storePersistantElementsForLater()
- swapCurrentPageWithNewHtml(html, () => {
- enablePersist && putPersistantElementsBack()
- hijackNewLinksOnThePage()
- restoreScroll && restoreScrollPosition()
- fireEventForOtherLibariesToHookInto()
- updateUrlAndStoreLatestHtmlForFutureBackButtons(html, fromDestination)
- andAfterAllThis(() => {
- autofocus && autofocusElementsWithTheAutofocusAttribute()
- nowInitializeAlpineOnTheNewPage(Alpine)
- })
- })
- })
- })
- })
- whenTheBackOrForwardButtonIsClicked((html) => {
- // @todo: see if there's a way to update the current HTML BEFORE
- // the back button is hit, and not AFTER:
- storeScrollInformationInHtmlBeforeNavigatingAway()
- // updateCurrentPageHtmlInHistoryStateForLaterBackButtonClicks()
- preventAlpineFromPickingUpDomChanges(Alpine, andAfterAllThis => {
- enablePersist && storePersistantElementsForLater()
- swapCurrentPageWithNewHtml(html, andThen => {
- enablePersist && putPersistantElementsBack()
- hijackNewLinksOnThePage()
- restoreScroll && restoreScrollPosition()
- fireEventForOtherLibariesToHookInto()
- andAfterAllThis(() => {
- autofocus && autofocusElementsWithTheAutofocusAttribute()
- nowInitializeAlpineOnTheNewPage(Alpine)
- })
- })
- })
- })
- }
- function fetchHtmlOrUsePrefetchedHtml(fromDestination, callback) {
- getPretchedHtmlOr(fromDestination, callback, () => {
- fetchHtml(fromDestination, callback)
- })
- }
- function preventAlpineFromPickingUpDomChanges(Alpine, callback) {
- Alpine.stopObservingMutations()
- callback((afterAllThis) => {
- Alpine.startObservingMutations()
- setTimeout(() => {
- afterAllThis()
- })
- })
- }
- function fireEventForOtherLibariesToHookInto() {
- document.dispatchEvent(new CustomEvent('alpine:navigated', { bubbles: true }))
- }
- function nowInitializeAlpineOnTheNewPage(Alpine) {
- Alpine.initTree(document.body, undefined, (el, skip) => {
- if (el._x_wasPersisted) skip()
- })
- }
- function autofocusElementsWithTheAutofocusAttribute() {
- document.querySelector('[autofocus]') && document.querySelector('[autofocus]').focus()
- }
- // Alpine.magic('history', (el, { interceptor }) => {
- // let alias
- // return interceptor((initialValue, getter, setter, path, key) => {
- // let pause = false
- // let queryKey = alias || path
- // let value = initialValue
- // let url = new URL(window.location.href)
- // if (url.searchParams.has(queryKey)) {
- // value = url.searchParams.get(queryKey)
- // }
- // setter(value)
- // let object = { value }
- // url.searchParams.set(queryKey, value)
- // replace(url.toString(), path, object)
- // window.addEventListener('popstate', (e) => {
- // if (! e.state) return
- // if (! e.state.alpine) return
- // Object.entries(e.state.alpine).forEach(([newKey, { value }]) => {
- // if (newKey !== key) return
- // pause = true
- // Alpine.disableEffectScheduling(() => {
- // setter(value)
- // })
- // pause = false
- // })
- // })
- // Alpine.effect(() => {
- // let value = getter()
- // if (pause) return
- // let object = { value }
- // let url = new URL(window.location.href)
- // url.searchParams.set(queryKey, value)
- // push(url.toString(), path, object)
- // })
- // return value
- // }, func => {
- // func.as = key => { alias = key; return func }
- // })
- // })
- // }
- // function replace(url, key, object) {
- // let state = window.history.state || {}
- // if (! state.alpine) state.alpine = {}
- // state.alpine[key] = object
- // window.history.replaceState(state, '', url)
- // }
- // function push(url, key, object) {
- // let state = { alpine: {...window.history.state.alpine, ...{[key]: object}} }
- // window.history.pushState(state, '', url)
- // }
|