diff --git a/IPython/html/static/base/js/utils.js b/IPython/html/static/base/js/utils.js index 044a045..714faba 100644 --- a/IPython/html/static/base/js/utils.js +++ b/IPython/html/static/base/js/utils.js @@ -5,9 +5,10 @@ define([ 'base/js/namespace', 'jquery', 'codemirror/lib/codemirror', + 'moment', // silently upgrades CodeMirror 'codemirror/mode/meta', -], function(IPython, $, CodeMirror){ +], function(IPython, $, CodeMirror, moment){ "use strict"; IPython.load_extensions = function () { @@ -784,7 +785,42 @@ define([ return MathJax.Hub.Queue(["Typeset", MathJax.Hub, this]); }); }; - + + var time = {}; + time.milliseconds = {}; + time.milliseconds.s = 1000; + time.milliseconds.m = 60 * time.milliseconds.s; + time.milliseconds.h = 60 * time.milliseconds.m; + time.milliseconds.d = 24 * time.milliseconds.h; + + time.thresholds = { + // moment.js thresholds in milliseconds + s: moment.relativeTimeThreshold('s') * time.milliseconds.s, + m: moment.relativeTimeThreshold('m') * time.milliseconds.m, + h: moment.relativeTimeThreshold('h') * time.milliseconds.h, + d: moment.relativeTimeThreshold('d') * time.milliseconds.d, + }; + + time.timeout_from_dt = function (dt) { + /** compute a timeout based on dt + + input and output both in milliseconds + + use moment's relative time thresholds: + + - 10 seconds if in 'seconds ago' territory + - 1 minute if in 'minutes ago' + - 1 hour otherwise + */ + if (dt < time.thresholds.s) { + return 10 * time.milliseconds.s; + } else if (dt < time.thresholds.m) { + return time.milliseconds.m; + } else { + return time.milliseconds.h; + } + }; + var utils = { regex_split : regex_split, uuid : uuid, @@ -820,6 +856,7 @@ define([ resolve_promises_dict: resolve_promises_dict, reject: reject, typeset: typeset, + time: time, }; // Backwards compatability. diff --git a/IPython/html/static/components b/IPython/html/static/components index 87ff70d..6b578bb 160000 --- a/IPython/html/static/components +++ b/IPython/html/static/components @@ -1 +1 @@ -Subproject commit 87ff70d96567bf055eb94161a41e7b3e6da31b23 +Subproject commit 6b578bb789708ded9b6611039d162c71135dfd68 diff --git a/IPython/html/static/edit/js/savewidget.js b/IPython/html/static/edit/js/savewidget.js index 5688780..c71cafd 100644 --- a/IPython/html/static/edit/js/savewidget.js +++ b/IPython/html/static/edit/js/savewidget.js @@ -141,47 +141,22 @@ define([ var long_date = chkd.format('llll'); var human_date; var tdelta = Math.ceil(new Date() - this._last_modified); - if (tdelta < 24 * H){ + if (tdelta < utils.time.milliseconds.d){ // less than 24 hours old, use relative date human_date = chkd.fromNow(); } else { - // otherwise show calendar - // otherwise update every hour and show + // otherwise show calendar // at hh,mm,ss human_date = chkd.calendar(); } el.text(human_date).attr('title', long_date); }; - - - var S = 1000; - var M = 60*S; - var H = 60*M; - var thresholds = { - s: 45 * S, - m: 45 * M, - h: 22 * H - }; - var _timeout_from_dt = function (ms) { - /** compute a timeout to update the last-modified timeout - - based on the delta in milliseconds - */ - if (ms < thresholds.s) { - return 5 * S; - } else if (ms < thresholds.m) { - return M; - } else { - return 5 * M; - } - }; SaveWidget.prototype._schedule_render_last_modified = function () { /** schedule the next update to relative date periodically updated, so short values like 'a few seconds ago' don't get stale. */ - var that = this; if (!this._last_modified) { return; } @@ -189,12 +164,10 @@ define([ clearTimeout(this._last_modified_timeout); } var dt = Math.ceil(new Date() - this._last_modified); - if (dt < 24 * H) { - this._last_modified_timeout = setTimeout( - $.proxy(this._render_last_modified, this), - _timeout_from_dt(dt) - ); - } + this._last_modified_timeout = setTimeout( + $.proxy(this._render_last_modified, this), + utils.time.timeout_from_dt(dt) + ); }; return {'SaveWidget': SaveWidget}; diff --git a/IPython/html/static/notebook/js/savewidget.js b/IPython/html/static/notebook/js/savewidget.js index 6b9db96..d1c6f6e 100644 --- a/IPython/html/static/notebook/js/savewidget.js +++ b/IPython/html/static/notebook/js/savewidget.js @@ -155,93 +155,58 @@ define([ this.element.find('span.autosave_status').text(msg); }; - SaveWidget.prototype._set_checkpoint_status = function (human_date, iso_date) { - var el = this.element.find('span.checkpoint_status'); - if(human_date){ - el.text("Last Checkpoint: "+human_date).attr('title',iso_date); + SaveWidget.prototype._set_last_checkpoint = function (checkpoint) { + if (checkpoint) { + this._checkpoint_date = new Date(checkpoint.last_modified); } else { - el.text('').attr('title', 'no-checkpoint'); - } - }; - - // compute (roughly) the remaining time in millisecond until the next - // moment.js relative time update of the string, which by default - // happend at - // (a few seconds ago) - // - 45sec, - // (a minute ago) - // - 90sec, - // ( x minutes ago) - // - then every minutes until - // - 45 min, - // (an hour ago) - // - 1h45, - // (x hours ago ) - // - then every hours - // - 22 hours ago - var _next_timeago_update = function(deltatime_ms){ - var s = 1000; - var m = 60*s; - var h = 60*m; - - var mtt = moment.relativeTimeThreshold; - - if(deltatime_ms < mtt.s*s){ - return mtt.s*s-deltatime_ms; - } else if (deltatime_ms < (mtt.s*s+m)) { - return (mtt.s*s+m)-deltatime_ms; - } else if (deltatime_ms < mtt.m*m){ - return m; - } else if (deltatime_ms < (mtt.m*m+h)){ - return (mtt.m*m+h)-deltatime_ms; - } else { - return h; + this._checkpoint_date = null; } + this._render_checkpoint(); }; - - SaveWidget.prototype._regularly_update_checkpoint_date = function(){ - if (!this._checkpoint_date) { - this._set_checkpoint_status(null); - console.log('no checkpoint done'); + + SaveWidget.prototype._render_checkpoint = function () { + /** actually set the text in the element, from our _checkpoint value + + called directly, and periodically in timeouts. + */ + this._schedule_render_checkpoint(); + var el = this.element.find('span.checkpoint_status'); + if (!this._checkpoint_date) { + el.text('').attr('title', 'no checkpoint'); return; } var chkd = moment(this._checkpoint_date); - var longdate = chkd.format('llll'); - - var that = this; - var recall = function(t){ - /** - * recall slightly later (1s) as long timeout in js might be imprecise, - * and you want to be call **after** the change of formatting should happend. - */ - return setTimeout( - $.proxy(that._regularly_update_checkpoint_date, that), - t + 1000 - ); - }; - var tdelta = Math.ceil(new Date()-this._checkpoint_date); - - // update regularly for the first 6hours and show - // ago - if(tdelta < 6*3600*1000){ - recall(_next_timeago_update(tdelta)); - this._set_checkpoint_status(chkd.fromNow(), longdate); - // otherwise update every hour and show - // at hh,mm,ss - } else { - recall(1*3600*1000); - this._set_checkpoint_status(chkd.calendar(), longdate); + var long_date = chkd.format('llll'); + var human_date; + var tdelta = Math.ceil(new Date() - this._checkpoint_date); + if (tdelta < utils.time.milliseconds.d){ + // less than 24 hours old, use relative date + human_date = chkd.fromNow(); + } else { + // otherwise show calendar + // at hh,mm,ss + human_date = chkd.calendar(); } + el.text('Last Checkpoint: ' + human_date).attr('title', long_date); }; - SaveWidget.prototype._set_last_checkpoint = function (checkpoint) { - if (checkpoint) { - this._checkpoint_date = new Date(checkpoint.last_modified); - } else { - this._checkpoint_date = null; + + SaveWidget.prototype._schedule_render_checkpoint = function () { + /** schedule the next update to relative date + + periodically updated, so short values like 'a few seconds ago' don't get stale. + */ + if (!this._checkpoint_date) { + return; } - this._regularly_update_checkpoint_date(); - + if ((this._checkpoint_timeout)) { + clearTimeout(this._checkpoint_timeout); + } + var dt = Math.ceil(new Date() - this._checkpoint_date); + this._checkpoint_timeout = setTimeout( + $.proxy(this._render_checkpoint, this), + utils.time.timeout_from_dt(dt) + ); }; SaveWidget.prototype.set_autosaved = function (dirty) {