1
+ /**
2
+ * Angular directive/filter/service for formatting date so that it displays how long ago the given time was compared to now.
3
+ * @version v0.2.0 - 2015-07-24
4
+ * @link https://github.com/yaru22/angular-timeago
5
+ * @author Brian Park <[email protected] >
6
+ * @license MIT License, http://www.opensource.org/licenses/MIT
7
+ */
8
+ /* global angular */
9
+ 'use strict' ;
10
+ angular . module ( 'yaru22.angular-timeago' , [ ] ) . directive ( 'timeAgo' , [
11
+ 'timeAgo' ,
12
+ 'nowTime' ,
13
+ function ( timeAgo , nowTime ) {
14
+ return {
15
+ scope : {
16
+ fromTime : '@' ,
17
+ format : '@'
18
+ } ,
19
+ restrict : 'EA' ,
20
+ link : function ( scope , elem ) {
21
+ var fromTime = timeAgo . parse ( scope . fromTime ) ;
22
+ // Track changes to time difference
23
+ scope . $watch ( function ( ) {
24
+ return nowTime ( ) - fromTime ;
25
+ } , function ( value ) {
26
+ angular . element ( elem ) . text ( timeAgo . inWords ( value , fromTime , scope . format ) ) ;
27
+ } ) ;
28
+ }
29
+ } ;
30
+ }
31
+ ] ) . factory ( 'nowTime' , [
32
+ '$window' ,
33
+ '$rootScope' ,
34
+ function ( $window , $rootScope ) {
35
+ var nowTime = Date . now ( ) ;
36
+ var updateTime = function ( ) {
37
+ $window . setTimeout ( function ( ) {
38
+ $rootScope . $apply ( function ( ) {
39
+ nowTime = Date . now ( ) ;
40
+ updateTime ( ) ;
41
+ } ) ;
42
+ } , 1000 ) ;
43
+ } ;
44
+ updateTime ( ) ;
45
+ return function ( ) {
46
+ return nowTime ;
47
+ } ;
48
+ }
49
+ ] ) . factory ( 'timeAgo' , [
50
+ '$filter' ,
51
+ function ( $filter ) {
52
+ var service = { } ;
53
+ service . settings = {
54
+ refreshMillis : 60000 ,
55
+ allowFuture : false ,
56
+ overrideLang : null ,
57
+ fullDateAfterSeconds : null ,
58
+ strings : {
59
+ 'it_IT' : {
60
+ prefixAgo : null ,
61
+ prefixFromNow : null ,
62
+ suffixAgo : 'fa' ,
63
+ suffixFromNow : 'da ora' ,
64
+ seconds : 'meno di un minuto' ,
65
+ minute : 'circa un minuto' ,
66
+ minutes : '%d minuti' ,
67
+ hour : 'circa un\' ora' ,
68
+ hours : 'circa %d ore' ,
69
+ day : 'un giorno' ,
70
+ days : '%d giorni' ,
71
+ month : 'circa un mese' ,
72
+ months : '%d mesi' ,
73
+ year : 'circa un anno' ,
74
+ years : '%d anni' ,
75
+ numbers : [ ]
76
+ } ,
77
+ 'en_US' : {
78
+ prefixAgo : null ,
79
+ prefixFromNow : null ,
80
+ suffixAgo : 'ago' ,
81
+ suffixFromNow : 'from now' ,
82
+ seconds : 'less than a minute' ,
83
+ minute : 'about a minute' ,
84
+ minutes : '%d minutes' ,
85
+ hour : 'about an hour' ,
86
+ hours : 'about %d hours' ,
87
+ day : 'a day' ,
88
+ days : '%d days' ,
89
+ month : 'about a month' ,
90
+ months : '%d months' ,
91
+ year : 'about a year' ,
92
+ years : '%d years' ,
93
+ numbers : [ ]
94
+ } ,
95
+ 'de_DE' : {
96
+ prefixAgo : 'vor' ,
97
+ prefixFromNow : null ,
98
+ suffixAgo : null ,
99
+ suffixFromNow : 'from now' ,
100
+ seconds : 'weniger als einer Minute' ,
101
+ minute : 'ca. einer Minute' ,
102
+ minutes : '%d Minuten' ,
103
+ hour : 'ca. einer Stunde' ,
104
+ hours : 'ca. %d Stunden' ,
105
+ day : 'einem Tag' ,
106
+ days : '%d Tagen' ,
107
+ month : 'ca. einem Monat' ,
108
+ months : '%d Monaten' ,
109
+ year : 'ca. einem Jahr' ,
110
+ years : '%d Jahren' ,
111
+ numbers : [ ]
112
+ } ,
113
+ 'he_IL' : {
114
+ prefixAgo : null ,
115
+ prefixFromNow : null ,
116
+ suffixAgo : '\u05dc\u05e4\u05e0\u05d9' ,
117
+ suffixFromNow : '\u05de\u05e2\u05db\u05e9\u05d9\u05d5' ,
118
+ seconds : '\u05e4\u05d7\u05d5\u05ea \u05de\u05d3\u05e7\u05d4' ,
119
+ minute : '\u05db\u05d3\u05e7\u05d4' ,
120
+ minutes : '%d \u05d3\u05e7\u05d5\u05ea' ,
121
+ hour : '\u05db\u05e9\u05e2\u05d4' ,
122
+ hours : '\u05db %d \u05e9\u05e2\u05d5\u05ea' ,
123
+ day : '\u05d9\u05d5\u05dd' ,
124
+ days : '%d \u05d9\u05de\u05d9\u05dd' ,
125
+ month : '\u05db\u05d7\u05d5\u05d3\u05e9' ,
126
+ months : '%d \u05d7\u05d5\u05d3\u05e9\u05d9\u05dd' ,
127
+ year : '\u05db\u05e9\u05e0\u05d4' ,
128
+ years : '%d \u05e9\u05e0\u05d9\u05dd' ,
129
+ numbers : [ ]
130
+ } ,
131
+ 'pt_BR' : {
132
+ prefixAgo : null ,
133
+ prefixFromNow : 'daqui a' ,
134
+ suffixAgo : 'atr\xe1s' ,
135
+ suffixFromNow : null ,
136
+ seconds : 'menos de um minuto' ,
137
+ minute : 'cerca de um minuto' ,
138
+ minutes : '%d minutos' ,
139
+ hour : 'cerca de uma hora' ,
140
+ hours : 'cerca de %d horas' ,
141
+ day : 'um dia' ,
142
+ days : '%d dias' ,
143
+ month : 'cerca de um m\xeas' ,
144
+ months : '%d meses' ,
145
+ year : 'cerca de um ano' ,
146
+ years : '%d anos' ,
147
+ numbers : [ ]
148
+ } ,
149
+ 'fr_FR' : {
150
+ prefixAgo : 'il y a' ,
151
+ prefixFromNow : null ,
152
+ suffixAgo : null ,
153
+ suffixFromNow : 'from now' ,
154
+ seconds : 'moins d\'une minute' ,
155
+ minute : 'environ une minute' ,
156
+ minutes : '%d minutes' ,
157
+ hour : 'environ une heure' ,
158
+ hours : 'environ %d heures' ,
159
+ day : 'un jour' ,
160
+ days : '%d jours' ,
161
+ month : 'environ un mois' ,
162
+ months : '%d mois' ,
163
+ year : 'environ un an' ,
164
+ years : '%d ans' ,
165
+ numbers : [ ]
166
+ } ,
167
+ 'es_LA' : {
168
+ prefixAgo : 'hace' ,
169
+ prefixFromNow : null ,
170
+ suffixAgo : null ,
171
+ suffixFromNow : 'apartir de ahora' ,
172
+ seconds : 'menos de un minuto' ,
173
+ minute : 'un minuto' ,
174
+ minutes : '%d minutos' ,
175
+ hour : 'una hora' ,
176
+ hours : '%d horas' ,
177
+ day : 'un dia' ,
178
+ days : '%d dias' ,
179
+ month : 'un mes' ,
180
+ months : '%d meses' ,
181
+ year : 'un a\xf1o' ,
182
+ years : '%d a\xf1os' ,
183
+ numbers : [ ]
184
+ } ,
185
+ 'nl_NL' : {
186
+ prefixAgo : null ,
187
+ prefixFromNow : 'over' ,
188
+ suffixAgo : 'geleden' ,
189
+ suffixFromNow : 'vanaf nu' ,
190
+ seconds : 'een paar seconden' ,
191
+ minute : 'ongeveer een minuut' ,
192
+ minutes : '%d minuten' ,
193
+ hour : 'een uur' ,
194
+ hours : '%d uur' ,
195
+ day : 'een dag' ,
196
+ days : '%d dagen' ,
197
+ month : 'een maand' ,
198
+ months : '%d maanden' ,
199
+ year : 'een jaar' ,
200
+ years : '%d jaar' ,
201
+ numbers : [ ]
202
+ }
203
+ }
204
+ } ;
205
+ service . inWords = function ( distanceMillis , fromTime , format , timezone ) {
206
+ var fullDateAfterSeconds = parseInt ( service . settings . fullDateAfterSeconds , 10 ) ;
207
+ if ( ! isNaN ( fullDateAfterSeconds ) && ( distanceMillis >= 0 && fullDateAfterSeconds * 1000 <= distanceMillis || fullDateAfterSeconds * 1000 >= distanceMillis ) ) {
208
+ if ( format ) {
209
+ return $filter ( 'date' ) ( fromTime , format , timezone ) ;
210
+ }
211
+ return fromTime ;
212
+ }
213
+ var overrideLang = service . settings . overrideLang ;
214
+ var documentLang = document . documentElement . lang ;
215
+ var sstrings = service . settings . strings ;
216
+ var lang , $l ;
217
+ if ( typeof sstrings [ overrideLang ] !== 'undefined' ) {
218
+ lang = overrideLang ;
219
+ $l = sstrings [ overrideLang ] ;
220
+ } else if ( typeof sstrings [ documentLang ] !== 'undefined' ) {
221
+ lang = documentLang ;
222
+ $l = sstrings [ documentLang ] ;
223
+ } else {
224
+ lang = 'en_US' ;
225
+ $l = sstrings [ lang ] ;
226
+ }
227
+ var prefix = $l . prefixAgo ;
228
+ var suffix = $l . suffixAgo ;
229
+ if ( service . settings . allowFuture ) {
230
+ if ( distanceMillis < 0 ) {
231
+ prefix = $l . prefixFromNow ;
232
+ suffix = $l . suffixFromNow ;
233
+ }
234
+ }
235
+ var seconds = Math . abs ( distanceMillis ) / 1000 ;
236
+ var minutes = seconds / 60 ;
237
+ var hours = minutes / 60 ;
238
+ var days = hours / 24 ;
239
+ var years = days / 365 ;
240
+ function substitute ( stringOrFunction , number ) {
241
+ var string = angular . isFunction ( stringOrFunction ) ? stringOrFunction ( number , distanceMillis ) : stringOrFunction ;
242
+ var value = $l . numbers && $l . numbers [ number ] || number ;
243
+ return string . replace ( / % d / i, value ) ;
244
+ }
245
+ var words = seconds < 45 && substitute ( $l . seconds , Math . round ( seconds ) ) || seconds < 90 && substitute ( $l . minute , 1 ) || minutes < 45 && substitute ( $l . minutes , Math . round ( minutes ) ) || minutes < 90 && substitute ( $l . hour , 1 ) || hours < 24 && substitute ( $l . hours , Math . round ( hours ) ) || hours < 42 && substitute ( $l . day , 1 ) || days < 30 && substitute ( $l . days , Math . round ( days ) ) || days < 45 && substitute ( $l . month , 1 ) || days < 365 && substitute ( $l . months , Math . round ( days / 30 ) ) || years < 1.5 && substitute ( $l . year , 1 ) || substitute ( $l . years , Math . round ( years ) ) ;
246
+ var separator = $l . wordSeparator === undefined ? ' ' : $l . wordSeparator ;
247
+ if ( lang === 'he_IL' ) {
248
+ return [
249
+ prefix ,
250
+ suffix ,
251
+ words
252
+ ] . join ( separator ) . trim ( ) ;
253
+ } else {
254
+ return [
255
+ prefix ,
256
+ words ,
257
+ suffix
258
+ ] . join ( separator ) . trim ( ) ;
259
+ }
260
+ } ;
261
+ service . parse = function ( input ) {
262
+ if ( input instanceof Date ) {
263
+ return input ;
264
+ } else if ( angular . isNumber ( input ) ) {
265
+ return new Date ( input ) ;
266
+ } else if ( / ^ \d + $ / . test ( input ) ) {
267
+ return new Date ( parseInt ( input , 10 ) ) ;
268
+ } else {
269
+ var s = ( input || '' ) . trim ( ) ;
270
+ s = s . replace ( / \. \d + / , '' ) ;
271
+ // remove milliseconds
272
+ s = s . replace ( / - / , '/' ) . replace ( / - / , '/' ) ;
273
+ s = s . replace ( / T / , ' ' ) . replace ( / Z / , ' UTC' ) ;
274
+ s = s . replace ( / ( [ \+ \- ] \d \d ) \: ? ( \d \d ) / , ' $1$2' ) ;
275
+ // -04:00 -> -0400
276
+ return new Date ( s ) ;
277
+ }
278
+ } ;
279
+ return service ;
280
+ }
281
+ ] ) . filter ( 'timeAgo' , [
282
+ 'nowTime' ,
283
+ 'timeAgo' ,
284
+ function ( nowTime , timeAgo ) {
285
+ return function ( value , format , timezone ) {
286
+ var fromTime = timeAgo . parse ( value ) ;
287
+ var diff = nowTime ( ) - fromTime ;
288
+ return timeAgo . inWords ( diff , fromTime , format , timezone ) ;
289
+ } ;
290
+ }
291
+ ] ) ;
0 commit comments