|
3 | 3 | * updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").
|
4 | 4 | *
|
5 | 5 | * @name timeago
|
6 |
| - * @version 1.1.0 |
| 6 | + * @version 1.5.4 |
7 | 7 | * @requires jQuery v1.2.3+
|
8 | 8 | * @author Ryan McGeary
|
9 | 9 | * @license MIT License - http://www.opensource.org/licenses/mit-license.php
|
10 | 10 | *
|
11 | 11 | * For usage and examples, visit:
|
12 | 12 | * http://timeago.yarp.com/
|
13 | 13 | *
|
14 |
| - * Copyright (c) 2008-2013, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org) |
| 14 | + * Copyright (c) 2008-2017, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org) |
15 | 15 | */
|
16 | 16 |
|
17 | 17 | (function (factory) {
|
18 | 18 | if (typeof define === 'function' && define.amd) {
|
19 | 19 | // AMD. Register as an anonymous module.
|
20 | 20 | define(['jquery'], factory);
|
| 21 | + } else if (typeof module === 'object' && typeof module.exports === 'object') { |
| 22 | + factory(require('jquery')); |
21 | 23 | } else {
|
22 | 24 | // Browser globals
|
23 | 25 | factory(jQuery);
|
|
39 | 41 | $.extend($.timeago, {
|
40 | 42 | settings: {
|
41 | 43 | refreshMillis: 60000,
|
| 44 | + allowPast: true, |
42 | 45 | allowFuture: false,
|
| 46 | + localeTitle: false, |
| 47 | + cutoff: 0, |
| 48 | + autoDispose: true, |
43 | 49 | strings: {
|
44 | 50 | prefixAgo: null,
|
45 | 51 | prefixFromNow: null,
|
46 | 52 | suffixAgo: "ago",
|
47 | 53 | suffixFromNow: "from now",
|
| 54 | + inPast: 'any moment now', |
48 | 55 | seconds: "less than a minute",
|
49 | 56 | minute: "about a minute",
|
50 | 57 | minutes: "%d minutes",
|
|
60 | 67 | numbers: []
|
61 | 68 | }
|
62 | 69 | },
|
| 70 | + |
63 | 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 | + |
64 | 76 | var $l = this.settings.strings;
|
65 | 77 | var prefix = $l.prefixAgo;
|
66 | 78 | var suffix = $l.suffixAgo;
|
|
71 | 83 | }
|
72 | 84 | }
|
73 | 85 |
|
| 86 | + if (!this.settings.allowPast && distanceMillis >= 0) { |
| 87 | + return this.settings.strings.inPast; |
| 88 | + } |
| 89 | + |
74 | 90 | var seconds = Math.abs(distanceMillis) / 1000;
|
75 | 91 | var minutes = seconds / 60;
|
76 | 92 | var hours = minutes / 60;
|
|
99 | 115 | if ($l.wordSeparator === undefined) { separator = " "; }
|
100 | 116 | return $.trim([prefix, words, suffix].join(separator));
|
101 | 117 | },
|
| 118 | + |
102 | 119 | parse: function(iso8601) {
|
103 | 120 | var s = $.trim(iso8601);
|
104 | 121 | s = s.replace(/\.\d+/,""); // remove milliseconds
|
105 | 122 | s = s.replace(/-/,"/").replace(/-/,"/");
|
106 | 123 | s = s.replace(/T/," ").replace(/Z/," UTC");
|
107 | 124 | s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400
|
| 125 | + s = s.replace(/([\+\-]\d\d)$/," $100"); // +09 -> +0900 |
108 | 126 | return new Date(s);
|
109 | 127 | },
|
110 | 128 | datetime: function(elem) {
|
|
121 | 139 | // init is default when no action is given
|
122 | 140 | // functions are called with context of a single element
|
123 | 141 | var functions = {
|
124 |
| - init: function(){ |
| 142 | + init: function() { |
| 143 | + functions.dispose.call(this); |
125 | 144 | var refresh_el = $.proxy(refresh, this);
|
126 | 145 | refresh_el();
|
127 | 146 | var $s = $t.settings;
|
128 | 147 | if ($s.refreshMillis > 0) {
|
129 |
| - setInterval(refresh_el, $s.refreshMillis); |
| 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()); |
130 | 156 | }
|
| 157 | + refresh.apply(this); |
131 | 158 | },
|
132 |
| - update: function(time){ |
133 |
| - $(this).data('timeago', { datetime: $t.parse(time) }); |
| 159 | + updateFromDOM: function() { |
| 160 | + $(this).data('timeago', { datetime: $t.parse( $t.isTime(this) ? $(this).attr("datetime") : $(this).attr("title") ) }); |
134 | 161 | refresh.apply(this);
|
| 162 | + }, |
| 163 | + dispose: function () { |
| 164 | + if (this._timeagoInterval) { |
| 165 | + window.clearInterval(this._timeagoInterval); |
| 166 | + this._timeagoInterval = null; |
| 167 | + } |
135 | 168 | }
|
136 | 169 | };
|
137 | 170 |
|
138 | 171 | $.fn.timeago = function(action, options) {
|
139 | 172 | var fn = action ? functions[action] : functions.init;
|
140 |
| - if(!fn){ |
| 173 | + if (!fn) { |
141 | 174 | throw new Error("Unknown function name '"+ action +"' for timeago");
|
142 | 175 | }
|
143 | 176 | // each over objects here and call the requested function
|
144 |
| - this.each(function(){ |
| 177 | + this.each(function() { |
145 | 178 | fn.call(this, options);
|
146 | 179 | });
|
147 | 180 | return this;
|
148 | 181 | };
|
149 | 182 |
|
150 | 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 | + |
151 | 193 | var data = prepareData(this);
|
| 194 | + |
152 | 195 | if (!isNaN(data.datetime)) {
|
153 |
| - $(this).text(inWords(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 | + } |
154 | 203 | }
|
155 | 204 | return this;
|
156 | 205 | }
|
|
160 | 209 | if (!element.data("timeago")) {
|
161 | 210 | element.data("timeago", { datetime: $t.datetime(element) });
|
162 | 211 | var text = $.trim(element.text());
|
163 |
| - if (text.length > 0 && !($t.isTime(element) && element.attr("title"))) { |
| 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"))) { |
164 | 215 | element.attr("title", text);
|
165 | 216 | }
|
166 | 217 | }
|
|
0 commit comments