]> git.proxmox.com Git - sencha-touch.git/blob - src/src/util/Format.js
import Sencha Touch 2.4.2 source
[sencha-touch.git] / src / src / util / Format.js
1 /**
2 * Reusable data formatting functions
3 */
4 Ext.define('Ext.util.Format', {
5 requires: [
6 'Ext.DateExtras'
7 ],
8
9 singleton: true,
10
11 /**
12 * The global default date format.
13 */
14 defaultDateFormat: 'm/d/Y',
15
16 escapeRe: /('|\\)/g,
17 trimRe: /^[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000]+|[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000]+$/g,
18 formatRe: /\{(\d+)\}/g,
19 escapeRegexRe: /([-.*+?^${}()|[\]\/\\])/g,
20 dashesRe: /-/g,
21 iso8601TestRe: /\d\dT\d\d/,
22 iso8601SplitRe: /[- :T\.Z\+]/,
23
24 /**
25 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length.
26 * @param {String} value The string to truncate.
27 * @param {Number} length The maximum length to allow before truncating.
28 * @param {Boolean} [word=false] True to try to find a common word break.
29 * @return {String} The converted text.
30 */
31 ellipsis: function(value, len, word) {
32 if (value && value.length > len) {
33 if (word) {
34 var vs = value.substr(0, len - 2),
35 index = Math.max(vs.lastIndexOf(' '), vs.lastIndexOf('.'), vs.lastIndexOf('!'), vs.lastIndexOf('?'));
36 if (index != -1 && index >= (len - 15)) {
37 return vs.substr(0, index) + "...";
38 }
39 }
40 return value.substr(0, len - 3) + "...";
41 }
42 return value;
43 },
44
45 /**
46 * Escapes the passed string for use in a regular expression.
47 * @param {String} str
48 * @return {String}
49 */
50 escapeRegex: function(s) {
51 return s.replace(Ext.util.Format.escapeRegexRe, "\\$1");
52 },
53
54 /**
55 * Escapes the passed string for ' and \.
56 * @param {String} string The string to escape.
57 * @return {String} The escaped string.
58 */
59 escape: function(string) {
60 return string.replace(Ext.util.Format.escapeRe, "\\$1");
61 },
62
63 /**
64 * Utility function that allows you to easily switch a string between two alternating values. The passed value
65 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
66 * they are already different, the first value passed in is returned.
67 *
68 * __Note:__ This method returns the new value but does not change the current string.
69 *
70 * // alternate sort directions
71 * sort = Ext.util.Format.toggle(sort, 'ASC', 'DESC');
72 *
73 * // instead of conditional logic:
74 * sort = (sort === 'ASC' ? 'DESC' : 'ASC');
75 *
76 * @param {String} string The current string
77 * @param {String} value The value to compare to the current string
78 * @param {String} other The new value to use if the string already equals the first value passed in
79 * @return {String} The new value
80 */
81 toggle: function(string, value, other) {
82 return string == value ? other : value;
83 },
84
85 /**
86 * Trims whitespace from either end of a string, leaving spaces within the string intact. Example:
87 *
88 * var s = ' foo bar ';
89 * alert('-' + s + '-'); // alerts "- foo bar -"
90 * alert('-' + Ext.util.Format.trim(s) + '-'); // alerts "-foo bar-"
91 *
92 * @param {String} string The string to escape
93 * @return {String} The trimmed string
94 */
95 trim: function(string) {
96 return string.replace(Ext.util.Format.trimRe, "");
97 },
98
99 /**
100 * Pads the left side of a string with a specified character. This is especially useful
101 * for normalizing number and date strings. Example usage:
102 *
103 * var s = Ext.util.Format.leftPad('123', 5, '0');
104 * // s now contains the string: '00123'
105 *
106 * @param {String} string The original string.
107 * @param {Number} size The total length of the output string.
108 * @param {String} [char=' '] (optional) The character with which to pad the original string.
109 * @return {String} The padded string.
110 */
111 leftPad: function (val, size, ch) {
112 var result = String(val);
113 ch = ch || " ";
114 while (result.length < size) {
115 result = ch + result;
116 }
117 return result;
118 },
119
120 /**
121 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
122 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
123 *
124 * var cls = 'my-class', text = 'Some text';
125 * var s = Ext.util.Format.format('<div class="{0}">{1}</div>', cls, text);
126 * // s now contains the string: '<div class="my-class">Some text</div>'
127 *
128 * @param {String} string The tokenized string to be formatted.
129 * @param {String...} values The values to replace token {0}, {1}, etc.
130 * @return {String} The formatted string.
131 */
132 format: function (format) {
133 var args = Ext.toArray(arguments, 1);
134 return format.replace(Ext.util.Format.formatRe, function(m, i) {
135 return args[i];
136 });
137 },
138
139 /**
140 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
141 * @param {String} value The string to encode.
142 * @return {String} The encoded text.
143 */
144 htmlEncode: function(value) {
145 return ! value ? value: String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
146 },
147
148 /**
149 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
150 * @param {String} value The string to decode.
151 * @return {String} The decoded text.
152 */
153 htmlDecode: function(value) {
154 return ! value ? value: String(value).replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"').replace(/&amp;/g, "&");
155 },
156
157 /**
158 * Parse a value into a formatted date using the specified format pattern.
159 * Note that this uses the native Javascript Date.parse() method and is therefore subject to its idiosyncrasies.
160 * Most formats assume the local timezone unless specified. One notable exception is 'YYYY-MM-DD' (note the dashes)
161 * which is typically interpreted in UTC and can cause date shifting.
162 * @param {String/Date} value The value to format. Strings must conform to the format expected by the JavaScript
163 * Date object's [parse() method](http://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/parse).
164 * @param {String} [format='m/d/Y'] (optional) Any valid date format string.
165 * @return {String} The formatted date string.
166 */
167 date: function(value, format) {
168 var date = value;
169 if (!value) {
170 return "";
171 }
172 if (!Ext.isDate(value)) {
173 date = new Date(Date.parse(value));
174 if (isNaN(date)) {
175 // Dates with ISO 8601 format are not well supported by mobile devices, this can work around the issue.
176 if (this.iso8601TestRe.test(value)) {
177 // Fix for older android browsers to properly implement ISO 8601 formatted dates with timezone
178 if (Ext.os.is.Android && Ext.os.version.isLessThan("3.0")) {
179 /**
180 * This code is modified from the following source: <https://github.com/csnover/js-iso8601>
181 * © 2011 Colin Snover <http://zetafleet.com>
182 * Released under MIT license.
183 */
184 var potentialUndefinedKeys = [ 1, 4, 5, 6, 7, 10, 11 ];
185 var dateParsed, minutesOffset = 0;
186
187 // Capture Groups
188 // 1 YYYY (optional)
189 // 2 MM
190 // 3 DD
191 // 4 HH
192 // 5 mm (optional)
193 // 6 ss (optional)
194 // 7 msec (optional)
195 // 8 Z (optional)
196 // 9 ± (optional)
197 // 10 tzHH (optional)
198 // 11 tzmm (optional)
199 if ((dateParsed = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(value))) {
200
201 //Set any undefined values needed for Date to 0
202 for (var i = 0, k; (k = potentialUndefinedKeys[i]); ++i) {
203 dateParsed[k] = +dateParsed[k] || 0;
204 }
205
206 // Fix undefined month and decrement
207 dateParsed[2] = (+dateParsed[2] || 1) - 1;
208 //fix undefined days
209 dateParsed[3] = +dateParsed[3] || 1;
210
211 // Correct for timezone
212 if (dateParsed[8] !== 'Z' && dateParsed[9] !== undefined) {
213 minutesOffset = dateParsed[10] * 60 + dateParsed[11];
214
215 if (dateParsed[9] === '+') {
216 minutesOffset = 0 - minutesOffset;
217 }
218 }
219
220 // Calculate valid date
221 date = new Date(Date.UTC(dateParsed[1], dateParsed[2], dateParsed[3], dateParsed[4], dateParsed[5] + minutesOffset, dateParsed[6], dateParsed[7]));
222 }
223 } else {
224 date = value.split(this.iso8601SplitRe);
225 date = new Date(date[0], date[1] - 1, date[2], date[3], date[4], date[5]);
226 }
227 }
228 }
229 if (isNaN(date)) {
230 // Dates with the format "2012-01-20" fail, but "2012/01/20" work in some browsers. We'll try and
231 // get around that.
232 date = new Date(Date.parse(value.replace(this.dashesRe, "/")));
233 //<debug>
234 if (isNaN(date)) {
235 Ext.Logger.error("Cannot parse the passed value " + value + " into a valid date");
236 }
237 //</debug>
238 }
239 value = date;
240 }
241 return Ext.Date.format(value, format || Ext.util.Format.defaultDateFormat);
242 }
243 });