source: Dev/branches/rest-dojo-ui/client/dojox/date/islamic/locale.js @ 256

Last change on this file since 256 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

File size: 12.7 KB
Line 
1define(["dojo/_base/kernel", "dojo/_base/lang", "dojo/_base/array", "dojo/date", "dojo/i18n", "dojo/regexp", "dojo/string", "./Date", "dojo/i18n!dojo/cldr/nls/islamic"],
2        function(dojo, dlang, darray, dd, i18n, regexp, string, islamicDate){
3
4        dojo.getObject("date.islamic.locale", true, dojox);
5        dojo.experimental("dojox.date.islamic.locale");
6
7        dojo.requireLocalization("dojo.cldr", "islamic");
8
9        // Format a pattern without literals
10        function formatPattern(dateObject, bundle, locale, fullYear,  pattern){
11
12                return pattern.replace(/([a-z])\1*/ig, function(match){
13                        var s, pad;
14                        var c = match.charAt(0);
15                        var l = match.length;
16                        var widthList = ["abbr", "wide", "narrow"];
17                       
18                        switch(c){
19                                case 'G':
20                                        s = bundle["eraAbbr"][0];
21                                        break;
22                                case 'y':
23                                        s = String(dateObject.getFullYear());
24                                        break;
25                                case 'M':
26                                        var m = dateObject.getMonth();
27                                        if(l<3){
28                                                s = m+1; pad = true;
29                                        }else{
30                                                var propM = ["months", "format", widthList[l-3]].join("-");
31                                                s = bundle[propM][m];
32                                        }
33                                        break;
34                                case 'd':
35                                        s = dateObject.getDate(true); pad = true;
36                                        break;
37                                case 'E':
38                                        var d = dateObject.getDay();
39                                        if(l<3){
40                                                s = d+1; pad = true;
41                                        }else{
42                                                var propD = ["days", "format", widthList[l-3]].join("-");
43                                                s = bundle[propD][d];
44                                        }
45                                        break;
46                                case 'a':
47                                        var timePeriod = (dateObject.getHours() < 12) ? 'am' : 'pm';
48                                        s = bundle['dayPeriods-format-wide-' + timePeriod];
49                                        break;
50                                case 'h':
51                                case 'H':
52                                case 'K':
53                                case 'k':
54                                        var h = dateObject.getHours();
55                                        switch (c){
56                                                case 'h': // 1-12
57                                                        s = (h % 12) || 12;
58                                                        break;
59                                                case 'H': // 0-23
60                                                        s = h;
61                                                        break;
62                                                case 'K': // 0-11
63                                                        s = (h % 12);
64                                                        break;
65                                                case 'k': // 1-24
66                                                        s = h || 24;
67                                                        break;
68                                        }
69                                        pad = true;
70                                        break;
71                                case 'm':
72                                        s = dateObject.getMinutes(); pad = true;
73                                        break;
74                                case 's':
75                                        s = dateObject.getSeconds(); pad = true;
76                                        break;
77                                case 'S':
78                                        s = Math.round(dateObject.getMilliseconds() * Math.pow(10, l-3)); pad = true;
79                                        break;
80                                case 'z':
81                                        // We only have one timezone to offer; the one from the browser
82                                        s = dd.getTimezoneName(dateObject.toGregorian());
83                                        if(s){ break; }
84                                        l = 4;
85                                        // fallthrough... use GMT if tz not available
86                                case 'Z':
87                                        var offset = dateObject.toGregorian().getTimezoneOffset();
88                                        var tz = [
89                                                (offset <= 0 ? "+" : "-"),
90                                                string.pad(Math.floor(Math.abs(offset) / 60), 2),
91                                                string.pad(Math.abs(offset) % 60, 2)
92                                        ];
93                                        if(l == 4){
94                                                tz.splice(0, 0, "GMT");
95                                                tz.splice(3, 0, ":");
96                                        }
97                                        s = tz.join("");
98                                        break;
99                                default:
100                                        throw new Error("dojox.date.islamic.locale.formatPattern: invalid pattern char: "+pattern);
101                        }
102                        if(pad){ s = string.pad(s, l); }
103                        return s;
104                });
105        }
106       
107        // based on and similar to dojo.date.locale.format
108        dojox.date.islamic.locale.format = function(/*islamic.Date*/dateObject, /*Object?*/options){
109                // summary:
110                //              Format a Date object as a String, using  settings.
111                options = options || {};
112
113                var locale = i18n.normalizeLocale(options.locale);
114                var formatLength = options.formatLength || 'short';
115                var bundle = dojox.date.islamic.locale._getIslamicBundle(locale);
116                var str = [];
117
118                var sauce = dojo.hitch(this, formatPattern, dateObject, bundle, locale, options.fullYear);
119                if(options.selector == "year"){
120                        var year = dateObject.getFullYear();
121                        return year;
122                }
123                if(options.selector != "time"){
124                        var datePattern = options.datePattern || bundle["dateFormat-"+formatLength];
125                        if(datePattern){str.push(_processPattern(datePattern, sauce));}
126                }
127                if(options.selector != "date"){
128                        var timePattern = options.timePattern || bundle["timeFormat-"+formatLength];
129                        if(timePattern){str.push(_processPattern(timePattern, sauce));}
130                }
131                var result = str.join(" "); //TODO: use locale-specific pattern to assemble date + time
132
133                return result; // String
134        };
135
136        dojox.date.islamic.locale.regexp = function(/*object?*/options){
137                //      based on and similar to dojo.date.locale.regexp
138                // summary:
139                //              Builds the regular needed to parse a islamic.Date
140                return dojox.date.islamic.locale._parseInfo(options).regexp; // String
141        };
142
143        dojox.date.islamic.locale._parseInfo = function(/*oblect?*/options){
144        /* based on and similar to dojo.date.locale._parseInfo */
145
146                options = options || {};
147                var locale = i18n.normalizeLocale(options.locale);
148                var bundle = dojox.date.islamic.locale._getIslamicBundle(locale);
149                var formatLength = options.formatLength || 'short';
150                var datePattern = options.datePattern || bundle["dateFormat-" + formatLength];
151                var timePattern = options.timePattern || bundle["timeFormat-" + formatLength];
152
153                var pattern;
154                if(options.selector == 'date'){
155                        pattern = datePattern;
156                }else if(options.selector == 'time'){
157                        pattern = timePattern;
158                }else{
159                        pattern = (typeof (timePattern) == "undefined") ? datePattern : datePattern + ' ' + timePattern;
160                }
161
162                var tokens = [];
163       
164                var re = _processPattern(pattern, dojo.hitch(this, _buildDateTimeRE, tokens, bundle, options));
165                return {regexp: re, tokens: tokens, bundle: bundle};
166        };
167
168        dojox.date.islamic.locale.parse = function(/*String*/value, /*Object?*/options){
169                // based on and similar to dojo.date.locale.parse
170                // summary: This function parse string date value according to options
171       
172                value =  value.replace(/[\u200E\u200F\u202A\u202E]/g, ""); //remove bidi non-printing chars
173
174                if(!options){ options={}; }
175                var info = dojox.date.islamic.locale._parseInfo(options);
176
177                var tokens = info.tokens, bundle = info.bundle;
178                var regexp = info.regexp.replace(/[\u200E\u200F\u202A\u202E]/g, ""); //remove bidi non-printing chars from the pattern
179                var re = new RegExp("^" + regexp + "$");
180
181                var match = re.exec(value);
182
183                var locale = i18n.normalizeLocale(options.locale);
184
185                if(!match){
186                        console.debug("dojox.date.islamic.locale.parse: value  "+value+" doesn't match pattern   " + re);
187                        return null;
188                } // null
189       
190                var date, date1;
191       
192                var result = [1389,0,1,0,0,0,0];  //FIXME: islamic date for [1970,0,1,0,0,0,0] used in gregorian locale
193                var amPm = "";
194                var mLength = 0;
195                var widthList = ["abbr", "wide", "narrow"];
196                var valid = dojo.every(match, function(v, i){
197                        if(!i){return true;}
198                        var token=tokens[i-1];
199                        var l=token.length;
200                        switch(token.charAt(0)){
201                                case 'y':
202                                        result[0] = Number(v);
203                                        break;
204                                case 'M':
205                                        if(l>2){
206                                                var months = bundle['months-format-' + widthList[l-3]].concat();
207                                                if(!options.strict){
208                                                        //Tolerate abbreviating period in month part
209                                                        //Case-insensitive comparison
210                                                        v = v.replace(".","").toLowerCase();
211                                                        months = dojo.map(months, function(s){ return s ? s.replace(".","").toLowerCase() : s; } );
212                                                }
213                                                v = dojo.indexOf(months, v);
214                                                if(v == -1){
215                                                        return false;
216                                                }
217                                                mLength = l;
218                                        }else{
219                                                v--;
220                                        }
221                                        result[1] = Number(v);
222                                        break;
223                                case 'D':
224                                        result[1] = 0;
225                                        // fallthrough...
226                                case 'd':
227                                                result[2] =  Number(v);
228                                        break;
229                                case 'a': //am/pm
230                                        var am = options.am || bundle['dayPeriods-format-wide-am'],
231                                                pm = options.pm || bundle['dayPeriods-format-wide-pm'];
232                                        if(!options.strict){
233                                                var period = /\./g;
234                                                v = v.replace(period,'').toLowerCase();
235                                                am = am.replace(period,'').toLowerCase();
236                                                pm = pm.replace(period,'').toLowerCase();
237                                        }
238                                        if(options.strict && v != am && v != pm){
239                                                return false;
240                                        }
241
242                                        // we might not have seen the hours field yet, so store the state and apply hour change later
243                                        amPm = (v == pm) ? 'p' : (v == am) ? 'a' : '';
244                                        break;
245                                case 'K': //hour (1-24)
246                                        if(v == 24){ v = 0; }
247                                        // fallthrough...
248                                case 'h': //hour (1-12)
249                                case 'H': //hour (0-23)
250                                case 'k': //hour (0-11)
251                                        //in the 12-hour case, adjusting for am/pm requires the 'a' part
252                                        //which could come before or after the hour, so we will adjust later
253                                        result[3] = Number(v);
254                                        break;
255                                case 'm': //minutes
256                                        result[4] = Number(v);
257                                        break;
258                                case 's': //seconds
259                                        result[5] = Number(v);
260                                        break;
261                                case 'S': //milliseconds
262                                        result[6] = Number(v);
263                        }
264                        return true;
265                });
266
267                var hours = +result[3];
268                if(amPm === 'p' && hours < 12){
269                        result[3] = hours + 12; //e.g., 3pm -> 15
270                }else if(amPm === 'a' && hours == 12){
271                        result[3] = 0; //12am -> 0
272                }
273                var dateObject = new islamicDate(result[0], result[1], result[2], result[3], result[4], result[5], result[6]);
274                return dateObject;
275        };
276
277        function _processPattern(pattern, applyPattern, applyLiteral, applyAll){
278                //summary: Process a pattern with literals in it
279
280                // Break up on single quotes, treat every other one as a literal, except '' which becomes '
281                var identity = function(x){return x;};
282                applyPattern = applyPattern || identity;
283                applyLiteral = applyLiteral || identity;
284                applyAll = applyAll || identity;
285
286                //split on single quotes (which escape literals in date format strings)
287                //but preserve escaped single quotes (e.g., o''clock)
288                var chunks = pattern.match(/(''|[^'])+/g);
289                var literal = pattern.charAt(0) == "'";
290
291                dojo.forEach(chunks, function(chunk, i){
292                        if(!chunk){
293                                chunks[i]='';
294                        }else{
295                                chunks[i]=(literal ? applyLiteral : applyPattern)(chunk);
296                                literal = !literal;
297                        }
298                });
299                return applyAll(chunks.join(''));
300        }
301
302        function _buildDateTimeRE  (tokens, bundle, options, pattern){
303                        // based on and similar to dojo.date.locale._buildDateTimeRE
304                        //
305       
306                pattern = regexp.escapeString(pattern);
307                var locale = i18n.normalizeLocale(options.locale);
308       
309                return pattern.replace(/([a-z])\1*/ig, function(match){
310
311                                // Build a simple regexp.  Avoid captures, which would ruin the tokens list
312                                var s;
313                                var c = match.charAt(0);
314                                var l = match.length;
315                                var p2 = '', p3 = '';
316                                if(options.strict){
317                                        if(l > 1){ p2 = '0' + '{'+(l-1)+'}'; }
318                                        if(l > 2){ p3 = '0' + '{'+(l-2)+'}'; }
319                                }else{
320                                        p2 = '0?'; p3 = '0{0,2}';
321                                }
322                                switch(c){
323                                        case 'y':
324                                                s = '\\d+';
325                                                break;
326                                        case 'M':
327                                                s = (l>2) ?  '\\S+ ?\\S+' : p2+'[1-9]|1[0-2]';
328                                                break;
329                                        case 'd':
330                                                s = '[12]\\d|'+p2+'[1-9]|3[01]';
331                                                break;
332                                        case 'E':
333                                                s = '\\S+';
334                                                break;
335                                        case 'h': //hour (1-12)
336                                                s = p2+'[1-9]|1[0-2]';
337                                                break;
338                                        case 'k': //hour (0-11)
339                                                s = p2+'\\d|1[01]';
340                                                break;
341                                        case 'H': //hour (0-23)
342                                                s = p2+'\\d|1\\d|2[0-3]';
343                                                break;
344                                        case 'K': //hour (1-24)
345                                                s = p2+'[1-9]|1\\d|2[0-4]';
346                                                break;
347                                        case 'm':
348                                        case 's':
349                                                s = p2+'\\d|[0-5]\\d';
350                                                break;
351                                        case 'S':
352                                                s = '\\d{'+l+'}';
353                                                break;
354                                        case 'a':
355                                                var am = options.am || bundle['dayPeriods-format-wide-am'],
356                                                        pm = options.pm || bundle['dayPeriods-format-wide-pm'];
357                                                if(options.strict){
358                                                        s = am + '|' + pm;
359                                                }else{
360                                                        s = am + '|' + pm;
361                                                        if(am != am.toLowerCase()){ s += '|' + am.toLowerCase(); }
362                                                        if(pm != pm.toLowerCase()){ s += '|' + pm.toLowerCase(); }
363                                                }
364                                                break;
365                                        default:
366                                                s = ".*";
367                                }
368                                if(tokens){ tokens.push(match); }
369                                return "(" + s + ")"; // add capture
370                        }).replace(/[\xa0 ]/g, "[\\s\\xa0]"); // normalize whitespace.  Need explicit handling of \xa0 for IE. */
371        }
372
373        var _customFormats = [];
374        dojox.date.islamic.locale.addCustomFormats = function(/*String*/packageName, /*String*/bundleName){
375                // summary:
376                //              Add a reference to a bundle containing localized custom formats to be
377                //              used by date/time formatting and parsing routines.
378                _customFormats.push({pkg:packageName,name:bundleName});
379        };
380
381        dojox.date.islamic.locale._getIslamicBundle = function(/*String*/locale){
382                var islamic = {};
383                dojo.forEach(_customFormats, function(desc){
384                        var bundle = i18n.getLocalization(desc.pkg, desc.name, locale);
385                        islamic = dojo.mixin(islamic, bundle);
386                }, this);
387                return islamic; /*Object*/
388        };
389
390        dojox.date.islamic.locale.addCustomFormats("dojo.cldr","islamic");
391
392        dojox.date.islamic.locale.getNames = function(/*String*/item, /*String*/type, /*String?*/context, /*String?*/locale, /*islamic Date Object?*/date){
393                // summary:
394                //              Used to get localized strings from dojo.cldr for day or month names.
395                var label;
396                var lookup = dojox.date.islamic.locale._getIslamicBundle(locale);
397                var props = [item, context, type];
398                if(context == 'standAlone'){
399                        var key = props.join('-');
400                        label = lookup[key];
401                        // Fall back to 'format' flavor of name
402                        if(label[0] == 1){ label = undefined; } // kludge, in the absence of real aliasing support in dojo.cldr
403                }
404                props[1] = 'format';
405       
406                // return by copy so changes won't be made accidentally to the in-memory model
407                return (label || lookup[props.join('-')]).concat(); /*Array*/
408        };
409
410
411        dojox.date.islamic.locale.weekDays = dojox.date.islamic.locale.getNames('days', 'wide', 'format');
412
413        dojox.date.islamic.locale.months = dojox.date.islamic.locale.getNames('months', 'wide', 'format');
414
415        return dojox.date.islamic.locale;
416});
Note: See TracBrowser for help on using the repository browser.