1
+ /**
2
+ * Timeago is a jQuery plugin that makes it easy to support automatically
3
+ * updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").
4
+ *
5
+ * @name timeago
6
+ * @version 1.6.7
7
+ * @requires jQuery >=1.5.0 <4.0
8
+ * @author Ryan McGeary
9
+ * @license MIT License - http://www.opensource.org/licenses/mit-license.php
10
+ *
11
+ * For usage and examples, visit:
12
+ * http://timeago.yarp.com/
13
+ *
14
+ * Copyright (c) 2008-2019, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org)
15
+ */
16
+
17
+ ( function ( factory ) {
18
+ if ( typeof define === 'function' && define . amd ) {
19
+ // AMD. Register as an anonymous module.
20
+ define ( [ 'jquery' ] , factory ) ;
21
+ } else if ( typeof module === 'object' && typeof module . exports === 'object' ) {
22
+ factory ( require ( 'jquery' ) ) ;
23
+ } else {
24
+ // Browser globals
25
+ factory ( jQuery ) ;
26
+ }
27
+ } ( function ( $ ) {
28
+ $ . timeago = function ( timestamp ) {
29
+ if ( timestamp instanceof Date ) {
30
+ return inWords ( timestamp ) ;
31
+ } else if ( typeof timestamp === "string" ) {
32
+ return inWords ( $ . timeago . parse ( timestamp ) ) ;
33
+ } else if ( typeof timestamp === "number" ) {
34
+ return inWords ( new Date ( timestamp ) ) ;
35
+ } else {
36
+ return inWords ( $ . timeago . datetime ( timestamp ) ) ;
37
+ }
38
+ } ;
39
+ var $t = $ . timeago ;
40
+
41
+ $ . extend ( $ . timeago , {
42
+ settings : {
43
+ refreshMillis : 60000 ,
44
+ allowPast : true ,
45
+ allowFuture : false ,
46
+ localeTitle : false ,
47
+ cutoff : 0 ,
48
+ autoDispose : true ,
49
+ strings : {
50
+ prefixAgo : null ,
51
+ prefixFromNow : null ,
52
+ suffixAgo : "ago" ,
53
+ suffixFromNow : "from now" ,
54
+ inPast : 'any moment now' ,
55
+ seconds : "less than a minute" ,
56
+ minute : "about a minute" ,
57
+ minutes : "%d minutes" ,
58
+ hour : "about an hour" ,
59
+ hours : "about %d hours" ,
60
+ day : "a day" ,
61
+ days : "%d days" ,
62
+ month : "about a month" ,
63
+ months : "%d months" ,
64
+ year : "about a year" ,
65
+ years : "%d years" ,
66
+ wordSeparator : " " ,
67
+ numbers : [ ]
68
+ }
69
+ } ,
70
+
71
+ inWords : function ( distanceMillis ) {
72
+ if ( ! this . settings . allowPast && ! this . settings . allowFuture ) {
73
+ throw 'timeago allowPast and allowFuture settings can not both be set to false.' ;
74
+ }
75
+
76
+ var $l = this . settings . strings ;
77
+ var prefix = $l . prefixAgo ;
78
+ var suffix = $l . suffixAgo ;
79
+ if ( this . settings . allowFuture ) {
80
+ if ( distanceMillis < 0 ) {
81
+ prefix = $l . prefixFromNow ;
82
+ suffix = $l . suffixFromNow ;
83
+ }
84
+ }
85
+
86
+ if ( ! this . settings . allowPast && distanceMillis >= 0 ) {
87
+ return this . settings . strings . inPast ;
88
+ }
89
+
90
+ var seconds = Math . abs ( distanceMillis ) / 1000 ;
91
+ var minutes = seconds / 60 ;
92
+ var hours = minutes / 60 ;
93
+ var days = hours / 24 ;
94
+ var years = days / 365 ;
95
+
96
+ function substitute ( stringOrFunction , number ) {
97
+ var string = $ . isFunction ( stringOrFunction ) ? stringOrFunction ( number , distanceMillis ) : stringOrFunction ;
98
+ var value = ( $l . numbers && $l . numbers [ number ] ) || number ;
99
+ return string . replace ( / % d / i, value ) ;
100
+ }
101
+
102
+ var words = seconds < 45 && substitute ( $l . seconds , Math . round ( seconds ) ) ||
103
+ seconds < 90 && substitute ( $l . minute , 1 ) ||
104
+ minutes < 45 && substitute ( $l . minutes , Math . round ( minutes ) ) ||
105
+ minutes < 90 && substitute ( $l . hour , 1 ) ||
106
+ hours < 24 && substitute ( $l . hours , Math . round ( hours ) ) ||
107
+ hours < 42 && substitute ( $l . day , 1 ) ||
108
+ days < 30 && substitute ( $l . days , Math . round ( days ) ) ||
109
+ days < 45 && substitute ( $l . month , 1 ) ||
110
+ days < 365 && substitute ( $l . months , Math . round ( days / 30 ) ) ||
111
+ years < 1.5 && substitute ( $l . year , 1 ) ||
112
+ substitute ( $l . years , Math . round ( years ) ) ;
113
+
114
+ var separator = $l . wordSeparator || "" ;
115
+ if ( $l . wordSeparator === undefined ) { separator = " " ; }
116
+ return $ . trim ( [ prefix , words , suffix ] . join ( separator ) ) ;
117
+ } ,
118
+
119
+ parse : function ( iso8601 ) {
120
+ var s = $ . trim ( iso8601 ) ;
121
+ s = s . replace ( / \. \d + / , "" ) ; // remove milliseconds
122
+ s = s . replace ( / - / , "/" ) . replace ( / - / , "/" ) ;
123
+ s = s . replace ( / T / , " " ) . replace ( / Z / , " UTC" ) ;
124
+ s = s . replace ( / ( [ \+ \- ] \d \d ) \: ? ( \d \d ) / , " $1$2" ) ; // -04:00 -> -0400
125
+ s = s . replace ( / ( [ \+ \- ] \d \d ) $ / , " $100" ) ; // +09 -> +0900
126
+ return new Date ( s ) ;
127
+ } ,
128
+ datetime : function ( elem ) {
129
+ var iso8601 = $t . isTime ( elem ) ? $ ( elem ) . attr ( "datetime" ) : $ ( elem ) . attr ( "title" ) ;
130
+ return $t . parse ( iso8601 ) ;
131
+ } ,
132
+ isTime : function ( elem ) {
133
+ // jQuery's `is()` doesn't play well with HTML5 in IE
134
+ return $ ( elem ) . get ( 0 ) . tagName . toLowerCase ( ) === "time" ; // $(elem).is("time");
135
+ }
136
+ } ) ;
137
+
138
+ // functions that can be called via $(el).timeago('action')
139
+ // init is default when no action is given
140
+ // functions are called with context of a single element
141
+ var functions = {
142
+ init : function ( ) {
143
+ functions . dispose . call ( this ) ;
144
+ var refresh_el = $ . proxy ( refresh , this ) ;
145
+ refresh_el ( ) ;
146
+ var $s = $t . settings ;
147
+ if ( $s . refreshMillis > 0 ) {
148
+ this . _timeagoInterval = setInterval ( refresh_el , $s . refreshMillis ) ;
149
+ }
150
+ } ,
151
+ update : function ( timestamp ) {
152
+ var date = ( timestamp instanceof Date ) ? timestamp : $t . parse ( timestamp ) ;
153
+ $ ( this ) . data ( 'timeago' , { datetime : date } ) ;
154
+ if ( $t . settings . localeTitle ) {
155
+ $ ( this ) . attr ( "title" , date . toLocaleString ( ) ) ;
156
+ }
157
+ refresh . apply ( this ) ;
158
+ } ,
159
+ updateFromDOM : function ( ) {
160
+ $ ( this ) . data ( 'timeago' , { datetime : $t . parse ( $t . isTime ( this ) ? $ ( this ) . attr ( "datetime" ) : $ ( this ) . attr ( "title" ) ) } ) ;
161
+ refresh . apply ( this ) ;
162
+ } ,
163
+ dispose : function ( ) {
164
+ if ( this . _timeagoInterval ) {
165
+ window . clearInterval ( this . _timeagoInterval ) ;
166
+ this . _timeagoInterval = null ;
167
+ }
168
+ }
169
+ } ;
170
+
171
+ $ . fn . timeago = function ( action , options ) {
172
+ var fn = action ? functions [ action ] : functions . init ;
173
+ if ( ! fn ) {
174
+ throw new Error ( "Unknown function name '" + action + "' for timeago" ) ;
175
+ }
176
+ // each over objects here and call the requested function
177
+ this . each ( function ( ) {
178
+ fn . call ( this , options ) ;
179
+ } ) ;
180
+ return this ;
181
+ } ;
182
+
183
+ function refresh ( ) {
184
+ var $s = $t . settings ;
185
+
186
+ //check if it's still visible
187
+ if ( $s . autoDispose && ! $ . contains ( document . documentElement , this ) ) {
188
+ //stop if it has been removed
189
+ $ ( this ) . timeago ( "dispose" ) ;
190
+ return this ;
191
+ }
192
+
193
+ var data = prepareData ( this ) ;
194
+
195
+ if ( ! isNaN ( data . datetime ) ) {
196
+ if ( $s . cutoff === 0 || Math . abs ( distance ( data . datetime ) ) < $s . cutoff ) {
197
+ $ ( this ) . text ( inWords ( data . datetime ) ) ;
198
+ } else {
199
+ if ( $ ( this ) . attr ( 'title' ) . length > 0 ) {
200
+ $ ( this ) . text ( $ ( this ) . attr ( 'title' ) ) ;
201
+ }
202
+ }
203
+ }
204
+ return this ;
205
+ }
206
+
207
+ function prepareData ( element ) {
208
+ element = $ ( element ) ;
209
+ if ( ! element . data ( "timeago" ) ) {
210
+ element . data ( "timeago" , { datetime : $t . datetime ( element ) } ) ;
211
+ var text = $ . trim ( element . text ( ) ) ;
212
+ if ( $t . settings . localeTitle ) {
213
+ element . attr ( "title" , element . data ( 'timeago' ) . datetime . toLocaleString ( ) ) ;
214
+ } else if ( text . length > 0 && ! ( $t . isTime ( element ) && element . attr ( "title" ) ) ) {
215
+ element . attr ( "title" , text ) ;
216
+ }
217
+ }
218
+ return element . data ( "timeago" ) ;
219
+ }
220
+
221
+ function inWords ( date ) {
222
+ return $t . inWords ( distance ( date ) ) ;
223
+ }
224
+
225
+ function distance ( date ) {
226
+ return ( new Date ( ) . getTime ( ) - date . getTime ( ) ) ;
227
+ }
228
+
229
+ // fix for IE6 suckage
230
+ document . createElement ( "abbr" ) ;
231
+ document . createElement ( "time" ) ;
232
+ } ) ) ;
0 commit comments