1 | /* |
---|
2 | * timeago: a jQuery plugin, version: 0.9.3 (2011-01-21) |
---|
3 | * @requires jQuery v1.2.3 or later |
---|
4 | * |
---|
5 | * Timeago is a jQuery plugin that makes it easy to support automatically |
---|
6 | * updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago"). |
---|
7 | * |
---|
8 | * For usage and examples, visit: |
---|
9 | * http://timeago.yarp.com/ |
---|
10 | * |
---|
11 | * Licensed under the MIT: |
---|
12 | * http://www.opensource.org/licenses/mit-license.php |
---|
13 | * |
---|
14 | * Copyright (c) 2008-2011, Ryan McGeary (ryanonjavascript -[at]- mcgeary [*dot*] org) |
---|
15 | */ |
---|
16 | |
---|
17 | (function($) { |
---|
18 | $.timeago = function(timestamp) { |
---|
19 | if (timestamp instanceof Date) { |
---|
20 | return inWords(timestamp); |
---|
21 | } else if (typeof timestamp === "string") { |
---|
22 | return inWords($.timeago.parse(timestamp)); |
---|
23 | } else { |
---|
24 | return inWords($.timeago.datetime(timestamp)); |
---|
25 | } |
---|
26 | }; |
---|
27 | var $t = $.timeago; |
---|
28 | |
---|
29 | $.extend($.timeago, { |
---|
30 | settings: { |
---|
31 | refreshMillis: 60000, |
---|
32 | allowFuture: false, |
---|
33 | strings: { |
---|
34 | prefixAgo: null, |
---|
35 | prefixFromNow: null, |
---|
36 | suffixAgo: "ago", |
---|
37 | suffixFromNow: "from now", |
---|
38 | seconds: "less than a minute", |
---|
39 | minute: "about a minute", |
---|
40 | minutes: "%d minutes", |
---|
41 | hour: "about an hour", |
---|
42 | hours: "about %d hours", |
---|
43 | day: "a day", |
---|
44 | days: "%d days", |
---|
45 | month: "about a month", |
---|
46 | months: "%d months", |
---|
47 | year: "about a year", |
---|
48 | years: "%d years", |
---|
49 | numbers: [] |
---|
50 | } |
---|
51 | }, |
---|
52 | inWords: function(distanceMillis) { |
---|
53 | var $l = this.settings.strings; |
---|
54 | var prefix = $l.prefixAgo; |
---|
55 | var suffix = $l.suffixAgo; |
---|
56 | if (this.settings.allowFuture) { |
---|
57 | if (distanceMillis < 0) { |
---|
58 | prefix = $l.prefixFromNow; |
---|
59 | suffix = $l.suffixFromNow; |
---|
60 | } |
---|
61 | distanceMillis = Math.abs(distanceMillis); |
---|
62 | } |
---|
63 | |
---|
64 | var seconds = distanceMillis / 1000; |
---|
65 | var minutes = seconds / 60; |
---|
66 | var hours = minutes / 60; |
---|
67 | var days = hours / 24; |
---|
68 | var years = days / 365; |
---|
69 | |
---|
70 | function substitute(stringOrFunction, number) { |
---|
71 | var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction; |
---|
72 | var value = ($l.numbers && $l.numbers[number]) || number; |
---|
73 | return string.replace(/%d/i, value); |
---|
74 | } |
---|
75 | |
---|
76 | var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) || |
---|
77 | seconds < 90 && substitute($l.minute, 1) || |
---|
78 | minutes < 45 && substitute($l.minutes, Math.round(minutes)) || |
---|
79 | minutes < 90 && substitute($l.hour, 1) || |
---|
80 | hours < 24 && substitute($l.hours, Math.round(hours)) || |
---|
81 | hours < 48 && substitute($l.day, 1) || |
---|
82 | days < 30 && substitute($l.days, Math.floor(days)) || |
---|
83 | days < 60 && substitute($l.month, 1) || |
---|
84 | days < 365 && substitute($l.months, Math.floor(days / 30)) || |
---|
85 | years < 2 && substitute($l.year, 1) || |
---|
86 | substitute($l.years, Math.floor(years)); |
---|
87 | |
---|
88 | return $.trim([prefix, words, suffix].join(" ")); |
---|
89 | }, |
---|
90 | parse: function(iso8601) { |
---|
91 | var s = $.trim(iso8601); |
---|
92 | s = s.replace(/\.\d\d\d+/,""); // remove milliseconds |
---|
93 | s = s.replace(/-/g,"/"); |
---|
94 | s = s.replace(/(\d)T(\d)/,"$1 $2").replace(/(\d)Z/,"$1 UTC"); |
---|
95 | s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400 |
---|
96 | return new Date(s); |
---|
97 | }, |
---|
98 | datetime: function(elem) { |
---|
99 | // jQuery's `is()` doesn't play well with HTML5 in IE |
---|
100 | var isTime = $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time"); |
---|
101 | |
---|
102 | var iso8601 = null; |
---|
103 | |
---|
104 | if( isTime ) |
---|
105 | { |
---|
106 | iso8601 = $(elem).attr("datetime"); |
---|
107 | } |
---|
108 | |
---|
109 | if( !iso8601 ) |
---|
110 | { |
---|
111 | iso8601 = $(elem).attr("title"); |
---|
112 | } |
---|
113 | |
---|
114 | if( !iso8601 ) |
---|
115 | { |
---|
116 | iso8601 = $(elem).text(); |
---|
117 | } |
---|
118 | |
---|
119 | return $t.parse(iso8601); |
---|
120 | } |
---|
121 | }); |
---|
122 | |
---|
123 | $.fn.timeago = function() { |
---|
124 | var self = this; |
---|
125 | self.each(refresh); |
---|
126 | |
---|
127 | var $s = $t.settings; |
---|
128 | if ($s.refreshMillis > 0) { |
---|
129 | setInterval(function() { self.each(refresh); }, $s.refreshMillis); |
---|
130 | } |
---|
131 | return self; |
---|
132 | }; |
---|
133 | |
---|
134 | function refresh() { |
---|
135 | var data = prepareData(this); |
---|
136 | if (!isNaN(data.datetime)) { |
---|
137 | $(this).text(inWords(data.datetime)); |
---|
138 | } |
---|
139 | return this; |
---|
140 | } |
---|
141 | |
---|
142 | function prepareData(element) { |
---|
143 | element = $(element); |
---|
144 | if (!element.data("timeago")) { |
---|
145 | element.data("timeago", { datetime: $t.datetime(element) }); |
---|
146 | var text = $.trim(element.text()); |
---|
147 | if (text.length > 0) { |
---|
148 | element.attr("title", text); |
---|
149 | } |
---|
150 | } |
---|
151 | return element.data("timeago"); |
---|
152 | } |
---|
153 | |
---|
154 | function inWords(date) { |
---|
155 | return $t.inWords(distance(date)); |
---|
156 | } |
---|
157 | |
---|
158 | function distance(date) { |
---|
159 | return (new Date().getTime() - date.getTime()); |
---|
160 | } |
---|
161 | |
---|
162 | // fix for IE6 suckage |
---|
163 | document.createElement("abbr"); |
---|
164 | document.createElement("time"); |
---|
165 | }(jQuery)); |
---|