]> git.proxmox.com Git - extjs.git/blame - extjs/packages/core/src/util/Format.js
add extjs 6.0.1 sources
[extjs.git] / extjs / packages / core / src / util / Format.js
CommitLineData
6527f429
DM
1/**\r
2 * @class Ext.util.Format\r
3 * \r
4 * This class is a centralized place for formatting functions. It includes\r
5 * functions to format various different types of data, such as text, dates and numeric values.\r
6 * \r
7 * ## Localization\r
8 *\r
9 * This class contains several options for localization. These can be set once the library has loaded,\r
10 * all calls to the functions from that point will use the locale settings that were specified.\r
11 *\r
12 * Options include:\r
13 *\r
14 * - thousandSeparator\r
15 * - decimalSeparator\r
16 * - currenyPrecision\r
17 * - currencySign\r
18 * - currencyAtEnd\r
19 *\r
20 * This class also uses the default date format defined here: {@link Ext.Date#defaultFormat}.\r
21 *\r
22 * ## Using with renderers\r
23 *\r
24 * There are two helper functions that return a new function that can be used in conjunction with\r
25 * grid renderers:\r
26 * \r
27 * columns: [{\r
28 * dataIndex: 'date',\r
29 * renderer: Ext.util.Format.dateRenderer('Y-m-d')\r
30 * }, {\r
31 * dataIndex: 'time',\r
32 * renderer: Ext.util.Format.numberRenderer('0.000')\r
33 * }]\r
34 * \r
35 * Functions that only take a single argument can also be passed directly:\r
36 *\r
37 * columns: [{\r
38 * dataIndex: 'cost',\r
39 * renderer: Ext.util.Format.usMoney\r
40 * }, {\r
41 * dataIndex: 'productCode',\r
42 * renderer: Ext.util.Format.uppercase\r
43 * }]\r
44 * \r
45 * ## Using with XTemplates\r
46 *\r
47 * XTemplates can also directly use Ext.util.Format functions:\r
48 * \r
49 * new Ext.XTemplate([\r
50 * 'Date: {startDate:date("Y-m-d")}',\r
51 * 'Cost: {cost:usMoney}'\r
52 * ]);\r
53 *\r
54 * @singleton\r
55 */\r
56Ext.define('Ext.util.Format', function () {\r
57 var me; // holds our singleton instance\r
58\r
59 return {\r
60 requires: [\r
61 'Ext.Error',\r
62 'Ext.Number',\r
63 'Ext.String',\r
64 'Ext.Date'\r
65 ],\r
66\r
67 singleton: true,\r
68\r
69 /**\r
70 * The global default date format.\r
71 */\r
72 defaultDateFormat: 'm/d/Y',\r
73\r
74 //<locale>\r
75 /**\r
76 * @property {String} thousandSeparator\r
77 * The character that the {@link #number} function uses as a thousand separator.\r
78 *\r
79 * This may be overridden in a locale file.\r
80 */\r
81 thousandSeparator: ',',\r
82 //</locale>\r
83\r
84 //<locale>\r
85 /**\r
86 * @property {String} decimalSeparator\r
87 * The character that the {@link #number} function uses as a decimal point.\r
88 *\r
89 * This may be overridden in a locale file.\r
90 */\r
91 decimalSeparator: '.',\r
92 //</locale>\r
93\r
94 //<locale>\r
95 /**\r
96 * @property {Number} currencyPrecision\r
97 * The number of decimal places that the {@link #currency} function displays.\r
98 *\r
99 * This may be overridden in a locale file.\r
100 */\r
101 currencyPrecision: 2,\r
102 //</locale>\r
103\r
104 //<locale>\r
105 /**\r
106 * @property {String} currencySign\r
107 * The currency sign that the {@link #currency} function displays.\r
108 *\r
109 * This may be overridden in a locale file.\r
110 */\r
111 currencySign: '$',\r
112 //</locale>\r
113\r
114 /**\r
115 * @property {String} percentSign\r
116 * The percent sign that the {@link #percent} function displays.\r
117 *\r
118 * This may be overridden in a locale file.\r
119 */\r
120 percentSign: '%',\r
121\r
122 //<locale>\r
123 /**\r
124 * @property {Boolean} currencyAtEnd\r
125 * This may be set to <code>true</code> to make the {@link #currency} function\r
126 * append the currency sign to the formatted value.\r
127 *\r
128 * This may be overridden in a locale file.\r
129 */\r
130 currencyAtEnd: false,\r
131 //</locale>\r
132\r
133 stripTagsRe: /<\/?[^>]+>/gi,\r
134 stripScriptsRe: /(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig,\r
135 nl2brRe: /\r?\n/g,\r
136 hashRe: /#+$/,\r
137 allHashes: /^#+$/,\r
138\r
139 // Match a format string characters to be able to detect remaining "literal" characters\r
140 formatPattern: /[\d,\.#]+/,\r
141\r
142 // A RegExp to remove from a number format string, all characters except digits and '.'\r
143 formatCleanRe: /[^\d\.#]/g,\r
144\r
145 // A RegExp to remove from a number format string, all characters except digits and the local decimal separator.\r
146 // Created on first use. The local decimal separator character must be initialized for this to be created.\r
147 I18NFormatCleanRe: null,\r
148\r
149 // Cache ofg number formatting functions keyed by format string\r
150 formatFns: {},\r
151\r
152 constructor: function () {\r
153 me = this; // we are a singleton, so cache our this pointer in scope\r
154 },\r
155\r
156 /**\r
157 * Checks a reference and converts it to empty string if it is undefined.\r
158 * @param {Object} value Reference to check\r
159 * @return {Object} Empty string if converted, otherwise the original value\r
160 */\r
161 undef : function(value) {\r
162 return value !== undefined ? value : "";\r
163 },\r
164\r
165 /**\r
166 * Checks a reference and converts it to the default value if it's empty.\r
167 * @param {Object} value Reference to check\r
168 * @param {String} [defaultValue=""] The value to insert of it's undefined.\r
169 * @return {String}\r
170 */\r
171 defaultValue : function(value, defaultValue) {\r
172 return value !== undefined && value !== '' ? value : defaultValue;\r
173 },\r
174\r
175 /**\r
176 * Returns a substring from within an original string.\r
177 * @param {String} value The original text\r
178 * @param {Number} start The start index of the substring\r
179 * @param {Number} length The length of the substring\r
180 * @return {String} The substring\r
181 * @method\r
182 */\r
183 substr : 'ab'.substr(-1) != 'b'\r
184 ? function (value, start, length) {\r
185 var str = String(value);\r
186 return (start < 0)\r
187 ? str.substr(Math.max(str.length + start, 0), length)\r
188 : str.substr(start, length);\r
189 }\r
190 : function(value, start, length) {\r
191 return String(value).substr(start, length);\r
192 },\r
193\r
194 /**\r
195 * Converts a string to all lower case letters.\r
196 * @param {String} value The text to convert\r
197 * @return {String} The converted text\r
198 */\r
199 lowercase : function(value) {\r
200 return String(value).toLowerCase();\r
201 },\r
202\r
203 /**\r
204 * Converts a string to all upper case letters.\r
205 * @param {String} value The text to convert\r
206 * @return {String} The converted text\r
207 */\r
208 uppercase : function(value) {\r
209 return String(value).toUpperCase();\r
210 },\r
211\r
212 /**\r
213 * Format a number as US currency.\r
214 * @param {Number/String} value The numeric value to format\r
215 * @return {String} The formatted currency string\r
216 */\r
217 usMoney : function(v) {\r
218 return me.currency(v, '$', 2);\r
219 },\r
220\r
221 /**\r
222 * Format a number as a currency.\r
223 * @param {Number/String} value The numeric value to format\r
224 * @param {String} [sign] The currency sign to use (defaults to {@link #currencySign})\r
225 * @param {Number} [decimals] The number of decimals to use for the currency\r
226 * (defaults to {@link #currencyPrecision})\r
227 * @param {Boolean} [end] True if the currency sign should be at the end of the string\r
228 * (defaults to {@link #currencyAtEnd})\r
229 * @return {String} The formatted currency string\r
230 */\r
231 currency: function(v, currencySign, decimals, end) {\r
232 var negativeSign = '',\r
233 format = ",0",\r
234 i = 0;\r
235 v = v - 0;\r
236 if (v < 0) {\r
237 v = -v;\r
238 negativeSign = '-';\r
239 }\r
240 decimals = Ext.isDefined(decimals) ? decimals : me.currencyPrecision;\r
241 format += (decimals > 0 ? '.' : '');\r
242 for (; i < decimals; i++) {\r
243 format += '0';\r
244 }\r
245 v = me.number(v, format);\r
246 if ((end || me.currencyAtEnd) === true) {\r
247 return Ext.String.format("{0}{1}{2}", negativeSign, v, currencySign || me.currencySign);\r
248 } else {\r
249 return Ext.String.format("{0}{1}{2}", negativeSign, currencySign || me.currencySign, v);\r
250 }\r
251 },\r
252\r
253 /**\r
254 * Formats the passed date using the specified format pattern.\r
255 * Note that this uses the native Javascript Date.parse() method and is therefore subject to its idiosyncrasies.\r
256 * Most formats assume the local timezone unless specified. One notable exception is 'YYYY-MM-DD' (note the dashes)\r
257 * which is typically interpreted in UTC and can cause date shifting.\r
258 * \r
259 * @param {String/Date} value The value to format. Strings must conform to the format\r
260 * expected by the JavaScript Date object's\r
261 * [parse() method](http://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/parse).\r
262 * @param {String} [format] Any valid date format string. Defaults to {@link Ext.Date#defaultFormat}.\r
263 * @return {String} The formatted date string.\r
264 */\r
265 date: function(v, format) {\r
266 if (!v) {\r
267 return "";\r
268 }\r
269 if (!Ext.isDate(v)) {\r
270 v = new Date(Date.parse(v));\r
271 }\r
272 return Ext.Date.dateFormat(v, format || Ext.Date.defaultFormat);\r
273 },\r
274\r
275 /**\r
276 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently.\r
277 * @param {String} format Any valid date format string. Defaults to {@link Ext.Date#defaultFormat}.\r
278 * @return {Function} The date formatting function\r
279 */\r
280 dateRenderer : function(format) {\r
281 return function(v) {\r
282 return me.date(v, format);\r
283 };\r
284 },\r
285\r
286 /**\r
287 * Returns the given number as a base 16 string at least `digits` in length. If\r
288 * the number is fewer digits, 0's are prepended as necessary. If `digits` is\r
289 * negative, the absolute value is the *exact* number of digits to return. In this\r
290 * case, if then number has more digits, only the least significant digits are\r
291 * returned.\r
292 *\r
293 * expect(Ext.util.Format.hex(0x12e4, 2)).toBe('12e4');\r
294 * expect(Ext.util.Format.hex(0x12e4, -2)).toBe('e4');\r
295 * expect(Ext.util.Format.hex(0x0e, 2)).toBe('0e');\r
296 *\r
297 * @param {Number} value The number to format in hex.\r
298 * @param {Number} digits\r
299 * @return {string}\r
300 */\r
301 hex: function (value, digits) {\r
302 var s = parseInt(value || 0, 10).toString(16);\r
303 if (digits) {\r
304 if (digits < 0) {\r
305 digits = -digits;\r
306 if (s.length > digits) {\r
307 s = s.substring(s.length - digits);\r
308 }\r
309 }\r
310 while (s.length < digits) {\r
311 s = '0' + s;\r
312 }\r
313 }\r
314 return s;\r
315 },\r
316\r
317 /**\r
318 * Returns this result:\r
319 *\r
320 * value || orValue\r
321 *\r
322 * The usefulness of this formatter method is in templates. For example:\r
323 *\r
324 * {foo:or("bar")}\r
325 *\r
326 * @param {Boolean} value The "if" value.\r
327 * @param {Mixed} orValue\r
328 */\r
329 or: function (value, orValue) {\r
330 return value || orValue;\r
331 },\r
332\r
333 /**\r
334 * If `value` is a number, returns the argument from that index. For example\r
335 *\r
336 * var s = Ext.util.Format.pick(2, 'zero', 'one', 'two');\r
337 * // s === 'two'\r
338 *\r
339 * Otherwise, `value` is treated in a truthy/falsey manner like so:\r
340 *\r
341 * var s = Ext.util.Format.pick(null, 'first', 'second');\r
342 * // s === 'first'\r
343 *\r
344 * s = Ext.util.Format.pick({}, 'first', 'second');\r
345 * // s === 'second'\r
346 *\r
347 * The usefulness of this formatter method is in templates. For example:\r
348 *\r
349 * {foo:pick("F","T")}\r
350 *\r
351 * {bar:pick("first","second","third")}\r
352 *\r
353 * @param {Boolean} value The "if" value.\r
354 * @param {Mixed} firstValue\r
355 * @param {Mixed} secondValue\r
356 */\r
357 pick: function (value, firstValue, secondValue) {\r
358 if (Ext.isNumber(value)) {\r
359 var ret = arguments[value + 1];\r
360 if (ret) {\r
361 return ret;\r
362 }\r
363 }\r
364 return value ? secondValue : firstValue;\r
365 },\r
366\r
367 /**\r
368 * Strips all HTML tags.\r
369 * @param {Object} value The text from which to strip tags\r
370 * @return {String} The stripped text\r
371 */\r
372 stripTags: function(v) {\r
373 return !v ? v : String(v).replace(me.stripTagsRe, "");\r
374 },\r
375\r
376 /**\r
377 * Strips all script tags.\r
378 * @param {Object} value The text from which to strip script tags\r
379 * @return {String} The stripped text\r
380 */\r
381 stripScripts : function(v) {\r
382 return !v ? v : String(v).replace(me.stripScriptsRe, "");\r
383 },\r
384\r
385 /**\r
386 * @method\r
387 * Simple format for a file size (xxx bytes, xxx KB, xxx MB).\r
388 * @param {Number/String} size The numeric value to format\r
389 * @return {String} The formatted file size\r
390 */\r
391 fileSize : (function(){\r
392 var byteLimit = 1024,\r
393 kbLimit = 1048576,\r
394 mbLimit = 1073741824;\r
395 \r
396 return function(size) {\r
397 var out;\r
398 if (size < byteLimit) {\r
399 if (size === 1) {\r
400 out = '1 byte'; \r
401 } else {\r
402 out = size + ' bytes';\r
403 }\r
404 } else if (size < kbLimit) {\r
405 out = (Math.round(((size*10) / byteLimit))/10) + ' KB';\r
406 } else if (size < mbLimit) {\r
407 out = (Math.round(((size*10) / kbLimit))/10) + ' MB';\r
408 } else {\r
409 out = (Math.round(((size*10) / mbLimit))/10) + ' GB';\r
410 }\r
411 return out;\r
412 };\r
413 })(),\r
414\r
415 /**\r
416 * It does simple math for use in a template, for example:\r
417 *\r
418 * var tpl = new Ext.Template('{value} * 10 = {value:math("* 10")}');\r
419 *\r
420 * @return {Function} A function that operates on the passed value.\r
421 * @method\r
422 */\r
423 math : (function(){\r
424 var fns = {};\r
425\r
426 return function(v, a){\r
427 if (!fns[a]) {\r
428 fns[a] = Ext.functionFactory('v', 'return v ' + a + ';');\r
429 }\r
430 return fns[a](v);\r
431 };\r
432 }()),\r
433\r
434 /**\r
435 * Rounds the passed number to the required decimal precision.\r
436 * @param {Number/String} value The numeric value to round.\r
437 * @param {Number} [precision] The number of decimal places to which to round the\r
438 * first parameter's value. If `undefined` the `value` is passed to `Math.round`\r
439 * otherwise the value is returned unmodified.\r
440 * @return {Number} The rounded value.\r
441 */\r
442 round : function(value, precision) {\r
443 var result = Number(value);\r
444 if (typeof precision === 'number') {\r
445 precision = Math.pow(10, precision);\r
446 result = Math.round(value * precision) / precision;\r
447 } else if (precision === undefined) {\r
448 result = Math.round(result);\r
449 }\r
450 return result;\r
451 },\r
452\r
453 /**\r
454 * Formats the passed number according to the passed format string.\r
455 *\r
456 * The number of digits after the decimal separator character specifies the number of\r
457 * decimal places in the resulting string. The *local-specific* decimal character is\r
458 * used in the result.\r
459 *\r
460 * The *presence* of a thousand separator character in the format string specifies that\r
461 * the *locale-specific* thousand separator (if any) is inserted separating thousand groups.\r
462 *\r
463 * By default, "," is expected as the thousand separator, and "." is expected as the decimal separator.\r
464 *\r
465 * Locale-specific characters are always used in the formatted output when inserting\r
466 * thousand and decimal separators. These can be set using the {@link #thousandSeparator} and\r
467 * {@link #decimalSeparator} options.\r
468 *\r
469 * The format string must specify separator characters according to US/UK conventions ("," as the\r
470 * thousand separator, and "." as the decimal separator)\r
471 *\r
472 * To allow specification of format strings according to local conventions for separator characters, add\r
473 * the string `/i` to the end of the format string. This format depends on the {@link #thousandSeparator} and\r
474 * {@link #decimalSeparator} options. For example, if using European style separators, then the format string\r
475 * can be specified as `'0.000,00'`. This would be equivalent to using `'0,000.00'` when using US style formatting.\r
476 *\r
477 * Examples (123456.789):\r
478 * \r
479 * - `0` - (123457) show only digits, no precision\r
480 * - `0.00` - (123456.79) show only digits, 2 precision\r
481 * - `0.0000` - (123456.7890) show only digits, 4 precision\r
482 * - `0,000` - (123,457) show comma and digits, no precision\r
483 * - `0,000.00` - (123,456.79) show comma and digits, 2 precision\r
484 * - `0,0.00` - (123,456.79) shortcut method, show comma and digits, 2 precision\r
485 * - `0.####` - (123,456.789) Allow maximum 4 decimal places, but do not right pad with zeroes\r
486 * - `0.00##` - (123456.789) Show at least 2 decimal places, maximum 4, but do not right pad with zeroes\r
487 *\r
488 * @param {Number} v The number to format.\r
489 * @param {String} formatString The way you would like to format this text.\r
490 * @return {String} The formatted number.\r
491 */\r
492 number : function(v, formatString) {\r
493 if (!formatString) {\r
494 return v;\r
495 }\r
496 if (isNaN(v)) {\r
497 return '';\r
498 }\r
499 \r
500 var formatFn = me.formatFns[formatString];\r
501\r
502 // Generate formatting function to be cached and reused keyed by the format string.\r
503 // This results in a 100% performance increase over analyzing the format string each invocation.\r
504 if (!formatFn) {\r
505\r
506 var originalFormatString = formatString,\r
507 comma = me.thousandSeparator,\r
508 decimalSeparator = me.decimalSeparator,\r
509 precision = 0,\r
510 trimPart = '',\r
511 hasComma,\r
512 splitFormat,\r
513 extraChars,\r
514 trimTrailingZeroes,\r
515 code, len;\r
516\r
517 // The "/i" suffix allows caller to use a locale-specific formatting string.\r
518 // Clean the format string by removing all but numerals and the decimal separator.\r
519 // Then split the format string into pre and post decimal segments according to *what* the\r
520 // decimal separator is. If they are specifying "/i", they are using the local convention in the format string.\r
521 if (formatString.substr(formatString.length - 2) === '/i') {\r
522 // In a vast majority of cases, the separator will never change over the lifetime of the application.\r
523 // So we'll only regenerate this if we really need to\r
524 if (!me.I18NFormatCleanRe || me.lastDecimalSeparator !== decimalSeparator) {\r
525 me.I18NFormatCleanRe = new RegExp('[^\\d\\' + decimalSeparator + '#]','g');\r
526 me.lastDecimalSeparator = decimalSeparator;\r
527 }\r
528 formatString = formatString.substr(0, formatString.length - 2);\r
529 hasComma = formatString.indexOf(comma) !== -1;\r
530 splitFormat = formatString.replace(me.I18NFormatCleanRe, '').split(decimalSeparator);\r
531 } else {\r
532 hasComma = formatString.indexOf(',') !== -1;\r
533 splitFormat = formatString.replace(me.formatCleanRe, '').split('.');\r
534 }\r
535 extraChars = formatString.replace(me.formatPattern, '');\r
536\r
537 if (splitFormat.length > 2) {\r
538 //<debug>\r
539 Ext.raise({\r
540 sourceClass: "Ext.util.Format",\r
541 sourceMethod: "number",\r
542 value: v,\r
543 formatString: formatString,\r
544 msg: "Invalid number format, should have no more than 1 decimal"\r
545 });\r
546 //</debug>\r
547 } else if (splitFormat.length === 2) {\r
548 precision = splitFormat[1].length;\r
549\r
550 // Formatting ending in .##### means maximum 5 trailing significant digits\r
551 trimTrailingZeroes = splitFormat[1].match(me.hashRe);\r
552 if (trimTrailingZeroes) {\r
553 len = trimTrailingZeroes[0].length;\r
554 // Need to escape, since this will be '.' by default\r
555 trimPart = 'trailingZeroes=new RegExp(Ext.String.escapeRegex(utilFormat.decimalSeparator) + "*0{0,' + len + '}$")';\r
556 }\r
557 }\r
558 \r
559 // The function we create is called immediately and returns a closure which has access to vars and some fixed values; RegExes and the format string.\r
560 code = [\r
561 'var utilFormat=Ext.util.Format,extNumber=Ext.Number,neg,absVal,fnum,parts' +\r
562 (hasComma ? ',thousandSeparator,thousands=[],j,n,i' : '') +\r
563 (extraChars ? ',formatString="' + formatString + '",formatPattern=/[\\d,\\.#]+/' : '') +\r
564 ',trailingZeroes;' +\r
565 'return function(v){' +\r
566 'if(typeof v!=="number"&&isNaN(v=extNumber.from(v,NaN)))return"";' +\r
567 'neg=v<0;',\r
568 'absVal=Math.abs(v);',\r
569 'fnum=Ext.Number.toFixed(absVal, ' + precision + ');',\r
570 trimPart, ';'\r
571 ];\r
572\r
573 if (hasComma) {\r
574 // If we have to insert commas...\r
575 \r
576 // split the string up into whole and decimal parts if there are decimals\r
577 if (precision) {\r
578 code[code.length] = 'parts=fnum.split(".");';\r
579 code[code.length] = 'fnum=parts[0];';\r
580 }\r
581 code[code.length] =\r
582 'if(absVal>=1000) {';\r
583 code[code.length] = 'thousandSeparator=utilFormat.thousandSeparator;' +\r
584 'thousands.length=0;' +\r
585 'j=fnum.length;' +\r
586 'n=fnum.length%3||3;' +\r
587 'for(i=0;i<j;i+=n){' +\r
588 'if(i!==0){' +\r
589 'n=3;' +\r
590 '}' +\r
591 'thousands[thousands.length]=fnum.substr(i,n);' +\r
592 '}' +\r
593 'fnum=thousands.join(thousandSeparator);' + \r
594 '}';\r
595 if (precision) {\r
596 code[code.length] = 'fnum += utilFormat.decimalSeparator+parts[1];';\r
597 }\r
598 \r
599 } else if (precision) {\r
600 // If they are using a weird decimal separator, split and concat using it\r
601 code[code.length] = 'if(utilFormat.decimalSeparator!=="."){' +\r
602 'parts=fnum.split(".");' +\r
603 'fnum=parts[0]+utilFormat.decimalSeparator+parts[1];' +\r
604 '}';\r
605 }\r
606\r
607 /*\r
608 * Edge case. If we have a very small negative number it will get rounded to 0,\r
609 * however the initial check at the top will still report as negative. Replace\r
610 * everything but 1-9 and check if the string is empty to determine a 0 value.\r
611 */\r
612 code[code.length] = 'if(neg&&fnum!=="' + (precision ? '0.' + Ext.String.repeat('0', precision) : '0') + '") { fnum="-"+fnum; }';\r
613\r
614 if (trimTrailingZeroes) {\r
615 code[code.length] = 'fnum=fnum.replace(trailingZeroes,"");';\r
616 }\r
617\r
618 code[code.length] = 'return ';\r
619\r
620 // If there were extra characters around the formatting string, replace the format string part with the formatted number.\r
621 if (extraChars) {\r
622 code[code.length] = 'formatString.replace(formatPattern, fnum);';\r
623 } else {\r
624 code[code.length] = 'fnum;';\r
625 }\r
626 code[code.length] = '};';\r
627\r
628 formatFn = me.formatFns[originalFormatString] = Ext.functionFactory('Ext', code.join(''))(Ext);\r
629 }\r
630 return formatFn(v);\r
631 },\r
632\r
633 /**\r
634 * Returns a number rendering function that can be reused to apply a number format multiple\r
635 * times efficiently.\r
636 *\r
637 * @param {String} format Any valid number format string for {@link #number}\r
638 * @return {Function} The number formatting function\r
639 */\r
640 numberRenderer : function(format) {\r
641 return function(v) {\r
642 return me.number(v, format);\r
643 };\r
644 },\r
645\r
646 /**\r
647 * Formats the passed number as a percentage according to the passed format string.\r
648 * The number should be between 0 and 1 to represent 0% to 100%.\r
649 *\r
650 * @param {Number} value The percentage to format.\r
651 * @param {String} [formatString="0"] See {@link #number} for details.\r
652 * @return {String} The formatted percentage.\r
653 */\r
654 percent: function (value, formatString) {\r
655 return me.number(value * 100, formatString || '0') + me.percentSign;\r
656 },\r
657\r
658 /**\r
659 * Formats an object of name value properties as HTML element attribute values suitable for using when creating textual markup.\r
660 * @param {Object} attributes An object containing the HTML attributes as properties eg: `{height:40, vAlign:'top'}`\r
661 */\r
662 attributes: function(attributes) {\r
663 if (typeof attributes === 'object') {\r
664 var result = [],\r
665 name;\r
666\r
667 for (name in attributes) {\r
668 if (attributes.hasOwnProperty(name)) {\r
669 result.push(name, '="', name === 'style' ? \r
670 Ext.DomHelper.generateStyles(attributes[name], null, true) :\r
671 Ext.htmlEncode(attributes[name]), '" ');\r
672 }\r
673 }\r
674 attributes = result.join('');\r
675 }\r
676 return attributes || '';\r
677 },\r
678\r
679 /**\r
680 * Selectively return the plural form of a word based on a numeric value.\r
681 * \r
682 * For example, the following template would result in "1 Comment". If the \r
683 * value of `count` was 0 or greater than 1, the result would be "x Comments".\r
684 * \r
685 * var tpl = new Ext.XTemplate('{count:plural("Comment")}');\r
686 * \r
687 * tpl.apply({\r
688 * count: 1\r
689 * }); // returns "1 Comment"\r
690 * \r
691 * Examples using the static `plural` method call:\r
692 * \r
693 * Ext.util.Format.plural(2, 'Comment');\r
694 * // returns "2 Comments"\r
695 * \r
696 * Ext.util.Format.plural(4, 'person', 'people');\r
697 * // returns "4 people"\r
698 *\r
699 * @param {Number} value The value to compare against\r
700 * @param {String} singular The singular form of the word\r
701 * @param {String} [plural] The plural form of the word (defaults to the \r
702 * singular form with an "s" appended)\r
703 * @return {String} output The pluralized output of the passed singular form\r
704 */\r
705 plural : function(v, s, p) {\r
706 return v +' ' + (v === 1 ? s : (p ? p : s+'s'));\r
707 },\r
708\r
709 /**\r
710 * Converts newline characters to the HTML tag `<br/>`\r
711 *\r
712 * @param {String} v The string value to format.\r
713 * @return {String} The string with embedded `<br/>` tags in place of newlines.\r
714 */\r
715 nl2br : function(v) {\r
716 return Ext.isEmpty(v) ? '' : v.replace(me.nl2brRe, '<br/>');\r
717 },\r
718\r
719 /**\r
720 * Alias for {@link Ext.String#capitalize}.\r
721 * @method\r
722 * @inheritdoc Ext.String#capitalize\r
723 */\r
724 capitalize: Ext.String.capitalize,\r
725\r
726 /**\r
727 * Alias for {@link Ext.String#uncapitalize}.\r
728 * @method\r
729 * @inheritdoc Ext.String#uncapitalize\r
730 */\r
731 uncapitalize: Ext.String.uncapitalize,\r
732\r
733 /**\r
734 * Alias for {@link Ext.String#ellipsis}.\r
735 * @method\r
736 * @inheritdoc Ext.String#ellipsis\r
737 */\r
738 ellipsis: Ext.String.ellipsis,\r
739\r
740 /**\r
741 * Alias for {@link Ext.String#escape}.\r
742 * @method\r
743 * @inheritdoc Ext.String#escape\r
744 */\r
745 escape: Ext.String.escape,\r
746\r
747 /**\r
748 * Alias for {@link Ext.String#escapeRegex}.\r
749 * @method\r
750 * @inheritdoc Ext.String#escapeRegex\r
751 */\r
752 escapeRegex : Ext.String.escapeRegex,\r
753\r
754 /**\r
755 * Alias for {@link Ext.String#htmlDecode}.\r
756 * @method\r
757 * @inheritdoc Ext.String#htmlDecode\r
758 */\r
759 htmlDecode: Ext.String.htmlDecode,\r
760\r
761 /**\r
762 * Alias for {@link Ext.String#htmlEncode}.\r
763 * @method\r
764 * @inheritdoc Ext.String#htmlEncode\r
765 */\r
766 htmlEncode: Ext.String.htmlEncode,\r
767\r
768 /**\r
769 * Alias for {@link Ext.String#leftPad}.\r
770 * @method\r
771 * @inheritdoc Ext.String#leftPad\r
772 */\r
773 leftPad: Ext.String.leftPad,\r
774\r
775 /**\r
776 * Alias for {@link Ext.String#toggle}.\r
777 * @method\r
778 * @inheritdoc Ext.String#toggle\r
779 */\r
780 toggle: Ext.String.toggle,\r
781\r
782 /**\r
783 * Alias for {@link Ext.String#trim}.\r
784 * @method\r
785 * @inheritdoc Ext.String#trim\r
786 */\r
787 trim : Ext.String.trim,\r
788\r
789 /**\r
790 * Parses a number or string representing margin sizes into an object.\r
791 * Supports CSS-style margin declarations (e.g. 10, "10", "10 10", "10 10 10" and\r
792 * "10 10 10 10" are all valid options and would return the same result).\r
793 *\r
794 * @param {Number/String} box The encoded margins\r
795 * @return {Object} An object with margin sizes for top, right, bottom and left\r
796 */\r
797 parseBox : function(box) {\r
798 box = box || 0;\r
799\r
800 if (typeof box === 'number') {\r
801 return {\r
802 top : box,\r
803 right : box,\r
804 bottom: box,\r
805 left : box\r
806 };\r
807 }\r
808\r
809 var parts = box.split(' '),\r
810 ln = parts.length;\r
811\r
812 if (ln === 1) {\r
813 parts[1] = parts[2] = parts[3] = parts[0];\r
814 }\r
815 else if (ln === 2) {\r
816 parts[2] = parts[0];\r
817 parts[3] = parts[1];\r
818 }\r
819 else if (ln === 3) {\r
820 parts[3] = parts[1];\r
821 }\r
822\r
823 return {\r
824 top :parseInt(parts[0], 10) || 0,\r
825 right :parseInt(parts[1], 10) || 0,\r
826 bottom:parseInt(parts[2], 10) || 0,\r
827 left :parseInt(parts[3], 10) || 0\r
828 };\r
829 }\r
830 };\r
831});\r