diff --git a/www/js/ts.js b/www/js/ts.js index 7923023..8a9eca1 100644 --- a/www/js/ts.js +++ b/www/js/ts.js @@ -11,10 +11,40 @@ $(document).ready(function(){ * - id * - mark * - notes - * - start + * - timestamp */ TS.EntryModel = Backbone.Model.extend({ + get: function(attribute) { + if (attribute == "timestamp") { + if (!this.timestampDate) { + this.timestampDate = new Date( + Backbone.Model.prototype.get.call(this, attribute)); + } + return this.timestampDate; + } else { + return Backbone.Model.prototype.get.call(this, attribute); + } + }, + + set: function(attributes, options) { + var attrsToSet = {} + _.each(attributes, function(val, key) { + if (key == "timestamp") { + if (val instanceof Date) { + this.timestampDate = val; + attrsToSet.timestamp = dateToJSON(val); + } else { + this.timestampDate = new Date(val); + attrsToSet.timestamp = dateToJSON(this.timestampDate); + } + } else { + attrsToSet[key] = val; + } + }); + + return Backbone.Model.prototype.set.call(this, attrsToSet, options); + } }); /* Timeline model. @@ -207,7 +237,7 @@ $(document).ready(function(){ save: function() { this.model.save({ mark: this.$('.mark-input').val(), - timestamp: this.$('.timestamp-input').val(), + timestamp: new Date(this.$('.timestamp-input').val()), notes: this.$('.notes-input').val()}); }, @@ -250,12 +280,12 @@ $(document).ready(function(){ * @return the duration between model and nextModel, formatted for * display: `Xd Yhr Zm`. */ formatDuration: function(model, nextModel) { - var d1 = new Date(model.get('timestamp')); + var d1 = model.get('timestamp'); var d2, diff; var day, hr, min; // if no next model, assume it's an onoing task - if (nextModel) { d2 = new Date(nextModel.get('timestamp')); } + if (nextModel) { d2 = nextModel.get('timestamp'); } else { d2 = new Date(); } diff= d2.getTime() - d1.getTime(); @@ -345,7 +375,7 @@ $(document).ready(function(){ // create the mark. Immediately fetch to get server-side timestamp this.collection.create({mark: entryMark, notes: '', - timestamp: getUTCTimestamp()}).fetch(); + timestamp: new Date()}).fetch(); // clear the input for the next entry this.$("#new-entry-input").val(""); @@ -367,11 +397,23 @@ $(document).ready(function(){ userExclusions.concat(timelineExclusions), function(exclusion) { return new RegExp(exclusion)} ); + // clear existing elements in the view container this.entryContainer.empty(); + + // last day we have printed a separator for + var currentDay = null; + var today = new Date(); + + // iterate through the collection and render the elements. for (var i = 0, len = this.collection.length; i < len; i++) { var entry = this.collection.at(i); var nextEntry = (i + 1 < len ? this.collection.at(i + 1) : null); + if (currentDay != entry.get('timestamp').getDate()) { + currentDay = entry.get('timestamp').getDate(); + + } + this.renderOne(entry, nextEntry); } } @@ -687,7 +729,7 @@ $(document).ready(function(){ var timelineDesc = this.$("#new-timeline-desc").val(); this.timelineCollection.create( {id: timelineId, description: timelineDesc, - created: getUTCTimestamp()}); + created: dateToJSON(new Date())}); this.hide(); }, @@ -705,9 +747,7 @@ $(document).ready(function(){ }) -function getUTCTimestamp() { - var d = new Date(); - +function dateToJSON(d) { function pad(n){return n<10 ? '0'+n : n} return d.getUTCFullYear()+'-' @@ -718,3 +758,58 @@ function getUTCTimestamp() { + pad(d.getUTCSeconds())+'Z'; } +function daysApart(d1, d2) { + var daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30]; + + days1 = (d1.getFullYear() * 365) + daysInMonth[d1.getMonth()] + d1.getDate(); + days2 = (d2.getFullYear() * 365) + daysInMonth[d2.getMonth()] + d2.getDate(); + + return days1 - days2; +} + +function getEnglishDate(d) { + if (typeof getEnglishDate.today == 'undefined') { + getEnglishDate.today = new Date() }; + + var yearDiff = today.getFullYear() - d.getFullYear(); + var monthDiff = today.getMonth() - d.getMonth(); + var dayDiff = today.getDate() - d.getDate(); + + if (yearDiff > 1) { return capitalize(toWords(yearDiff)) + " years ago."; } + else if (yearDiff > 0) { return "Last year"; } + else if (monthDiff > 1) { + return capitalize(toWords(monthDiff)) + "months ago."; } + else if (monthDiff > 0) { return "Last month."; } + else if (dayDiff > 0) { + // weeks as 7-day periods + var weekDiff = Math.ceil(dayDiff / 7) + + // adjust for the hard boundary of the weekend + if (today.getDay() > d.getDay()) { weekDiff--; } + + if (weekDiff > 1) { + return capitalize(toWords(weekDiff)) + " weeks ago."; } + else if (weekDiff > 0) { return "Last week."; } + else { return capitalize(toWords(dayDiff)) + " days ago."; } + + } else if (yearDiff < 0 || monthDiff < 0 || daysDiff < 0) { + return "In the future."; } + else { return "Today."; } +} + + +function toWords(i) { + if (typeof toWords.words == 'undefined') { + toWords.words = ['zero','one','two','three','four', 'five','six', + 'seven','eight','nine','ten','eleven','twelve', + 'thirteen', 'fourteen','fifteen','sixteen', + 'seventeen','eighteen','nineteen' ]; + } + + if (i < 20) { return toWords.words[i]; } + else { return i.toString(); } +} + +function capitalize(s) { + return s.slice(0, 1).toUpperCase() + s.slice(1); +}