@@ -2,8 +2,7 @@ import { createState } from "dreamland/core";
22import { browser } from "./Browser" ;
33import { StatefulClass } from "./StatefulClass" ;
44import type { Tab } from "./Tab" ;
5-
6- import type { ScramjetClient , ScramjetFrame } from "@mercuryworkshop/scramjet" ;
5+ import { sendFrame } from "./IsolatedFrame" ;
76
87// history api emulation
98export class HistoryState extends StatefulClass {
@@ -13,6 +12,8 @@ export class HistoryState extends StatefulClass {
1312 favicon : string | null = null ;
1413 timestamp : number ;
1514
15+ virtual : boolean = false ; // whether this state was created by pushState and can be navigated to without a full reload
16+
1617 constructor ( partial ?: Partial < HistoryState > ) {
1718 super ( createState ( Object . create ( HistoryState . prototype ) ) ) ;
1819 Object . assign ( this , partial ) ;
@@ -126,15 +127,27 @@ export class History {
126127 this . index = this . states . length - 1 ;
127128 }
128129
129- if ( navigate ) {
130+ let newstate = this . states [ this . index ] ;
131+
132+ if ( newstate . virtual ) {
133+ sendFrame ( this . tab , "history_go" , {
134+ delta,
135+ } ) ;
136+ } else if ( navigate ) {
130137 this . justTriggeredNavigation = true ;
131- this . tab . _directnavigate ( this . states [ this . index ] . url ) ;
138+ this . tab . _directnavigate ( newstate . url ) ;
139+ }
140+
141+ if ( newstate . virtual || ! navigate ) {
142+ this . tab . url = newstate . url ;
143+ this . tab . title = newstate . title ;
144+ this . tab . icon = newstate . favicon ;
132145 }
133146
134147 this . tab . canGoBack = this . canGoBack ( ) ;
135148 this . tab . canGoForward = this . canGoForward ( ) ;
136149
137- return this . states [ this . index ] ;
150+ return newstate ;
138151 }
139152 canGoBack ( ) : boolean {
140153 return this . index > 0 ;
@@ -143,61 +156,3 @@ export class History {
143156 return this . index < this . states . length - 1 ;
144157 }
145158}
146-
147- export function addHistoryListeners ( frame : ScramjetFrame , tab : Tab ) {
148- frame . addEventListener ( "navigate" , ( e ) => {
149- console . log ( "History push from navigate" , e , tab . history . states ) ;
150- // this event is fired whenever location.href is set, or similar
151- // importantly not fired when replaceState is called (we overwrite it ourselves in injectContext)
152-
153- // behavior here is just to create a new history entry
154- const url = new URL ( e . url ) ;
155- tab . history . push ( url , undefined , false ) ;
156-
157- console . log ( "History push from navigate" , url , tab . history . states ) ;
158- } ) ;
159- }
160-
161- export function injectHistoryEmulation ( client : ScramjetClient , tab : Tab ) {
162- // this is extremely problematic in terms of security but whatever
163- client . global . addEventListener ( "beforeunload" , ( e : BeforeUnloadEvent ) => {
164- console . log ( "History beforeunload" , e ) ;
165- } ) ;
166-
167- client . Proxy ( "History.prototype.pushState" , {
168- apply ( ctx ) {
169- console . log ( "STATE PUSH" , ctx . args ) ;
170- ctx . return ( undefined ) ;
171- } ,
172- } ) ;
173-
174- client . Proxy ( "History.prototype.replaceState" , {
175- apply ( ctx ) {
176- console . log ( "STATE REPLACE" , ctx . args ) ;
177- ctx . return ( undefined ) ;
178- } ,
179- } ) ;
180- client . Proxy ( "History.prototype.back" , {
181- apply ( ctx ) {
182- console . log ( "HISTORY BACK" , ctx ) ;
183- tab . history . go ( - 1 ) ;
184- ctx . return ( undefined ) ;
185- } ,
186- } ) ;
187- client . Proxy ( "History.prototype.forward" , {
188- apply ( ctx ) {
189- console . log ( "HISTORY FORWARD" , ctx ) ;
190- tab . history . go ( 1 ) ;
191- ctx . return ( undefined ) ;
192- } ,
193- } ) ;
194- client . Proxy ( "History.prototype.go" , {
195- apply ( ctx ) {
196- console . log ( "HISTORY GO" , ctx ) ;
197- tab . history . go ( ctx . args [ 0 ] ) ;
198- ctx . return ( undefined ) ;
199- } ,
200- } ) ;
201- }
202-
203- export function handleNavigate ( ) { }
0 commit comments