@@ -5,97 +5,129 @@ import routes from '../models/routes';
5
5
/* eslint-disable max-len */
6
6
/* eslint-disable no-param-reassign */
7
7
import componentActionsRecord from '../models/masterState' ;
8
+ import { Status } from '../types/backendTypes' ;
9
+ import Tree from '../models/tree' ;
8
10
const circularComponentTable = new Set ( ) ;
9
11
10
12
/**
11
- * This file contains necessary functionality for time-travel feature
13
+ * This file contains necessary functionality for time-travel feature.
12
14
*
13
- * Default Export:
14
- * @function timeJump
15
- * @param origin The latest snapshot, linked to the fiber (changes to origin will change app)
16
- * @param mode The current mode (i.e. jumping, time-traveling, or paused)
17
- * @returns A function that takes a target snapshot and a boolean flag checking for firstCall, then invokes `jump` on that target snapshot
15
+ * The target snapshot portrays some past state we want to travel to `jump` recursively and setState for any stateful component.
16
+ *
17
+ * @param mode - The current mode (i.e. jumping, time-traveling, or paused)
18
+ * @returns A function that takes a `target` snapshot and a boolean flag checking for `firstCall`, then invokes `jump` on that target snapshot
18
19
*
19
- * The target snapshot portrays some past state we want to travel to.
20
- * `jump` recursively sets state for any stateful components.
21
20
*/
22
- export default function timeJump ( mode ) {
23
- // Recursively change state of tree
24
- // Set the state of the origin tree if the component is stateful
25
- async function jump ( target ) : Promise < void > {
26
- if ( ! target ) return ;
27
- // Base Case: if has visited, return
28
- if ( circularComponentTable . has ( target ) ) {
29
- return ;
21
+ export default function timeJump ( mode : Status ) {
22
+ // payload from index.ts is assigned to target
23
+ /**
24
+ * @param target - The target snapshot to re-render
25
+ * @param firstCall - A boolean flag checking for `firstCall`
26
+ */
27
+ return ( target : Tree , firstCall = false ) : void => {
28
+ // Setting mode disables setState from posting messages to window
29
+ mode . jumping = true ;
30
+ // Clearn the circularComponentTable
31
+ if ( firstCall ) circularComponentTable . clear ( ) ;
32
+ // Determine if user is navigating to another site
33
+ const navigating : boolean = routes . navigate ( target . route ) ;
34
+
35
+ if ( navigating ) {
36
+ // Initiate popStateHandler to aid the removeListener for 'popstate'
37
+ const popStateHandler = ( ) => {
38
+ initiateJump ( target , mode ) ;
39
+ } ;
40
+ // removeEventListener('popstate', popStateHandler);
41
+ // Background will "perform" popstate till get to the correct history location?
42
+ addEventListener ( 'popstate' , popStateHandler ) ;
30
43
} else {
31
- circularComponentTable . add ( target ) ;
32
- }
33
- // ------------------------STATELESS/ROOT COMPONENT-------------------------
34
- // Since stateless component has no data to update, continue to traverse its child nodes:
35
- if ( target . state === 'stateless' || target . state === 'root' ) {
36
- target . children . forEach ( ( child ) => jump ( child ) ) ;
37
- return ;
44
+ // Intiate the jump
45
+ initiateJump ( target , mode ) ;
38
46
}
47
+ } ;
48
+ }
39
49
40
- // Destructure component data:
41
- const { index, state, hooksIndex, hooksState } = target . componentData ;
42
- // ------------------------STATEFUL CLASS COMPONENT-------------------------
43
- // for stateful class components
44
- // check if it is a stateful class component
45
- // if yes, find the component by its index and assign it to a variable
46
- // call that components setState method to reset state to the state at the time of the jump snapshot
47
- //index can be zero => falsy value => DO NOT REMOVE UNDEFINED
48
- if ( index !== undefined ) {
49
- // Obtain component data & its update method at the given index
50
- const classComponent = componentActionsRecord . getComponentByIndex ( index ) ;
51
- if ( classComponent && classComponent . setState ) {
52
- await classComponent . setState (
53
- // prevState contains the states of the snapshots we are jumping FROM, not jumping TO
54
- ( prevState ) => state ,
55
- ) ;
56
- }
57
- // Iterate through new children after state has been set
58
- target . children . forEach ( ( child ) => jump ( child ) ) ;
59
- return ;
50
+ /**
51
+ * This function initiate the request for jump and will pause the jump when user moves mouse over the body of the document.
52
+ * @param target - The target snapshot to re-render
53
+ * @param mode - The current mode (i.e. jumping, time-traveling, or paused)
54
+ */
55
+ async function initiateJump ( target , mode ) : Promise < void > {
56
+ console . log ( 'JUMP' ) ;
57
+ updateTreeState ( target ) . then ( ( ) => {
58
+ document . body . onmouseover = ( ) => {
59
+ mode . jumping = false ;
60
+ } ;
61
+ } ) ;
62
+ }
63
+
64
+ /**
65
+ * This recursive function receives the target snapshot and will update the state of the fiber tree if the component is statefu
66
+ * @param target - The target snapshot to re-render
67
+ */
68
+ async function updateTreeState ( target ) : Promise < void > {
69
+ if ( ! target ) return ;
70
+ // Base Case: if has visited, return
71
+ if ( circularComponentTable . has ( target ) ) {
72
+ return ;
73
+ } else {
74
+ circularComponentTable . add ( target ) ;
75
+ }
76
+ // console.log(target.name);
77
+ // ------------------------STATELESS/ROOT COMPONENT-------------------------
78
+ // Since stateless component has no data to update, continue to traverse its child nodes:
79
+ if ( target . state === 'stateless' || target . state === 'root' ) {
80
+ target . children . forEach ( ( child ) => updateTreeState ( child ) ) ;
81
+ return ;
82
+ }
83
+
84
+ // Destructure component data:
85
+ const { index, state, hooksIndex, hooksState } = target . componentData ;
86
+ // ------------------------STATEFUL CLASS COMPONENT-------------------------
87
+ // for stateful class components
88
+ // check if it is a stateful class component
89
+ // if yes, find the component by its index and assign it to a variable
90
+ // call that components setState method to reset state to the state at the time of the jump snapshot
91
+ //index can be zero => falsy value => DO NOT REMOVE UNDEFINED
92
+ if ( index !== undefined ) {
93
+ // Obtain component data & its update method at the given index
94
+ const classComponent = componentActionsRecord . getComponentByIndex ( index ) ;
95
+ // If the user navigate to another page during jumps, Routes methods will popState until find a match => this cause changes in componentActionRecord => keep the if statement, otherwise will run into Uncaught Promise type error.
96
+ if ( classComponent ?. setState ) {
97
+ // Update component state
98
+ await classComponent . setState (
99
+ // prevState contains the states of the snapshots we are jumping FROM, not jumping TO
100
+ ( prevState ) => state ,
101
+ ) ;
60
102
}
103
+ // Else statement is to ensure if a mismatch, this popstate is not the correct componentActionRecord. Return immediately to avoid traverse the entire tree
104
+ else return ;
61
105
62
- // ----------------------STATEFUL FUNCTIONAL COMPONENT----------------------
63
- // check if component states are set with hooks
64
- // if yes, grab all relevant components for this snapshot by its index
65
- // call dispatch on each component passing in the corresponding currState value
66
- //index can be zero => falsy value => DO NOT REMOVE UNDEFINED
67
- if ( hooksIndex !== undefined ) {
68
- // Obtain component data & its update method at the given index
69
- const functionalComponent = componentActionsRecord . getComponentByIndexHooks ( hooksIndex ) ;
106
+ // Iterate through new children after state has been set
107
+ target . children . forEach ( ( child ) => updateTreeState ( child ) ) ;
108
+ return ;
109
+ }
110
+
111
+ // ----------------------STATEFUL FUNCTIONAL COMPONENT----------------------
112
+ // check if component states are set with hooks
113
+ // if yes, grab all relevant components for this snapshot by its index
114
+ // call dispatch on each component passing in the corresponding currState value
115
+ //index can be zero => falsy value => DO NOT REMOVE UNDEFINED
116
+ if ( hooksIndex !== undefined ) {
117
+ // Obtain component data & its update method at the given index
118
+ const functionalComponent = componentActionsRecord . getComponentByIndexHooks ( hooksIndex ) ;
119
+ // If the user navigate to another page during jumps, Routes methods will popState until find a match => this cause changes in componentActionRecord => keep the if statement, otherwise will run into Uncaught Promise type error.
120
+ if ( functionalComponent [ 0 ] ?. dispatch ) {
121
+ // Update component state
70
122
for ( let i in functionalComponent ) {
71
123
await functionalComponent [ i ] . dispatch ( Object . values ( hooksState ) [ i ] ) ;
72
124
}
73
- // Iterate through new children after state has been set
74
- target . children . forEach ( ( child ) => jump ( child ) ) ;
75
- return ;
76
125
}
77
- }
126
+ // Else statement is to ensure if a mismatch, this popstate is not the correct componentActionRecord. Return immediately to avoid traverse the entire tree
127
+ else return ;
78
128
79
- // payload from index.ts is assigned to target
80
- return ( target , firstCall = false ) => {
81
- // * Setting mode disables setState from posting messages to window
82
- mode . jumping = true ;
83
- if ( firstCall ) circularComponentTable . clear ( ) ;
84
- const navigating : boolean = routes . navigate ( target . route ) ;
85
- if ( navigating ) {
86
- addEventListener ( 'popstate' , ( event ) => {
87
- jump ( target ) . then ( ( ) => {
88
- document . body . onmouseover = ( ) => {
89
- mode . jumping = false ;
90
- } ;
91
- } ) ;
92
- } ) ;
93
- } else {
94
- jump ( target ) . then ( ( ) => {
95
- document . body . onmouseover = ( ) => {
96
- mode . jumping = false ;
97
- } ;
98
- } ) ;
99
- }
100
- } ;
129
+ // Iterate through new children after state has been set
130
+ target . children . forEach ( ( child ) => updateTreeState ( child ) ) ;
131
+ return ;
132
+ }
101
133
}
0 commit comments