2 Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
8 YUI.add('datatype-number-parse', function(Y) {
11 * Parse number submodule.
14 * @submodule datatype-number-parse
15 * @for DataType.Number
20 Y.mix(Y.namespace("DataType.Number"), {
22 * Converts data to type Number.
25 * @param data {String | Number | Boolean} Data to convert. The following
26 * values return as null: null, undefined, NaN, "".
27 * @return {Number} A number, or null.
29 parse: function(data) {
30 var number = (data === null) ? data : +data;
31 if(LANG.isNumber(number)) {
40 // Add Parsers shortcut
41 Y.namespace("Parsers").number = Y.DataType.Number.parse;
44 }, '3.3.0' ,{requires:['yui-base']});
45 YUI.add('datatype-number-format', function(Y) {
51 * @submodule datatype-number
55 * Format number submodule.
58 * @submodule datatype-number-format
62 * DataType.Number provides a set of utility functions to operate against Number objects.
64 * @class DataType.Number
69 Y.mix(Y.namespace("DataType.Number"), {
71 * Takes a Number and formats to string for display to user.
74 * @param data {Number} Number.
75 * @param config {Object} (Optional) Optional configuration values:
77 * <dt>prefix {String}</dd>
78 * <dd>String prepended before each number, like a currency designator "$"</dd>
79 * <dt>decimalPlaces {Number}</dd>
80 * <dd>Number of decimal places to round. Must be a number 0 to 20.</dd>
81 * <dt>decimalSeparator {String}</dd>
82 * <dd>Decimal separator</dd>
83 * <dt>thousandsSeparator {String}</dd>
84 * <dd>Thousands separator</dd>
85 * <dt>suffix {String}</dd>
86 * <dd>String appended after each number, like " items" (note the space)</dd>
88 * @return {String} Formatted number for display. Note, the following values
89 * return as "": null, undefined, NaN, "".
91 format: function(data, config) {
92 if(LANG.isNumber(data)) {
93 config = config || {};
95 var isNeg = (data < 0),
97 decPlaces = config.decimalPlaces,
98 decSep = config.decimalSeparator || ".",
99 thouSep = config.thousandsSeparator,
104 if(LANG.isNumber(decPlaces) && (decPlaces >= 0) && (decPlaces <= 20)) {
105 // Round to the correct decimal place
106 output = data.toFixed(decPlaces);
111 output = output.replace(".", decSep);
114 // Add the thousands separator
116 // Find the dot or where it would be
117 decIndex = output.lastIndexOf(decSep);
118 decIndex = (decIndex > -1) ? decIndex : output.length;
119 // Start with the dot and everything to the right
120 newOutput = output.substring(decIndex);
121 // Working left, every third time add a separator, every time add a digit
122 for (count = 0, i=decIndex; i>0; i--) {
123 if ((count%3 === 0) && (i !== decIndex) && (!isNeg || (i > 1))) {
124 newOutput = thouSep + newOutput;
126 newOutput = output.charAt(i-1) + newOutput;
133 output = (config.prefix) ? config.prefix + output : output;
136 output = (config.suffix) ? output + config.suffix : output;
140 // Not a Number, just return as string
142 return (LANG.isValue(data) && data.toString) ? data.toString() : "";
148 }, '3.3.0' ,{requires:['yui-base']});
151 YUI.add('datatype-number', function(Y){}, '3.3.0' ,{use:['datatype-number-parse', 'datatype-number-format']});
153 YUI.add('datatype-date-parse', function(Y) {
156 * Parse number submodule.
159 * @submodule datatype-date-parse
164 Y.mix(Y.namespace("DataType.Date"), {
166 * Converts data to type Date.
169 * @param data {String | Number} Data to convert. Values supported by the Date constructor are supported.
170 * @return {Date} A Date, or null.
172 parse: function(data) {
176 if(!(LANG.isDate(data))) {
177 date = new Date(data);
184 if(LANG.isDate(date) && (date != "Invalid Date") && !isNaN(date)) { // Workaround for bug 2527965
193 // Add Parsers shortcut
194 Y.namespace("Parsers").date = Y.DataType.Date.parse;
197 }, '3.3.0' ,{requires:['yui-base']});
198 YUI.add('datatype-date-format', function(Y) {
201 * The DataType Utility provides type-conversion and string-formatting
202 * convenience methods for various JavaScript object types.
211 * @submodule datatype-date
215 * Format date submodule implements strftime formatters for javascript based on the
216 * Open Group specification defined at
217 * http://www.opengroup.org/onlinepubs/007908799/xsh/strftime.html
218 * This implementation does not include modified conversion specifiers (i.e., Ex and Ox)
221 * @submodule datatype-date-format
225 * DataType.Date provides a set of utility functions to operate against Date objects.
227 * @class DataType.Date
232 * Pad a number with leading spaces, zeroes or something else
234 * @param x {Number} The number to be padded
235 * @param pad {String} The character to pad the number with
236 * @param r {Number} (optional) The base of the pad, eg, 10 implies to two digits, 100 implies to 3 digits.
239 var xPad=function (x, pad, r)
241 if(typeof r === "undefined")
245 pad = pad.toString();
246 for( ; parseInt(x, 10)<r && r>1; r/=10) {
254 a: function (d, l) { return l.a[d.getDay()]; },
255 A: function (d, l) { return l.A[d.getDay()]; },
256 b: function (d, l) { return l.b[d.getMonth()]; },
257 B: function (d, l) { return l.B[d.getMonth()]; },
258 C: function (d) { return xPad(parseInt(d.getFullYear()/100, 10), 0); },
261 g: function (d) { return xPad(parseInt(Dt.formats.G(d)%100, 10), 0); },
263 var y = d.getFullYear();
264 var V = parseInt(Dt.formats.V(d), 10);
265 var W = parseInt(Dt.formats.W(d), 10);
269 } else if(W===0 && V>=52) {
275 H: ["getHours", "0"],
276 I: function (d) { var I=d.getHours()%12; return xPad(I===0?12:I, 0); },
278 var gmd_1 = new Date("" + d.getFullYear() + "/1/1 GMT");
279 var gmdate = new Date("" + d.getFullYear() + "/" + (d.getMonth()+1) + "/" + d.getDate() + " GMT");
280 var ms = gmdate - gmd_1;
281 var doy = parseInt(ms/60000/60/24, 10)+1;
282 return xPad(doy, 0, 100);
284 k: ["getHours", " "],
285 l: function (d) { var I=d.getHours()%12; return xPad(I===0?12:I, " "); },
286 m: function (d) { return xPad(d.getMonth()+1, 0); },
287 M: ["getMinutes", "0"],
288 p: function (d, l) { return l.p[d.getHours() >= 12 ? 1 : 0 ]; },
289 P: function (d, l) { return l.P[d.getHours() >= 12 ? 1 : 0 ]; },
290 s: function (d, l) { return parseInt(d.getTime()/1000, 10); },
291 S: ["getSeconds", "0"],
292 u: function (d) { var dow = d.getDay(); return dow===0?7:dow; },
294 var doy = parseInt(Dt.formats.j(d), 10);
295 var rdow = 6-d.getDay();
296 var woy = parseInt((doy+rdow)/7, 10);
300 var woy = parseInt(Dt.formats.W(d), 10);
301 var dow1_1 = (new Date("" + d.getFullYear() + "/1/1")).getDay();
302 // First week is 01 and not 00 as in the case of %U and %W,
303 // so we add 1 to the final result except if day 1 of the year
304 // is a Monday (then %W returns 01).
305 // We also need to subtract 1 if the day 1 of the year is
306 // Friday-Sunday, so the resulting equation becomes:
307 var idow = woy + (dow1_1 > 4 || dow1_1 <= 1 ? 0 : 1);
308 if(idow === 53 && (new Date("" + d.getFullYear() + "/12/31")).getDay() < 4)
314 idow = Dt.formats.V(new Date("" + (d.getFullYear()-1) + "/12/31"));
317 return xPad(idow, 0);
321 var doy = parseInt(Dt.formats.j(d), 10);
322 var rdow = 7-Dt.formats.u(d);
323 var woy = parseInt((doy+rdow)/7, 10);
324 return xPad(woy, 0, 10);
326 y: function (d) { return xPad(d.getFullYear()%100, 0); },
329 var o = d.getTimezoneOffset();
330 var H = xPad(parseInt(Math.abs(o/60), 10), 0);
331 var M = xPad(Math.abs(o%60), 0);
332 return (o>0?"-":"+") + H + M;
335 var tz = d.toString().replace(/^.*:\d\d( GMT[+-]\d+)? \(?([A-Za-z ]+)\)?\d*$/, "$2").replace(/[a-z ]/g, "");
337 tz = Dt.formats.z(d);
341 "%": function (d) { return "%"; }
356 //"+": "%a %b %e %T %Z %Y"
360 * Takes a native JavaScript Date and formats it as a string for display to user.
364 * @param oDate {Date} Date.
365 * @param oConfig {Object} (Optional) Object literal of configuration values:
367 * <dt>format {String} (Optional)</dt>
370 * Any strftime string is supported, such as "%I:%M:%S %p". strftime has several format specifiers defined by the Open group at
371 * <a href="http://www.opengroup.org/onlinepubs/007908799/xsh/strftime.html">http://www.opengroup.org/onlinepubs/007908799/xsh/strftime.html</a>
372 * PHP added a few of its own, defined at <a href="http://www.php.net/strftime">http://www.php.net/strftime</a>
375 * This javascript implementation supports all the PHP specifiers and a few more. The full list is below.
378 * If not specified, it defaults to the ISO 8601 standard date format: %Y-%m-%d.
379 * This may be overridden by the deprecated Y.config.dateFormat property.
382 * <dt>%a</dt> <dd>abbreviated weekday name according to the current locale</dd>
383 * <dt>%A</dt> <dd>full weekday name according to the current locale</dd>
384 * <dt>%b</dt> <dd>abbreviated month name according to the current locale</dd>
385 * <dt>%B</dt> <dd>full month name according to the current locale</dd>
386 * <dt>%c</dt> <dd>preferred date and time representation for the current locale</dd>
387 * <dt>%C</dt> <dd>century number (the year divided by 100 and truncated to an integer, range 00 to 99)</dd>
388 * <dt>%d</dt> <dd>day of the month as a decimal number (range 01 to 31)</dd>
389 * <dt>%D</dt> <dd>same as %m/%d/%y</dd>
390 * <dt>%e</dt> <dd>day of the month as a decimal number, a single digit is preceded by a space (range " 1" to "31")</dd>
391 * <dt>%F</dt> <dd>same as %Y-%m-%d (ISO 8601 date format)</dd>
392 * <dt>%g</dt> <dd>like %G, but without the century</dd>
393 * <dt>%G</dt> <dd>The 4-digit year corresponding to the ISO week number</dd>
394 * <dt>%h</dt> <dd>same as %b</dd>
395 * <dt>%H</dt> <dd>hour as a decimal number using a 24-hour clock (range 00 to 23)</dd>
396 * <dt>%I</dt> <dd>hour as a decimal number using a 12-hour clock (range 01 to 12)</dd>
397 * <dt>%j</dt> <dd>day of the year as a decimal number (range 001 to 366)</dd>
398 * <dt>%k</dt> <dd>hour as a decimal number using a 24-hour clock (range 0 to 23); single digits are preceded by a blank. (See also %H.)</dd>
399 * <dt>%l</dt> <dd>hour as a decimal number using a 12-hour clock (range 1 to 12); single digits are preceded by a blank. (See also %I.) </dd>
400 * <dt>%m</dt> <dd>month as a decimal number (range 01 to 12)</dd>
401 * <dt>%M</dt> <dd>minute as a decimal number</dd>
402 * <dt>%n</dt> <dd>newline character</dd>
403 * <dt>%p</dt> <dd>either "AM" or "PM" according to the given time value, or the corresponding strings for the current locale</dd>
404 * <dt>%P</dt> <dd>like %p, but lower case</dd>
405 * <dt>%r</dt> <dd>time in a.m. and p.m. notation equal to %I:%M:%S %p</dd>
406 * <dt>%R</dt> <dd>time in 24 hour notation equal to %H:%M</dd>
407 * <dt>%s</dt> <dd>number of seconds since the Epoch, ie, since 1970-01-01 00:00:00 UTC</dd>
408 * <dt>%S</dt> <dd>second as a decimal number</dd>
409 * <dt>%t</dt> <dd>tab character</dd>
410 * <dt>%T</dt> <dd>current time, equal to %H:%M:%S</dd>
411 * <dt>%u</dt> <dd>weekday as a decimal number [1,7], with 1 representing Monday</dd>
412 * <dt>%U</dt> <dd>week number of the current year as a decimal number, starting with the
413 * first Sunday as the first day of the first week</dd>
414 * <dt>%V</dt> <dd>The ISO 8601:1988 week number of the current year as a decimal number,
415 * range 01 to 53, where week 1 is the first week that has at least 4 days
416 * in the current year, and with Monday as the first day of the week.</dd>
417 * <dt>%w</dt> <dd>day of the week as a decimal, Sunday being 0</dd>
418 * <dt>%W</dt> <dd>week number of the current year as a decimal number, starting with the
419 * first Monday as the first day of the first week</dd>
420 * <dt>%x</dt> <dd>preferred date representation for the current locale without the time</dd>
421 * <dt>%X</dt> <dd>preferred time representation for the current locale without the date</dd>
422 * <dt>%y</dt> <dd>year as a decimal number without a century (range 00 to 99)</dd>
423 * <dt>%Y</dt> <dd>year as a decimal number including the century</dd>
424 * <dt>%z</dt> <dd>numerical time zone representation</dd>
425 * <dt>%Z</dt> <dd>time zone name or abbreviation</dd>
426 * <dt>%%</dt> <dd>a literal "%" character</dd>
429 * <dt>locale {String} (Deprecated, optional)</dt>
431 * <b>Deprecated - use Y.config.lang instead, which provides access to a much larger set of built-in languages.</b>
432 * The locale to use when displaying days of week, months of the year, and other locale specific
433 * strings. If not specified, this defaults to "en" (though this may be overridden by the deprecated Y.config.locale).
434 * The following locales are built in:
439 * <dd>US English</dd>
441 * <dd>British English</dd>
443 * <dd>Australian English (identical to British English)</dd>
445 * More locales may be added by subclassing of the deprecated Y.DataType.Date.Locale["en"].
446 * See Y.DataType.Date.Locale for more information.
449 * @return {String} Formatted date for display.
451 format : function (oDate, oConfig) {
452 oConfig = oConfig || {};
454 if(!Y.Lang.isDate(oDate)) {
455 return Y.Lang.isValue(oDate) ? oDate : "";
458 var format, resources, compatMode, sLocale, LOCALE;
460 // Y.config.dateFormat is deprecated - remove from YUI 3.2
461 format = oConfig.format || Y.config.dateFormat || "%Y-%m-%d";
462 // compatMode supports deprecated features - remove from YUI 3.2
463 compatMode = Y.Lang.isUndefined(Y.config.lang) && (Y.Lang.isValue(oConfig.locale) || Y.Lang.isValue(Y.config.locale));
465 sLocale = oConfig.locale || Y.config.locale;
466 LOCALE = Y.DataType.Date.Locale;
467 sLocale = sLocale.replace(/_/g, "-");
469 // Make sure we have a definition for the requested locale, or default to en.
470 if(!LOCALE[sLocale]) {
471 var tmpLocale = sLocale.replace(/-[a-zA-Z]+$/, "");
472 if(tmpLocale in LOCALE) {
474 } else if(Y.config.locale in LOCALE) {
475 sLocale = Y.config.locale;
481 resources = LOCALE[sLocale];
483 resources = Y.Intl.get('datatype-date-format');
486 var replace_aggs = function (m0, m1) {
487 if (compatMode && m1 === "r") {
488 return resources[m1];
490 var f = Dt.aggregates[m1];
491 return (f === "locale" ? resources[m1] : f);
494 var replace_formats = function (m0, m1) {
495 var f = Dt.formats[m1];
496 switch(Y.Lang.type(f)) {
497 case "string": // string => built in date function
499 case "function": // function => our own function
500 return f.call(oDate, oDate, resources);
501 case "array": // built in function with padding
502 if(Y.Lang.type(f[0]) === "string") {
503 return xPad(oDate[f[0]](), f[1]);
504 } // no break; (fall through to default:)
506 // Y.config.dateFormat is deprecated - remove from YUI 3.2
511 // First replace aggregates (run in a loop because an agg may be made up of other aggs)
512 while(format.match(/%[cDFhnrRtTxX]/)) {
513 format = format.replace(/%([cDFhnrRtTxX])/g, replace_aggs);
516 // Now replace formats (do not run in a loop otherwise %%a will be replace with the value of %a)
517 var str = format.replace(/%([aAbBCdegGHIjklmMpPsSuUVwWyYzZ%])/g, replace_formats);
519 replace_aggs = replace_formats = undefined;
525 Y.mix(Y.namespace("DataType.Date"), Dt);
531 * The Date.Locale class is a container for all localised date strings
532 * used by Y.DataType.Date. It is used internally, but may be extended
533 * to provide new date localisations.
535 * To create your own Locale, follow these steps:
537 * <li>Find an existing locale that matches closely with your needs</li>
538 * <li>Use this as your base class. Use Y.DataType.Date.Locale["en"] if nothing
540 * <li>Create your own class as an extension of the base class using
541 * Y.merge, and add your own localisations where needed.</li>
543 * See the Y.DataType.Date.Locale["en-US"] and Y.DataType.Date.Locale["en-GB"]
544 * classes which extend Y.DataType.Date.Locale["en"].
546 * For example, to implement locales for French french and Canadian french,
547 * we would do the following:
549 * <li>For French french, we have no existing similar locale, so use
550 * Y.DataType.Date.Locale["en"] as the base, and extend it:
552 * Y.DataType.Date.Locale["fr"] = Y.merge(Y.DataType.Date.Locale, {
553 * a: ["dim", "lun", "mar", "mer", "jeu", "ven", "sam"],
554 * A: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"],
555 * b: ["jan", "fév", "mar", "avr", "mai", "jun", "jui", "aoû", "sep", "oct", "nov", "déc"],
556 * B: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre"],
557 * c: "%a %d %b %Y %T %Z",
565 * <li>For Canadian french, we start with French french and change the meaning of \%x:
567 * Y.DataType.Date.Locale["fr-CA"] = Y.merge(Y.DataType.Date.Locale["fr"], {
574 * With that, you can use your new locales:
576 * var d = new Date("2008/04/22");
577 * Y.DataType.Date.format(d, { format: "%A, %d %B == %x", locale: "fr" });
581 * mardi, 22 avril == 22.04.2008
585 * Y.DataType.Date.format(d, {format: "%A, %d %B == %x", locale: "fr-CA" });
589 * mardi, 22 avril == 2008-04-22
592 * @class DataType.Date.Locale
594 * @deprecated - use Y.config.lang to request one of many built-in languages instead.
597 a: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
598 A: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
599 b: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
600 B: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
601 c: "%a %d %b %Y %T %Z",
609 Y.namespace("DataType.Date.Locale");
611 Y.DataType.Date.Locale["en"] = YDateEn;
613 Y.DataType.Date.Locale["en-US"] = Y.merge(YDateEn, {
614 c: "%a %d %b %Y %I:%M:%S %p %Z",
619 Y.DataType.Date.Locale["en-GB"] = Y.merge(YDateEn, {
622 Y.DataType.Date.Locale["en-AU"] = Y.merge(YDateEn);
627 }, '3.3.0' ,{requires:['yui-base'], lang:['ar','ar-JO','ca','ca-ES','da','da-DK','de','de-AT','de-DE','el','el-GR','en','en-AU','en-CA','en-GB','en-IE','en-IN','en-JO','en-MY','en-NZ','en-PH','en-SG','en-US','es','es-AR','es-BO','es-CL','es-CO','es-EC','es-ES','es-MX','es-PE','es-PY','es-US','es-UY','es-VE','fi','fi-FI','fr','fr-BE','fr-CA','fr-FR','hi','hi-IN','id','id-ID','it','it-IT','ja','ja-JP','ko','ko-KR','ms','ms-MY','nb','nb-NO','nl','nl-BE','nl-NL','pl','pl-PL','pt','pt-BR','ro','ro-RO','ru','ru-RU','sv','sv-SE','th','th-TH','tr','tr-TR','vi','vi-VN','zh-Hans','zh-Hans-CN','zh-Hant','zh-Hant-HK','zh-Hant-TW']});
630 YUI.add('datatype-date', function(Y){}, '3.3.0' ,{use:['datatype-date-parse', 'datatype-date-format']});
632 YUI.add('datatype-xml-parse', function(Y) {
635 * Parse XML submodule.
638 * @submodule datatype-xml-parse
644 Y.mix(Y.namespace("DataType.XML"), {
646 * Converts data to type XMLDocument.
649 * @param data {String} Data to convert.
650 * @return {XMLDoc} XML Document.
652 parse: function(data) {
654 if(LANG.isString(data)) {
656 if(!LANG.isUndefined(ActiveXObject)) {
657 xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
658 xmlDoc.async = false;
659 xmlDoc.loadXML(data);
664 if(!LANG.isUndefined(DOMParser)) {
665 xmlDoc = new DOMParser().parseFromString(data, "text/xml");
673 if( (LANG.isNull(xmlDoc)) || (LANG.isNull(xmlDoc.documentElement)) || (xmlDoc.documentElement.nodeName === "parsererror") ) {
680 // Add Parsers shortcut
681 Y.namespace("Parsers").xml = Y.DataType.XML.parse;
685 }, '3.3.0' ,{requires:['yui-base']});
686 YUI.add('datatype-xml-format', function(Y) {
689 * Format XML submodule.
692 * @submodule datatype-xml-format
699 * @submodule datatype-xml
703 * DataType.XML provides a set of utility functions to operate against XML documents.
705 * @class DataType.XML
710 Y.mix(Y.namespace("DataType.XML"), {
712 * Converts data to type XMLDocument.
715 * @param data {XMLDoc} Data to convert.
716 * @return {String} String.
718 format: function(data) {
720 if(!LANG.isUndefined(XMLSerializer)) {
721 return (new XMLSerializer()).serializeToString(data);
725 if(data && data.xml) {
729 return (LANG.isValue(data) && data.toString) ? data.toString() : "";
737 }, '3.3.0' ,{requires:['yui-base']});
740 YUI.add('datatype-xml', function(Y){}, '3.3.0' ,{use:['datatype-xml-parse', 'datatype-xml-format']});
744 YUI.add('datatype', function(Y){}, '3.3.0' ,{use:['datatype-number', 'datatype-date', 'datatype-xml']});