Merge branch 'hotfix/21.56.9' into master
[gitter.git] / public / js / views / behaviors / timeago.js
blobfe38093373009ab22d712519b3886714f7be169d
1 'use strict';
3 var Marionette = require('backbone.marionette');
4 var behaviourLookup = require('./lookup');
5 var timeFormat = require('gitter-web-shared/time/time-format');
7 var MS_IN_SECOND = 1000;
8 var MS_IN_MINUTE = 60 * MS_IN_SECOND;
9 var MS_IN_HOUR = 60 * MS_IN_MINUTE;
10 var MS_IN_DAY = 24 * MS_IN_HOUR;
12 /**
13  * If the supplied time is 'today' from the persepective of the
14  * user's local timezone, returns the number of milliseconds until
15  * midnight in the user's local timezone.
16  *
17  * For example:
18  *   At midnight, will return 86400k
19  *   At noon, will return 43200k
20  *   At 11pm, will return 3600k
21  *   At 11:59:59.000, will return 1k
22  *
23  * Currently, does not handle daylight savings changeover days.
24  */
25 function timeRemainingTodayLocalTZ(time) {
26   if (!time) return 0;
28   var now = new Date();
29   var nowYear = now.getFullYear();
30   var nowMonth = now.getMonth();
31   var nowDay = now.getDate();
33   if (time instanceof Date) {
34     if (
35       time.getDate() === nowDay &&
36       time.getMonth() === nowMonth &&
37       time.getFullYear() === nowYear
38     ) {
39       return (
40         MS_IN_DAY -
41         time.getHours() * MS_IN_HOUR +
42         time.getMinutes() * MS_IN_MINUTE +
43         time.getSeconds() * MS_IN_SECOND +
44         time.getMilliseconds()
45       );
46     }
47   }
49   // Deal with moment dates
50   if (time.date) {
51     if (time.date() === nowDay && time.month() === nowMonth && time.year() === nowYear) {
52       return (
53         MS_IN_DAY -
54         time.hour() * MS_IN_HOUR +
55         time.minute() * MS_IN_MINUTE +
56         time.second() * MS_IN_SECOND +
57         time.millisecond()
58       );
59     }
60   }
62   return 0;
65 var Behavior = Marionette.Behavior.extend({
66   defaults: {
67     modelAttribute: null,
68     el: null
69   },
71   ui: function() {
72     return {
73       time: this.options.el
74     };
75   },
77   modelEvents: function() {
78     var result = {};
79     result['change:' + this.options.modelAttribute] = 'onTimeChange';
80     return result;
81   },
83   initialize: function() {
84     this.timer = null;
85   },
87   onTimeChange: function(model) {
88     if (this.timer) {
89       clearTimeout(this.timer);
90       this.timer = null;
91     }
93     var time = model.get(this.options.modelAttribute);
95     var timeRemaining = timeRemainingTodayLocalTZ(time);
96     if (timeRemaining > 0) {
97       // Add one millisecond onto the time to make sure that it's definitely
98       // into the new day
99       this.timer = setTimeout(this.onTimeChange.bind(this, model), timeRemaining + 1);
100     }
102     this.renderTime(time);
103   },
105   renderTime: function(time) {
106     var timeElement = this.ui.time[0];
107     if (timeElement) {
108       var text = timeFormat(time, { compact: this.options.compact });
109       timeElement.textContent = text;
110     }
111   },
113   onDestroy: function() {
114     if (this.timer) {
115       clearTimeout(this.timer);
116       this.timer = null;
117     }
118   }
121 behaviourLookup.register('TimeAgo', Behavior);
122 module.exports = Behavior;