From 27f5851458242cd8be8c35eff3621c462a514385 Mon Sep 17 00:00:00 2001 From: Eddy Ernesto del Valle Pino Date: Thu, 20 Jun 2019 09:39:39 +0200 Subject: [PATCH] Add support for push state --- reactor/channels.py | 4 ++++ reactor/component.py | 14 +++++++++++--- reactor/static/reactor.coffee | 29 ++++++++++++++++++++++++++++- 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/reactor/channels.py b/reactor/channels.py index b0b9d44..285e332 100644 --- a/reactor/channels.py +++ b/reactor/channels.py @@ -109,3 +109,7 @@ def remove(self, event): def redirect(self, event): log.debug(f"<<< REDIRECT {event['url']}") self.send_json(dict(event, type='redirect')) + + def push_state(self, event): + log.debug(f"<<< PUSH-STATE {event['url']}") + self.send_json(dict(event, type='push_state')) diff --git a/reactor/component.py b/reactor/component.py index f7dd6c2..cf3b985 100644 --- a/reactor/component.py +++ b/reactor/component.py @@ -95,6 +95,7 @@ def build(cls, tag_name, *args, **kwargs): def __init__(self, context, id=None): self._context = context self._destroy_sent = False + self._redirect_sent = False self._redirected_to = None self._last_sent_html = '' self._diff = diff_match_patch() @@ -152,10 +153,15 @@ def send_destroy(self): id=self.id, ) - def send_redirect(self, url): + def send_redirect(self, url, push_state=True): url = reverse(url) if self._channel_name: - send_to_channel(self._channel_name, 'redirect', url=url) + if push_state: + action = 'push_state' + else: + action = 'redirect' + send_to_channel(self._channel_name, action, url=url) + self._redirect_sent = True else: self._redirected_to = url @@ -184,7 +190,9 @@ def render_diff(self): ] def render(self): - if self._destroy_sent: + if self._redirect_sent: + html = self._last_sent_html + elif self._destroy_sent: html = '' elif self._redirected_to: html = ( diff --git a/reactor/static/reactor.coffee b/reactor/static/reactor.coffee index 4591c4c..d25d54a 100644 --- a/reactor/static/reactor.coffee +++ b/reactor/static/reactor.coffee @@ -87,7 +87,9 @@ reactor_channel.on 'close', -> reactor_channel.on 'message', ({type, id, html_diff, url}) -> console.log '<<<', type.toUpperCase(), id or url if type is 'redirect' - location.assign url + window.location.assign url + else if type is 'push_state' + push_state url else el = document.getElementById(id) if el? @@ -241,4 +243,29 @@ debounce = (delay_name, delay) -> (...args) -> clearTimeout _timeouts[delay_name] _timeouts[delay_name] = setTimeout (=> send(...args)), delay +push_state = (url) -> + if history.pushState? + history.pushState {}, '', url + load_page url + else + window.location.assign url + +window.onpopstate = -> + load_page window.location.href + +load_page = (url) -> + utf8_decoder = new TextDecoder("utf-8") + fetch(url).then (response) -> + reader = await response.body.getReader() + done = false + result = [] + while not done + {done, value} = await reader.read() + value = if value then utf8_decoder.decode(value) else '' + result.push value + html = result.join('').trim() + window.requestAnimationFrame -> + morphdom(document.documentElement, html) + document.querySelector('[autofocus]')?.focus() + reactor_channel.open()