/[suikacvs]/test/suikawebwww/style/ui/time.js.u8
Suika

Contents of /test/suikawebwww/style/ui/time.js.u8

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.3 - (hide annotations) (download)
Sun Dec 21 08:18:29 2008 UTC (17 years, 8 months ago) by wakaba
Branch: MAIN
Changes since 1.2: +3 -3 lines
New; Typo in example

1 wakaba 1.1 function TER (c) {
2     this.container = c;
3     this._initialize ();
4     } // TER
5    
6     /* Based on HTML5 "global date and time string", but allows
7     Unicode 5.1.0 White_Space where it was allowed in earlier draft of HTML5. */
8     TER.globalDateAndTimeStringPattern = /^([0-9]{4,})-([0-9]{2})-([0-9]{2})(?:[\u0009-\u000D\u0020\u0085\u00A0\u1680\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]+(?:T[\u0009-\u000D\u0020\u0085\u00A0\u1680\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]*)?|T[\u0009-\u000D\u0020\u0085\u00A0\u1680\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]*)([0-9]{2}):([0-9]{2})(?::([0-9]{2})(?:\.([0-9]+))?)?[\u0009-\u000D\u0020\u0085\u00A0\u1680\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]*(?:Z|([+-])([0-9]{2}):([0-9]{2}))$/;
9    
10     /* HTML5 "date string" */
11     TER.dateStringPattern = /^([0-9]{4,})-([0-9]{2})-([0-9]{2})$/;
12    
13     /* HTML5 "time string" */
14     TER.timeStringPattern = /^([0-9]{2}):([0-9]{2})(?::([0-9]{2})(?:\.([0-9]+))?)?$/;
15    
16     TER.prototype._initialize = function () {
17     var els = this.container.getElementsByTagName ('time');
18     var elsL = els.length;
19     for (var i = 0; i < elsL; i++) {
20     var el = els[i];
21     if (!el) break; /* If <time> is nested */
22     this._replaceTimeContent (el);
23     }
24     }; // TER.prototype._initialize
25    
26     TER.prototype._replaceTimeContent = function (el) {
27     var date = this._getDate (el);
28     if (isNaN (date.valueOf ())) return;
29     if (date.hasTimezone) { /* full date */
30     if (!el.getAttribute ('title')) {
31     el.setAttribute ('title', el.textContent || this._getTextContent (el));
32     }
33 wakaba 1.2 if (!el.getAttribute ('datetime')) {
34     this._setDateTimeAttr (el, date);
35     }
36 wakaba 1.1 this._setDateTimeContent (el, date);
37     } else if (date.hasDate) {
38     if (!el.getAttribute ('title')) {
39     el.setAttribute ('title', el.textContent || this._getTextContent (el));
40     }
41 wakaba 1.2 if (!el.getAttribute ('datetime')) {
42     this._setDateAttr (el, date);
43     }
44 wakaba 1.1 this._setDateContent (el, date);
45     } else if (date.hasTime) {
46     if (!el.getAttribute ('title')) {
47     el.setAttribute ('title', el.textContent || this._getTextContent (el));
48     }
49 wakaba 1.2 if (!el.getAttribute ('datetime')) {
50     this._setTimeAttr (el, date);
51     }
52 wakaba 1.1 this._setTimeContent (el, date);
53     }
54     }; // TER.prototype._replaceTimeContent
55    
56     TER.prototype._setDateTimeContent = function (el, date) {
57     this._setTextContent (el, date.toLocaleString ());
58     }; // TER.prototype._setDateTimeContent
59    
60     TER.prototype._setDateContent = function (el, date) {
61     this._setTextContent (el, this._getLocal (date).toLocaleDateString ());
62     }; // TER.prototype._setDateContent
63    
64     TER.prototype._setTimeContent = function (el, date) {
65     this._setTextContent (el, this._getLocal (date).toLocaleTimeString ());
66     }; // TER.prototype._setTimeContent
67 wakaba 1.2
68     TER.prototype._setDateTimeAttr = function (el, date) {
69     var r = '';
70     r = date.getUTCFullYear (); // JS does not support years 0001-0999
71     r += '-' + ('0' + (date.getUTCMonth () + 1)).slice (-2);
72     r += '-' + ('0' + date.getUTCDate ()).slice (-2);
73     r += 'T' + ('0' + date.getUTCHours ()).slice (-2);
74     r += ':' + ('0' + date.getUTCMinutes ()).slice (-2);
75     r += ':' + ('0' + date.getUTCSeconds ()).slice (-2);
76     r += '.' + (date.getUTCMilliseconds () + '00').slice (2);
77     r += 'Z';
78     el.setAttribute ('datetime', r);
79     }; // TER.prototype._setDateTimeAttr
80    
81     TER.prototype._setDateAttr = function (el, date) {
82     var r = '';
83     r = date.getUTCFullYear (); // JS does not support years 0001-0999
84     r += '-' + ('0' + (date.getUTCMonth () + 1)).slice (-2);
85     r += '-' + ('0' + date.getUTCDate ()).slice (-2);
86     el.setAttribute ('datetime', r);
87     }; // TER.prototype._setDateAttr
88    
89     TER.prototype._setTimeAttr = function (el, date) {
90     var r = '';
91     r = ('0' + date.getUTCHours ()).slice (-2);
92     r += ':' + ('0' + date.getUTCMinutes ()).slice (-2);
93     r += ':' + ('0' + date.getUTCSeconds ()).slice (-2);
94     r += '.' + (date.getUTCMilliseconds () + '00').slice (2);
95     el.setAttribute ('datetime', r);
96     }; // TER.prototype._setTimeAttr
97 wakaba 1.1
98     TER.prototype._getLocal = function (d) {
99     /* Return a Date with same numbers of date/time, but in local timezone */
100     return new Date (d.getUTCFullYear (), d.getUTCMonth (), d.getUTCDate (),
101     d.getUTCHours (), d.getUTCMinutes (), d.getUTCSeconds (),
102     d.getUTCMilliseconds ());
103     }; // TER.prototype._getLocal
104    
105     TER.prototype._getDate = function (el) {
106     var datetime = el.getAttribute ('datetime');
107 wakaba 1.3 if (datetime) { /* NOTE: IE7 does not have hasAttribute */
108 wakaba 1.1 datetime = el.getAttribute ('datetime');
109     } else {
110     datetime = el.textContent || this._getTextContent (el);
111     datetime = this._trimWhiteSpace (datetime);
112     }
113    
114     if (m = datetime.match (TER.globalDateAndTimeStringPattern)) {
115     if (m[1] < 100) {
116     return new Date (NaN);
117     } else if (m[8] && (m[9] > 23 || m[9] < -23)) {
118     return new Date (NaN);
119     } else if (m[8] && m[10] > 59) {
120     return new Date (NaN);
121     }
122     var d = new Date (Date.UTC (m[1], m[2] - 1, m[3], m[4], m[5], m[6] || 0));
123     if (m[1] != d.getUTCFullYear () ||
124     m[2] != d.getUTCMonth () + 1 ||
125     m[3] != d.getUTCDate () ||
126     m[4] != d.getUTCHours () ||
127     m[5] != d.getUTCMinutes () ||
128     (m[6] || 0) != d.getUTCSeconds ()) {
129     return new Date (NaN); // bad date error.
130     }
131     if (m[7]) {
132     var ms = (m[7] + "000").substring (0, 3);
133     d.setMilliseconds (ms);
134     }
135     if (m[9] != null) {
136     var offset = parseInt (m[9], 10) * 60 + parseInt (m[10], 10);
137     offset *= 60 * 1000;
138     if (m[8] == '-') offset *= -1;
139     d = new Date (d.valueOf () - offset);
140     }
141     d.hasDate = true;
142     d.hasTime = true;
143     d.hasTimezone = true;
144     return d;
145     } else if (m = datetime.match (TER.dateStringPattern)) {
146     if (m[1] < 100) {
147     return new Date (NaN);
148     }
149     var d = new Date (Date.UTC (m[1], m[2] - 1, m[3], 0, 0, 0));
150     if (m[1] != d.getUTCFullYear () ||
151     m[2] != d.getUTCMonth () + 1 ||
152     m[3] != d.getUTCDate ()) {
153     return new Date (NaN); // bad date error.
154     }
155     d.hasDate = true;
156     return d;
157     } else if (m = datetime.match (TER.timeStringPattern)) {
158     var d = new Date (Date.UTC (1970, 1 - 1, 1, m[1], m[2], m[3] || 0));
159     if (m[1] != d.getUTCHours () ||
160     m[2] != d.getUTCMinutes () ||
161     (m[3] || 0) != d.getUTCSeconds ()) {
162     return new Date (NaN); // bad time error.
163     }
164     if (m[4]) {
165     var ms = (m[4] + "000").substring (0, 3);
166     d.setMilliseconds (ms);
167     }
168     d.hasTime = true;
169     return d;
170     } else {
171     return new Date (NaN);
172     }
173     }; // TER.prototype._getDate
174    
175     TER.prototype._getTextContent = function (el) {
176     var r = '';
177     var elC = el.childNodes;
178     var elCL = elC.length;
179     for (var i = 0; i < elCL; i++) {
180     var child = elC[i];
181     if (child.nodeType == 3 || child.nodeType == 4) {
182     r += child.data;
183     } else if (child.nodeType == 1) {
184     r += this._getTextContent (child);
185     }
186     }
187     return r;
188     }; // TER.prototype._getTextContent
189    
190     TER.prototype._setTextContent = function (el, s) {
191     el.innerText = s;
192     el.textContent = s;
193     }; // TER.prototype._setTextContent
194    
195     TER.prototype._trimWhiteSpace = function (s) {
196     /* Unicode 5.1.0 White_Space */
197     return s.replace
198     (/^[\u0009-\u000D\u0020\u0085\u00A0\u1680\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]+/, '')
199     .replace
200     (/[\u0009-\u000D\u0020\u0085\u00A0\u1680\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]+$/, '');
201     }; // TER.prototype._trimWhiteSpace
202    
203     TER.Delta = function (c) {
204     TER.apply (this, [c]);
205     }; // TER.Delta
206    
207     /* Don't delete createElement('time') - this is a hack to support IE */
208     TER.Delta.prototype = new TER (document.createElement ('time'));
209    
210     TER.Delta.prototype._setDateTimeContent = function (el, date) {
211     var dateValue = date.valueOf ();
212     var nowValue = new Date ().valueOf ();
213    
214     var diff = dateValue - nowValue;
215     if (diff < 0) diff = -diff;
216    
217     if (diff == 0) {
218     this._setTextContent (el, this.text.now ());
219     return;
220     }
221    
222     var v;
223     diff = Math.floor (diff / 1000);
224     if (diff < 60) {
225     v = this.text.second (diff);
226     } else {
227     var f = diff;
228     diff = Math.floor (diff / 60);
229     if (diff < 60) {
230     v = this.text.minute (diff);
231     f -= diff * 60;
232     if (f > 0) v += this.text.second (f);
233     } else {
234     f = diff;
235     diff = Math.floor (diff / 60);
236     if (diff < 50) {
237     v = this.text.hour (diff);
238     f -= diff * 60;
239     if (f > 0) v += this.text.minute (f);
240     } else {
241     f = diff;
242     diff = Math.floor (diff / 24);
243     if (diff < 100) {
244     v = this.text.day (diff);
245     f -= diff * 24;
246     if (f > 0) v += this.text.hour (f);
247     } else {
248     this._setTextContent (el, date.toLocaleString ());
249     return;
250     }
251     }
252     }
253     }
254    
255     if (dateValue < nowValue) {
256     v = this.text.before (v);
257     } else {
258     v = this.text.after (v);
259     }
260     this._setTextContent (el, v);
261     }; // TER.Delta.prototype._setDateTimeContent
262    
263     TER.Delta.Text = {};
264    
265     TER.Delta.Text.en = {
266     day: function (n) {
267     return n + ' day' + (n == 1 ? '' : 's');
268     },
269     hour: function (n) {
270     return n + ' hour' + (n == 1 ? '' : 's');
271     },
272     minute: function (n) {
273     return n + ' minute' + (n == 1 ? '' : 's');
274     },
275     second: function (n) {
276     return n + ' second' + (n == 1 ? '' : 's');
277     },
278     before: function (s) {
279     return s + ' ago';
280     },
281     after: function (s) {
282     return 'in ' + s;
283     }
284     };
285    
286     TER.Delta.Text.ja = {
287     day: function (n) {
288     return n + '日';
289     },
290     hour: function (n) {
291     return n + '時間';
292     },
293     minute: function (n) {
294     return n + '分';
295     },
296     second: function (n) {
297     return n + '秒';
298     },
299     before: function (s) {
300     return s + '前';
301     },
302     after: function (s) {
303     return s + '後';
304     }
305     };
306    
307     (function () {
308     var lang = navigator.browserLanguage || navigator.language || navigator.userLanguage || '';
309     if (lang.match (/^[jJ][aA](?:-|$)/)) {
310     TER.Delta.prototype.text = TER.Delta.Text.ja;
311     } else {
312     TER.Delta.prototype.text = TER.Delta.Text.en;
313     }
314     })();
315    
316     if (window.TEROnLoad) {
317     TEROnLoad ();
318     }
319    
320     /*
321    
322     Usage:
323    
324     <script>
325     window.onload = function () {
326 wakaba 1.3 new TER (document.body);
327 wakaba 1.1 };
328     </script>
329     <script src="http://suika.fam.cx/www/style/ui/time.js.u8" charset=utf-8></script>
330    
331     <time>2008-12-20T23:27+09:00</time>
332     <!-- Will be rendered appropriately in the user's locale -->
333    
334     ... or:
335    
336     <script>
337     window.onload = function () {
338 wakaba 1.3 new TER.Delta (document.body);
339 wakaba 1.1 };
340     </script>
341     <script src="http://suika.fam.cx/www/style/ui/time.js.u8" charset=utf-8></script>
342    
343     <time>2008-12-20T23:27+09:00</time>
344     <!-- Will be rendered like "2 minutes ago" in English or Japanese -->
345    
346     If you'd like to load this script AFTER |time| elements are parsed,
347     invoke |document.createElement ('time')| before they are used,
348     otherwise they cannot be parsed appropriately in WinIE.
349    
350     Latest version of this script is available at
351     <http://suika.fam.cx/www/style/ui/time.js.u8>. Old versions of this
352     script are available from
353     <http://suika.fam.cx/www/style/ui/time.js.u8,cvslog>.
354    
355     */
356    
357     /* ***** BEGIN LICENSE BLOCK *****
358     * Version: MPL 1.1/GPL 2.0/LGPL 2.1
359     *
360     * The contents of this file are subject to the Mozilla Public License Version
361     * 1.1 (the "License"); you may not use this file except in compliance with
362     * the License. You may obtain a copy of the License at
363     * <http://www.mozilla.org/MPL/>
364     *
365     * Software distributed under the License is distributed on an "AS IS" basis,
366     * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
367     * for the specific language governing rights and limitations under the
368     * License.
369     *
370     * The Original Code is TER code.
371     *
372     * The Initial Developer of the Original Code is
373     * Wakaba <[email protected]>.
374     * Portions created by the Initial Developer are Copyright (C) 2008
375     * the Initial Developer. All Rights Reserved.
376     *
377     * Contributor(s):
378     * Wakaba <[email protected]>
379     *
380     * Alternatively, the contents of this file may be used under the terms of
381     * either the GNU General Public License Version 2 or later (the "GPL"), or
382     * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
383     * in which case the provisions of the GPL or the LGPL are applicable instead
384     * of those above. If you wish to allow use of your version of this file only
385     * under the terms of either the GPL or the LGPL, and not to allow others to
386     * use your version of this file under the terms of the MPL, indicate your
387     * decision by deleting the provisions above and replace them with the notice
388     * and other provisions required by the GPL or the LGPL. If you do not delete
389     * the provisions above, a recipient may use your version of this file under
390     * the terms of any one of the MPL, the GPL or the LGPL.
391     *
392     * ***** END LICENSE BLOCK ***** */

[email protected]
ViewVC Help
Powered by ViewVC 1.1.24