Skip to content

Instantly share code, notes, and snippets.

@amcgregor
Last active October 13, 2023 03:40
Show Gist options
  • Save amcgregor/9040e2e6be9249bcd73c to your computer and use it in GitHub Desktop.
Save amcgregor/9040e2e6be9249bcd73c to your computer and use it in GitHub Desktop.
JavaScripthon example ES6 module handling in-page navigation by XHR/Fetch vs. whole-page navigation.
from org.transcrypt.stubs.browser import __pragma__
from illico.common.vendor import Events
__pragma__ ('kwargs')
class NavigationManager:
def __init__(self):
self.loaded = False
def start(self, context=None):
window.console.log("NavigationManager starting.")
self.context = context
request = context.request.get(window.location)
request.then(self.inject)
def bindEvents(self, context=None):
e = Events(window)
e.on('popstate', self.popstate)
e = Events(document)
e.on('click', 'a', self.navigate)
def popstate(self, e):
if not e.state:
return
window.console.debug("Attempting to move through time.", e.state, e)
def navigate(self, e):
if not e.target.href.startswith(window.location.protocol + '//' + window.location.host + '/'):
return
# TODO: Seek through parents for a <button> or a <a> if we aren't already pointing at one.
if e.target.classList.contains('no-nav'):
return
window.console.debug("Attempting navigation.", e.target.href, e)
target = document.getElementsByTagName('main')[0]
for i in range(1, target.children.length):
target.children[1].remove()
target.classList.add('loading')
request = self.context.request.get(window.location)
request.then(self.inject)
return False
def inject(self, error, text, xhr):
if error:
window.console.error("Unable to load main content.", xhr.status, xhr.statusText, xhr)
return
window.console.debug("Loaded content.", xhr)
self._inject(text, xhr.responseURL)
def _inject(self, text, responseURL):
parser = new(DOMParser)
element = parser.parseFromString(text, "text/html")
target = document.getElementsByTagName('main')[0]
while element.body.children.length:
target.appendChild(element.body.children[0])
target.classList.remove('loading')
header = document.getElementsByTagName('h3')
if header.length:
title = header[0].textContent.strip()
state = {'title': title, 'url': responseURL}
title += ' – Illico Hodes RITA'
document.title = title
if not history.state:
# First page load won't have any state.
window.console.debug("Setting initial state.", state)
history.replaceState(state, title, responseURL)
elif history.state.url != window.location:
# Refreshing and re-navigation to the same target should avoid pushing duplicate state.
window.console.debug("Pushing new state.", state)
history.pushState(state, title, responseURL)
@takwas
Copy link

takwas commented Jun 15, 2018

This is good stuff.

@takwas
Copy link

takwas commented Jun 15, 2018

::)

@amcgregor
Copy link
Author

amcgregor commented Mar 1, 2022

See also CookieManager and the underlying RequestManager with Progress utilized here, and a basic outline of an AuthenticationManager to handle those form submissions.

Here's an example WebAssets static asset pipeline to utilize this, from the "SPA in 48 hours" example I frequently wield — built on an iPad:

An SPA built in less than 48h on an iPad.

Earlier, from the iPad I was building it on prior to applying more flex to give an iOS toolbar appearance:

Native-y iPad PWA.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment