@@ -7,15 +7,16 @@ define([
77 'base/js/utils' ,
88 'base/js/dialog' ,
99 'base/js/keyboard' ,
10- 'dateformat ' ,
11- ] , function ( IPython , $ , utils , dialog , keyboard , dateformat ) {
10+ 'moment ' ,
11+ ] , function ( IPython , $ , utils , dialog , keyboard , moment ) {
1212 "use strict" ;
1313
1414 var SaveWidget = function ( selector , options ) {
1515 // TODO: Remove circular ref.
1616 this . notebook = undefined ;
1717 this . selector = selector ;
1818 this . events = options . events ;
19+ this . _checkpoint_date = undefined ;
1920 this . keyboard_manager = options . keyboard_manager ;
2021 if ( this . selector !== undefined ) {
2122 this . element = $ ( selector ) ;
@@ -51,11 +52,11 @@ define([
5152 that . set_save_status ( 'Autosave Failed!' ) ;
5253 } ) ;
5354 this . events . on ( 'checkpoints_listed.Notebook' , function ( event , data ) {
54- that . set_last_checkpoint ( data [ 0 ] ) ;
55+ that . _set_last_checkpoint ( data [ 0 ] ) ;
5556 } ) ;
5657
5758 this . events . on ( 'checkpoint_created.Notebook' , function ( event , data ) {
58- that . set_last_checkpoint ( data ) ;
59+ that . _set_last_checkpoint ( data ) ;
5960 } ) ;
6061 this . events . on ( 'set_dirty.Notebook' , function ( event , data ) {
6162 that . set_autosaved ( data . value ) ;
@@ -123,7 +124,7 @@ define([
123124 var nbname = this . notebook . get_notebook_name ( ) ;
124125 document . title = nbname ;
125126 } ;
126-
127+
127128 SaveWidget . prototype . update_address_bar = function ( ) {
128129 var base_url = this . notebook . base_url ;
129130 var nbname = this . notebook . notebook_name ;
@@ -142,19 +143,87 @@ define([
142143 this . element . find ( 'span#autosave_status' ) . text ( msg ) ;
143144 } ;
144145
145- SaveWidget . prototype . set_checkpoint_status = function ( msg ) {
146- this . element . find ( 'span#checkpoint_status' ) . text ( msg ) ;
146+ SaveWidget . prototype . _set_checkpoint_status = function ( human_date , iso_date ) {
147+ var el = this . element . find ( 'span#checkpoint_status' )
148+ if ( human_date ) {
149+ el . text ( "Last Checkpoint: " + human_date ) . attr ( 'title' , iso_date ) ;
150+ } else {
151+ el . text ( '' ) . attr ( 'title' , 'no-checkpoint' )
152+ }
147153 } ;
148154
149- SaveWidget . prototype . set_last_checkpoint = function ( checkpoint ) {
150- if ( ! checkpoint ) {
151- this . set_checkpoint_status ( "" ) ;
155+ // compute (roughly) the remaining time in millisecond until the next
156+ // moment.js relative time update of the string, which by default
157+ // happend at
158+ // (a few seconds ago)
159+ // - 45sec,
160+ // (a minute ago)
161+ // - 90sec,
162+ // ( x minutes ago)
163+ // - then every minutes until
164+ // - 45 min,
165+ // (an hour ago)
166+ // - 1h45,
167+ // (x hours ago )
168+ // - then every hours
169+ // - 22 hours ago
170+ var _next_timeago_update = function ( deltatime_ms ) {
171+ var s = 1000 ;
172+ var m = 60 * s ;
173+ var h = 60 * m ;
174+
175+ var mtt = moment . relativeTimeThreshold ;
176+
177+ if ( deltatime_ms < mtt . s * s ) {
178+ return mtt . s * s - deltatime_ms ;
179+ } else if ( deltatime_ms < ( mtt . s * s + m ) ) {
180+ return ( mtt . s * s + m ) - deltatime_ms ;
181+ } else if ( deltatime_ms < mtt . m * m ) {
182+ return m ;
183+ } else if ( deltatime_ms < ( mtt . m * m + h ) ) {
184+ return ( mtt . m * m + h ) - deltatime_ms ;
185+ } else {
186+ return h ;
187+ }
188+
189+
190+ }
191+
192+ SaveWidget . prototype . _regularly_update_checkpoint_date = function ( ) {
193+ if ( ! this . _checkpoint_date ) {
194+ this . set_checkpoint_status ( null ) ;
195+ console . log ( 'no checkpoint done' ) ;
152196 return ;
153197 }
154- var d = new Date ( checkpoint . last_modified ) ;
155- this . set_checkpoint_status (
156- "Last Checkpoint: " + dateformat ( d , 'mmm dd HH:MM' )
157- ) ;
198+ var chkd = moment ( this . _checkpoint_date ) ;
199+ var longdate = chkd . format ( 'llll' ) ;
200+
201+ var that = this ;
202+ var recall = function ( t ) {
203+ // recall slightly later (1s) as long timeout in js might be imprecise,
204+ // and you want to be call **after** the change of formatting should happend.
205+ return setTimeout ( $ . proxy ( that . _regularly_update_checkpoint_date , that ) , ( t + 1000 ) )
206+ }
207+ var tdelta = Math . ceil ( new Date ( ) - this . _checkpoint_date ) ;
208+
209+ // update regularly for the first 6hours and show
210+ // <x time> ago
211+ if ( tdelta < tdelta < 6 * 3600 * 1000 ) {
212+ recall ( _next_timeago_update ( tdelta ) ) ;
213+ this . _set_checkpoint_status ( chkd . fromNow ( ) , longdate ) ;
214+ // otherwise update every hour and show
215+ // <Today | yesterday|...> at hh,mm,ss
216+ } else {
217+ recall ( 1 * 3600 * 1000 )
218+ this . _set_checkpoint_status ( chkd . calendar ( ) , longdate ) ;
219+ }
220+
221+ }
222+
223+ SaveWidget . prototype . _set_last_checkpoint = function ( checkpoint ) {
224+ this . _checkpoint_date = new Date ( checkpoint . last_modified ) ;
225+ this . _regularly_update_checkpoint_date ( ) ;
226+
158227 } ;
159228
160229 SaveWidget . prototype . set_autosaved = function ( dirty ) {
0 commit comments