@@ -14,21 +14,20 @@ var ipcRenderer = require('ipc-renderer'),
1414
1515module . exports = Backbone . Router . extend ( {
1616 initialize : function ( options ) {
17- var self = this ;
18-
19- var routes ;
17+ var self = this ,
18+ routes ,
19+ originalHistoryBack ,
20+ originalHistoryForward ;
2021
2122 this . options = options || { } ;
2223
2324 routes = [
2425 [ "" , "index" ] ,
2526 [ "home" , "home" ] ,
2627 [ "home/:state(/:searchText)" , "home" ] ,
27- [ "myPage" , "userPage" ] ,
2828 [ "userPage" , "userPage" ] ,
2929 [ "userPage/:userID(/:state)(/:itemHash)(/:skipNSFWmodal)" , "userPage" ] ,
3030 [ / ^ @ ( [ ^ \/ ] + ) ( .* ) $ / , "userPageViaHandle" ] ,
31- [ "userPageViaHandle" , "userPageViaHandle" ] ,
3231 [ "transactions" , "transactions" ] ,
3332 [ "transactions/:state(/:orderID)(/:tabState)" , "transactions" ] ,
3433 [ "settings" , "settings" ] ,
@@ -52,21 +51,50 @@ module.exports = Backbone.Router.extend({
5251 } ) ;
5352 } ) ;
5453
55- var originalHistoryBack = history . back ;
54+ originalHistoryBack = history . back ;
5655 history . back = function ( ) {
5756 self . historyAction = 'back' ;
58- return originalHistoryBack ( arguments ) ;
57+ return originalHistoryBack . apply ( this , arguments ) ;
5958 } ;
6059
61- var originalHistoryForward = history . forward ;
60+ originalHistoryForward = history . forward ;
6261 history . forward = function ( ) {
6362 self . historyAction = 'forward' ;
64- return originalHistoryForward ( arguments ) ;
63+ return originalHistoryForward . apply ( this , arguments ) ;
6564 } ;
6665
6766 this . historySize = - 1 ;
6867 this . historyPosition = - 1 ;
6968 this . historyAction = 'default' ;
69+
70+ this . $obContainer = $ ( '#obContainer' ) ;
71+ this . viewCache = { } ;
72+
73+ window . setInterval ( ( ) => {
74+ var cached ;
75+
76+ for ( var key in this . viewCache ) {
77+ if ( this . viewCache . hasOwnProperty ( key ) ) {
78+ cached = this . viewCache [ key ] ;
79+
80+ if ( Date . now ( ) - cached . cachedAt >= cached . view . cacheExpires ) {
81+ delete this . viewCache [ key ] ;
82+ }
83+ }
84+ }
85+ } , this . cleanCacheInterval ) ;
86+ } ,
87+
88+ // how often to clean out expired cached views
89+ cleanCacheInterval : 1 * 60 * 1000 ,
90+
91+ refresh : function ( ) {
92+ if ( this . view ) {
93+ // clear any cache for the view, so a fresh view is created
94+ delete this . viewCache [ this . view . constructor . getCacheIndex ( Backbone . history . getFragment ( ) ) ] ;
95+ }
96+
97+ Backbone . history . loadUrl ( ) ;
7098 } ,
7199
72100 translateRoute : function ( route ) {
@@ -159,43 +187,108 @@ module.exports = Backbone.Router.extend({
159187 window . obEventBus . trigger ( 'cleanNav' ) ;
160188 } ,
161189
162- newView : function ( view , bodyID , addressBarText , bodyClass ) {
163- var loadingConfig ;
190+ cacheView : function ( view , fragment ) {
191+ var index ;
192+
193+ fragment = fragment || Backbone . history . getFragment ( ) ;
194+ index = view . constructor . getCacheIndex ( fragment ) ;
195+
196+ this . viewCache [ index ] = {
197+ cachedAt : Date . now ( ) ,
198+ view : this . view
199+ }
200+ } ,
201+
202+ newView : function ( View , options ) {
203+ var now = Date . now ( ) ,
204+ cached = this . viewCache [ View . getCacheIndex ( Backbone . history . getFragment ( ) ) ] ,
205+ requestedRoute = Backbone . history . getFragment ( ) ,
206+ loadingConfig ;
207+
208+ options = __ . extend ( {
209+ // viewArgs can be an array of args to pass into the view or a single
210+ // arg (most likely an options object)
211+ viewArgs : [ { } ] ,
212+ addressBarText : '' ,
213+ bodyID : '' ,
214+ bodyClass : ''
215+ } , options || { } ) ;
216+
217+ options . viewArgs = options . viewArgs . length ? options . viewArgs : [ options . viewArgs ] ;
164218
165219 this . cleanup ( ) ;
166- //clear address bar. This will be replaced on the user page
167- addressBarText = addressBarText || "" ;
168- window . obEventBus . trigger ( "setAddressBar" , addressBarText ) ;
220+ window . obEventBus . trigger ( 'setAddressBar' , options . addressBarText ) ;
169221
170- if ( $ ( 'body' ) . attr ( 'id' ) != bodyID ) {
171- $ ( 'body' ) . attr ( "id" , bodyID || "" ) ;
172- }
173- if ( bodyClass ) {
174- $ ( 'body' ) . attr ( 'class' , bodyClass ) ;
175- }
176- $ ( '#obContainer' ) . removeClass ( "customizeUserPage" ) ; //remove customization styling if present
222+ $ ( 'body' ) . attr ( 'id' , options . bodyID ) ;
223+ $ ( 'body' ) . attr ( 'class' , options . bodyClass ) ;
224+ $ ( '#obContainer' ) . removeClass ( 'customizeUserPage' ) ; //remove customization styling if present
177225
178226 this . pageConnectModal && this . pageConnectModal . remove ( ) ;
179227 this . pageConnectModal = null ;
180228
181- if (
182- ( loadingConfig = __ . result ( view , 'loadingConfig' ) ) &&
183- loadingConfig . promise &&
184- typeof loadingConfig . promise . then === 'function' ) {
185- this . launchPageConnectModal ( loadingConfig ) ;
229+ // let's update the cache of our existing view (if it's cached && not expired) so
230+ // cachedAt is updated and the user has up until the view's 'cacheExpires' amount of
231+ // time to come back to it in it's current state.
232+ for ( var key in this . viewCache ) {
233+ if ( this . viewCache . hasOwnProperty ( key ) ) {
234+ let cached = this . viewCache [ key ] ;
235+
236+ if (
237+ cached . view === this . view &&
238+ ( Date . now ( ) - cached . cachedAt < cached . view . cacheExpires )
239+ ) {
240+ cached . cachedAt = Date . now ( ) ;
241+ }
242+ }
243+ }
244+
245+ // remove / detach any existing view
246+ if ( this . view ) {
247+ if ( this . view . cacheExpires ) {
248+ this . trigger ( 'cache-will-detach' , { view : this . view } ) ;
249+ this . view . $el . detach ( ) ;
250+ this . trigger ( 'cache-detached' , { view : this . view } ) ;
251+ } else {
252+ this . view . close ? this . view . close ( ) : this . view . remove ( )
253+ }
186254 }
187-
188- this . view && ( this . view . close ? this . view . close ( ) : this . view . remove ( ) ) ;
189- this . view = view ;
190255
191- $ ( '#obContainer' ) [ 0 ] . scrollTop = 0 ;
256+ if ( cached && ( now - cached . cachedAt < cached . view . cacheExpires ) ) {
257+ // we have an un-expired cached view, let's reattach it
258+ this . view = cached . view ;
259+
260+ $ ( '#content' ) . html ( this . view . $el ) ;
261+ this . view . delegateEvents ( ) ;
262+ this . $obContainer [ 0 ] . scrollTop = 0 ;
263+
264+ this . trigger ( 'cache-reattached' , {
265+ view : this . view ,
266+ route : requestedRoute
267+ } ) ;
268+ } else {
269+ this . view = new ( Function . prototype . bind . apply ( View , [ null ] . concat ( options . viewArgs ) ) ) ;
270+ $ ( '#content' ) . html ( this . view . $el ) ;
271+ this . $obContainer [ 0 ] . scrollTop = 0 ;
272+
273+ if (
274+ ( loadingConfig = __ . result ( this . view , 'loadingConfig' ) ) &&
275+ loadingConfig . promise &&
276+ typeof loadingConfig . promise . then === 'function' ) {
277+ this . launchPageConnectModal ( loadingConfig ) . done ( ( ) => {
278+ this . view . cacheExpires && this . cacheView ( this . view ) ;
279+ } ) ;
280+ } else {
281+ this . view . cacheExpires && this . cacheView ( this . view ) ;
282+ }
283+ }
192284 } ,
193285
194286 launchPageConnectModal : function ( config ) {
195287 var defaults = {
196- connectText : 'Connecting...' ,
197- failedText : 'Unable to Connect.'
198- } ;
288+ connectText : 'Connecting...' ,
289+ failedText : 'Unable to Connect.'
290+ } ,
291+ deferred = $ . Deferred ( ) ;
199292
200293 if ( ! (
201294 config &&
@@ -218,6 +311,7 @@ module.exports = Backbone.Router.extend({
218311
219312 this . pageConnectModal . on ( 'back' , ( ) => {
220313 history . back ( ) ;
314+ deferred . reject ( ) ;
221315 } ) ;
222316
223317 this . pageConnectModal . on ( 'retry' , ( ) => {
@@ -230,42 +324,49 @@ module.exports = Backbone.Router.extend({
230324
231325 this . pageConnectModal . on ( 'cancel' , ( ) => {
232326 typeof config . promise . cancel === 'function' && config . promise . cancel ( ) ;
327+ deferred . reject ( ) ;
233328 history . back ( ) ;
234329 } ) ;
235330
236331 config . promise . done ( ( ) => {
237332 this . pageConnectModal && this . pageConnectModal . remove ( ) ;
238333 this . pageConnectModal = null ;
334+ deferred . resolve ( ) ;
239335 } ) . fail ( ( ) => {
240- this . pageConnectModal . setState ( {
336+ this . pageConnectModal && this . pageConnectModal . setState ( {
241337 statusText : config . failedText ,
242338 mode : 'failed-connect' ,
243339 tooltip : config . failedTooltip
244340 } ) ;
341+ deferred . reject ( ) ;
245342 } ) ;
343+
344+ return deferred . promise ( ) ;
246345 } ,
247346
248347 index : function ( ) {
249- if ( localStorage . getItem ( "route" ) ) {
348+ if ( localStorage . getItem ( "route" ) ) {
250349 this . navigate ( '#' + localStorage . getItem ( "route" ) , { trigger : true } ) ;
251- } else if ( this . userProfile . get ( 'profile' ) . beenSet == true ) {
252- this . home ( ) ;
253350 } else {
254- this . userPage ( ) ;
351+ this . navigate ( '#home' , { trigger : true } ) ;
255352 }
256353 } ,
257354
258355 home : function ( state , searchText ) {
259- this . newView ( new homeView ( {
260- userModel : this . userModel ,
261- userProfile : this . userProfile ,
262- socketView : this . socketView ,
263- state : state ,
264- searchItemsText : searchText
265- } ) , '' , { 'addressText' : searchText ? "#" + searchText : "" } ) ;
356+ this . newView ( homeView , {
357+ viewArgs : {
358+ userModel : this . userModel ,
359+ userProfile : this . userProfile ,
360+ socketView : this . socketView ,
361+ state : state ,
362+ searchItemsText : searchText
363+ }
364+ } ) ;
266365
267366 // hide the discover onboarding callout
268- $ ( '.js-OnboardingIntroDiscoverHolder' ) . addClass ( 'hide' ) ;
367+ this . $discoverHolder = this . $discoverHolder || $ ( '.js-OnboardingIntroDiscoverHolder' ) ;
368+ this . $discoverHolder . addClass ( 'hide' ) ;
369+
269370 app . appBar . setTitle ( window . polyglot . t ( 'Discover' ) ) ;
270371 } ,
271372
@@ -282,7 +383,16 @@ module.exports = Backbone.Router.extend({
282383
283384 if ( handle ) options . handle = handle ;
284385
285- this . newView ( new userPageView ( options ) , "userPage" , '' , 'onPage' ) ;
386+ if ( ! userID ) {
387+ this . navigate ( `userPage/${ this . userModel . get ( 'guid' ) } ` , { replace : true } ) ;
388+ }
389+
390+ this . newView ( userPageView , {
391+ viewArgs : options ,
392+ bodyID : 'userPage' ,
393+ bodyClass : 'onPage'
394+ } ) ;
395+
286396 app . appBar . setTitle ( handle ? handle : options . userId || this . userModel . get ( 'guid' ) ) ;
287397 } ,
288398
@@ -302,6 +412,7 @@ module.exports = Backbone.Router.extend({
302412 // we want this to happen after the launchPageConnectModal processes
303413 // the resolution of the promise, hence the timeout.
304414 setTimeout ( ( ) => {
415+ this . navigate ( `userPage/${ guid } ${ subPath ? '/' + subPath : '' } ` , { replace : true } ) ;
305416 this . userPage ( guid , state , itemHash , skipNSFWmodal , '@' + handle ) ;
306417 } , 0 ) ;
307418 } ) ;
@@ -317,25 +428,33 @@ module.exports = Backbone.Router.extend({
317428 } ,
318429
319430 transactions : function ( state , orderID , tabState ) {
320- this . newView ( new transactionsView ( {
321- userModel : this . userModel ,
322- userProfile : this . userProfile ,
323- socketView : this . socketView ,
324- state : state ,
325- orderID : orderID ,
326- tabState : tabState //opens a tab in the order modal
327- } ) , "userPage" ) ;
431+ this . newView ( transactionsView , {
432+ viewArgs : {
433+ userModel : this . userModel ,
434+ userProfile : this . userProfile ,
435+ socketView : this . socketView ,
436+ state : state ,
437+ orderID : orderID ,
438+ tabState : tabState //opens a tab in the order modal
439+ } ,
440+ bodyID : 'transactionsPage'
441+ } ) ;
442+
328443 app . appBar . setTitle ( window . polyglot . t ( 'Transactions' ) ) ;
329444 } ,
330445
331446 settings : function ( state ) {
332447 $ ( '.js-loadingModal' ) . addClass ( 'show' ) ;
333- this . newView ( new settingsView ( {
334- userModel : this . userModel ,
335- userProfile : this . userProfile ,
336- state : state ,
337- socketView : this . socketView
338- } ) , "userPage" ) ;
448+
449+ this . newView ( settingsView , {
450+ viewArgs : {
451+ userModel : this . userModel ,
452+ userProfile : this . userProfile ,
453+ state : state ,
454+ socketView : this . socketView
455+ }
456+ } ) ;
457+
339458 app . appBar . setTitle ( window . polyglot . t ( 'Settings' ) ) ;
340459 }
341460} ) ;
0 commit comments