summaryrefslogtreecommitdiff
path: root/frontend/gamma/js/MochiKit/Text.js
Unidiff
Diffstat (limited to 'frontend/gamma/js/MochiKit/Text.js') (more/less context) (ignore whitespace changes)
-rw-r--r--frontend/gamma/js/MochiKit/Text.js359
1 files changed, 164 insertions, 195 deletions
diff --git a/frontend/gamma/js/MochiKit/Text.js b/frontend/gamma/js/MochiKit/Text.js
index a44f7e4..ff6366d 100644
--- a/frontend/gamma/js/MochiKit/Text.js
+++ b/frontend/gamma/js/MochiKit/Text.js
@@ -8,7 +8,7 @@ See <http://mochikit.com/> for documentation, downloads, license, etc.
8 8
9***/ 9***/
10 10
11MochiKit.Base._module('Text', '1.5', ['Base', 'Format']); 11MochiKit.Base.module(MochiKit, 'Text', '1.5', ['Base', 'Format']);
12 12
13/** 13/**
14 * Checks if a text string starts with the specified substring. If 14 * Checks if a text string starts with the specified substring. If
@@ -22,7 +22,7 @@ MochiKit.Base._module('Text', '1.5', ['Base', 'Format']);
22 */ 22 */
23MochiKit.Text.startsWith = function (substr, str) { 23MochiKit.Text.startsWith = function (substr, str) {
24 return str != null && substr != null && str.indexOf(substr) == 0; 24 return str != null && substr != null && str.indexOf(substr) == 0;
25} 25};
26 26
27/** 27/**
28 * Checks if a text string ends with the specified substring. If 28 * Checks if a text string ends with the specified substring. If
@@ -37,7 +37,7 @@ MochiKit.Text.startsWith = function (substr, str) {
37MochiKit.Text.endsWith = function (substr, str) { 37MochiKit.Text.endsWith = function (substr, str) {
38 return str != null && substr != null && 38 return str != null && substr != null &&
39 str.lastIndexOf(substr) == Math.max(str.length - substr.length, 0); 39 str.lastIndexOf(substr) == Math.max(str.length - substr.length, 0);
40} 40};
41 41
42/** 42/**
43 * Checks if a text string contains the specified substring. If 43 * Checks if a text string contains the specified substring. If
@@ -51,7 +51,7 @@ MochiKit.Text.endsWith = function (substr, str) {
51 */ 51 */
52MochiKit.Text.contains = function (substr, str) { 52MochiKit.Text.contains = function (substr, str) {
53 return str != null && substr != null && str.indexOf(substr) >= 0; 53 return str != null && substr != null && str.indexOf(substr) >= 0;
54} 54};
55 55
56/** 56/**
57 * Adds a character to the left-hand side of a string until it 57 * Adds a character to the left-hand side of a string until it
@@ -71,7 +71,7 @@ MochiKit.Text.padLeft = function (str, minLength, fillChar) {
71 str = fillChar + str; 71 str = fillChar + str;
72 } 72 }
73 return str; 73 return str;
74} 74};
75 75
76/** 76/**
77 * Adds a character to the right-hand side of a string until it 77 * Adds a character to the right-hand side of a string until it
@@ -91,7 +91,7 @@ MochiKit.Text.padRight = function (str, minLength, fillChar) {
91 str += fillChar; 91 str += fillChar;
92 } 92 }
93 return str; 93 return str;
94} 94};
95 95
96/** 96/**
97 * Returns a truncated copy of a string. If the string is shorter 97 * Returns a truncated copy of a string. If the string is shorter
@@ -119,29 +119,55 @@ MochiKit.Text.truncate = function (str, maxLength, tail) {
119 } else { 119 } else {
120 return str.slice(0, maxLength); 120 return str.slice(0, maxLength);
121 } 121 }
122} 122};
123 123
124/** 124/**
125 * Splits a text string, applies a function and joins the results 125 * Splits a text string using separator as the split point
126 * back together again. This is a convenience function for calling 126 * If max is given, at most max splits are done, giving at most
127 * split(), map() and join() separately. It can be used to easily 127 * max + 1 elements in the returned list.
128 * trim each line in a text string (using the strip function), or to
129 * translate a text word-by-word.
130 * 128 *
131 * @param {Function} func the function to apply
132 * @param {String} str the string to split 129 * @param {String} str the string to split
133 * @param {String} [separator] the separator character to use, 130 * @param {String/RegExp} [separator] the separator char or regexp to use,
134 * defaults to newline 131 * defaults to newline
132 * @param {Number} [max] the maximum number of parts to return
133 * @return {Array} an array of parts of the string
134 */
135MochiKit.Text.split = function (str, separator, max) {
136 if (str == null) {
137 return str;
138 }
139 separator = separator || '\n';
140 var bits = str.split(separator);
141 if ((typeof(max) == "undefined") || max >= bits.length - 1) {
142 return bits;
143 }
144 bits.splice(max, bits.length, bits.slice(max, bits.length).join(separator));
145 return bits;
146};
147
148/**
149 * Splits a text string using separator as the split point
150 * If max is given, at most max splits are done,
151 * using splits from the right
135 * 152 *
136 * @return {String} a string with the joined up results 153 * @param {String} str the string to split
154 * @param {String/RegExp} [separator] the separator char or regexp to use,
155 * defaults to newline
156 * @param {Number} [max] the maximum number of parts to return
157 * @return {Array} an array of parts of the string
137 */ 158 */
138MochiKit.Text.splitJoin = function (func, str, separator) { 159MochiKit.Text.rsplit = function (str, separator, max) {
139 if (str == null || str.length == 0) { 160 if (str == null) {
140 return str; 161 return str;
141 } 162 }
142 separator = separator || '\n' 163 separator = separator || '\n';
143 return MochiKit.Base.map(func, str.split(separator)).join(separator); 164 var bits = str.split(separator);
144} 165 if ((typeof(max) == "undefined") || max >= bits.length - 1){
166 return bits;
167 }
168 bits.splice(0, bits.length-max, bits.slice(0, bits.length-max).join(separator));
169 return bits;
170};
145 171
146/** 172/**
147 * Creates a formatter function for the specified formatter pattern 173 * Creates a formatter function for the specified formatter pattern
@@ -158,7 +184,7 @@ MochiKit.Text.splitJoin = function (func, str, separator) {
158 * @throws FormatPatternError if the format pattern was invalid 184 * @throws FormatPatternError if the format pattern was invalid
159 */ 185 */
160MochiKit.Text.formatter = function (pattern, locale) { 186MochiKit.Text.formatter = function (pattern, locale) {
161 if (typeof(locale) == "undefined") { 187 if (locale == null) {
162 locale = MochiKit.Format.formatLocale(); 188 locale = MochiKit.Format.formatLocale();
163 } else if (typeof(locale) == "string") { 189 } else if (typeof(locale) == "string") {
164 locale = MochiKit.Format.formatLocale(locale); 190 locale = MochiKit.Format.formatLocale(locale);
@@ -175,8 +201,8 @@ MochiKit.Text.formatter = function (pattern, locale) {
175 } 201 }
176 } 202 }
177 return res.join(""); 203 return res.join("");
178 } 204 };
179} 205};
180 206
181/** 207/**
182 * Formats the specified arguments according to a formatter pattern. 208 * Formats the specified arguments according to a formatter pattern.
@@ -193,7 +219,7 @@ MochiKit.Text.formatter = function (pattern, locale) {
193MochiKit.Text.format = function (pattern/*, ...*/) { 219MochiKit.Text.format = function (pattern/*, ...*/) {
194 var func = MochiKit.Text.formatter(pattern); 220 var func = MochiKit.Text.formatter(pattern);
195 return func.apply(this, MochiKit.Base.extend([], arguments, 1)); 221 return func.apply(this, MochiKit.Base.extend([], arguments, 1));
196} 222};
197 223
198/** 224/**
199 * Format a value with the specified format specifier. 225 * Format a value with the specified format specifier.
@@ -205,24 +231,29 @@ MochiKit.Text.format = function (pattern/*, ...*/) {
205 * LOCALE.en_US 231 * LOCALE.en_US
206 * 232 *
207 * @return {String} the formatted output string 233 * @return {String} the formatted output string
234 *
235 * @throws FormatPatternError if the format specifier was invalid
208 */ 236 */
209MochiKit.Text.formatValue = function (spec, value, locale) { 237MochiKit.Text.formatValue = function (spec, value, locale) {
210 var self = MochiKit.Text; 238 var self = MochiKit.Text;
211 if (typeof(spec) === "string") { 239 if (typeof(spec) === "string") {
212 spec = self._parseFormatFlags(spec, 0, spec.length - 1); 240 spec = self._parseFormatFlags(spec, 0, spec.length);
213 } 241 }
214 for (var i = 0; spec.path != null && i < spec.path.length; i++) { 242 for (var i = 0; spec.path != null && i < spec.path.length; i++) {
215 if (value != null) { 243 if (value != null) {
216 value = value[spec.path[i]]; 244 value = value[spec.path[i]];
217 } 245 }
218 } 246 }
219 if (typeof(locale) == "undefined") { 247 if (locale == null) {
220 locale = MochiKit.Format.formatLocale(); 248 locale = MochiKit.Format.formatLocale();
221 } else if (typeof(locale) == "string") { 249 } else if (typeof(locale) == "string") {
222 locale = MochiKit.Format.formatLocale(locale); 250 locale = MochiKit.Format.formatLocale(locale);
223 } 251 }
224 var str = ""; 252 var str = "";
225 if (spec.numeric) { 253 if (spec.type == "number") {
254 if (value instanceof Number) {
255 value = value.valueOf();
256 }
226 if (typeof(value) != "number" || isNaN(value)) { 257 if (typeof(value) != "number" || isNaN(value)) {
227 str = ""; 258 str = "";
228 } else if (value === Number.POSITIVE_INFINITY) { 259 } else if (value === Number.POSITIVE_INFINITY) {
@@ -230,8 +261,7 @@ MochiKit.Text.formatValue = function (spec, value, locale) {
230 } else if (value === Number.NEGATIVE_INFINITY) { 261 } else if (value === Number.NEGATIVE_INFINITY) {
231 str = "-\u221e"; 262 str = "-\u221e";
232 } else { 263 } else {
233 var sign = (spec.sign === "-") ? "" : spec.sign; 264 var sign = (value < 0) ? "-" : spec.sign;
234 sign = (value < 0) ? "-" : sign;
235 value = Math.abs(value); 265 value = Math.abs(value);
236 if (spec.format === "%") { 266 if (spec.format === "%") {
237 str = self._truncToPercent(value, spec.precision); 267 str = self._truncToPercent(value, spec.precision);
@@ -254,7 +284,7 @@ MochiKit.Text.formatValue = function (spec, value, locale) {
254 } else if (spec.padding == "0") { 284 } else if (spec.padding == "0") {
255 str = self.padLeft(str, spec.width - sign.length, "0"); 285 str = self.padLeft(str, spec.width - sign.length, "0");
256 } 286 }
257 str = self._localizeNumber(str, locale, spec.grouping); 287 str = self._localizeNumber(str, locale, spec.group);
258 str = sign + str; 288 str = sign + str;
259 } 289 }
260 if (str !== "" && spec.format === "%") { 290 if (str !== "" && spec.format === "%") {
@@ -264,7 +294,7 @@ MochiKit.Text.formatValue = function (spec, value, locale) {
264 if (spec.format == "r") { 294 if (spec.format == "r") {
265 str = MochiKit.Base.repr(value); 295 str = MochiKit.Base.repr(value);
266 } else { 296 } else {
267 str = (value == null) ? "null" : value.toString(); 297 str = (value == null) ? "" : value.toString();
268 } 298 }
269 str = self.truncate(str, spec.precision); 299 str = self.truncate(str, spec.precision);
270 } 300 }
@@ -274,7 +304,7 @@ MochiKit.Text.formatValue = function (spec, value, locale) {
274 str = self.padLeft(str, spec.width); 304 str = self.padLeft(str, spec.width);
275 } 305 }
276 return str; 306 return str;
277} 307};
278 308
279/** 309/**
280 * Adjust an already formatted numeric string for locale-specific 310 * Adjust an already formatted numeric string for locale-specific
@@ -284,16 +314,16 @@ MochiKit.Text.formatValue = function (spec, value, locale) {
284 * 314 *
285 * @param {String} num the formatted number string 315 * @param {String} num the formatted number string
286 * @param {Object} locale the formatting locale to use 316 * @param {Object} locale the formatting locale to use
287 * @param {Boolean} grouping the grouping flag 317 * @param {Boolean} group the grouping flag
288 * 318 *
289 * @return {String} the localized number string 319 * @return {String} the localized number string
290 */ 320 */
291MochiKit.Text._localizeNumber = function (num, locale, grouping) { 321MochiKit.Text._localizeNumber = function (num, locale, group) {
292 var parts = num.split(/\./); 322 var parts = num.split(/\./);
293 var whole = parts[0]; 323 var whole = parts[0];
294 var frac = (parts.length == 1) ? "" : parts[1]; 324 var frac = (parts.length == 1) ? "" : parts[1];
295 var res = (frac.length > 0) ? locale.decimal : ""; 325 var res = (frac.length > 0) ? locale.decimal : "";
296 while (grouping && frac.length > 3) { 326 while (group && frac.length > 3) {
297 res = res + frac.substring(0, 3) + locale.separator; 327 res = res + frac.substring(0, 3) + locale.separator;
298 frac = frac.substring(3); 328 frac = frac.substring(3);
299 if (whole.charAt(0) == "0") { 329 if (whole.charAt(0) == "0") {
@@ -301,15 +331,15 @@ MochiKit.Text._localizeNumber = function (num, locale, grouping) {
301 } 331 }
302 } 332 }
303 if (frac.length > 0) { 333 if (frac.length > 0) {
304 res += frac; 334 res = res + frac;
305 } 335 }
306 while (grouping && whole.length > 3) { 336 while (group && whole.length > 3) {
307 var pos = whole.length - 3; 337 var pos = whole.length - 3;
308 res = locale.separator + whole.substring(pos) + res; 338 res = locale.separator + whole.substring(pos) + res;
309 whole = whole.substring((whole.charAt(0) == "0") ? 1 : 0, pos); 339 whole = whole.substring((whole.charAt(0) == "0") ? 1 : 0, pos);
310 } 340 }
311 return whole + res; 341 return whole + res;
312} 342};
313 343
314/** 344/**
315 * Parses a format pattern and returns an array of constant strings 345 * Parses a format pattern and returns an array of constant strings
@@ -324,44 +354,32 @@ MochiKit.Text._localizeNumber = function (num, locale, grouping) {
324MochiKit.Text._parsePattern = function (pattern) { 354MochiKit.Text._parsePattern = function (pattern) {
325 var self = MochiKit.Text; 355 var self = MochiKit.Text;
326 var parts = []; 356 var parts = [];
327 var start = 0; 357 var re = /{[^{}]*}|{{?|}}?/g;
328 var pos = 0; 358 var lastPos = re.lastIndex = 0;
329 for (pos = 0; pos < pattern.length; pos++) { 359 var m;
330 if (pattern.charAt(pos) == "{") { 360 while ((m = re.exec(pattern)) != null) {
331 if (pos + 1 >= pattern.length) { 361 if (lastPos < m.index) {
332 var msg = "unescaped { char, should be escaped as {{"; 362 parts.push(pattern.substring(lastPos, m.index))
333 throw new self.FormatPatternError(pattern, pos, msg); 363 }
334 } else if (pattern.charAt(pos + 1) == "{") { 364 var str = m[0];
335 parts.push(pattern.substring(start, pos + 1)); 365 lastPos = m.index + str.length;
336 start = pos + 2; 366 if (self.startsWith("{", str) && self.endsWith("}", str)) {
337 pos++; 367 parts.push(self._parseFormat(pattern, m.index + 1, lastPos - 1));
338 } else { 368 } else if (self.startsWith("{{", str) || self.startsWith("}}", str)) {
339 if (start < pos) { 369 parts.push(str.substring(1));
340 parts.push(pattern.substring(start, pos)); 370 } else if (self.startsWith("{", str)) {
341 } 371 var msg = "unescaped { char, should be escaped as {{";
342 start = pattern.indexOf("}", pos) + 1; 372 throw new self.FormatPatternError(pattern, m.index, msg);
343 if (start <= 0) { 373 } else if (self.startsWith("}", str)) {
344 var msg = "unmatched { char, not followed by a } char"; 374 var msg = "unescaped } char, should be escaped as }}";
345 throw new self.FormatPatternError(pattern, pos, msg); 375 throw new self.FormatPatternError(pattern, m.index, msg);
346 }
347 parts.push(self._parseFormat(pattern, pos + 1, start - 1));
348 pos = start - 1;
349 }
350 } else if (pattern.charAt(pos) == "}") {
351 if (pos + 1 >= pattern.length || pattern.charAt(pos + 1) != "}") {
352 var msg = "unescaped } char, should be escaped as }}";
353 throw new self.FormatPatternError(pattern, pos, msg);
354 }
355 parts.push(pattern.substring(start, pos + 1));
356 start = pos + 2;
357 pos++;
358 } 376 }
359 } 377 }
360 if (start < pos) { 378 if (lastPos < pattern.length) {
361 parts.push(pattern.substring(start, pos)); 379 parts.push(pattern.substring(lastPos));
362 } 380 }
363 return parts; 381 return parts;
364} 382};
365 383
366/** 384/**
367 * Parses a format instruction and returns a format info object. 385 * Parses a format instruction and returns a format info object.
@@ -377,40 +395,30 @@ MochiKit.Text._parsePattern = function (pattern) {
377MochiKit.Text._parseFormat = function (pattern, startPos, endPos) { 395MochiKit.Text._parseFormat = function (pattern, startPos, endPos) {
378 var self = MochiKit.Text; 396 var self = MochiKit.Text;
379 var text = pattern.substring(startPos, endPos); 397 var text = pattern.substring(startPos, endPos);
380 var info; 398 var parts = self.split(text, ":", 1);
381 var pos = text.indexOf(":"); 399 var path = parts[0];
382 if (pos == 0) { 400 var flagsPos = startPos + path.length + ((parts.length == 1) ? 0 : 1);
383 info = self._parseFormatFlags(pattern, startPos + 1, endPos); 401 var info = self._parseFormatFlags(pattern, flagsPos, endPos);
384 info.path = [0]; 402 info.path = (path == "") ? [] : path.split(".");
385 } else if (pos > 0) {
386 info = self._parseFormatFlags(pattern, startPos + pos + 1, endPos);
387 info.path = text.substring(0, pos).split(".");
388 } else {
389 info = self._parseFormatFlags(pattern, endPos, endPos);
390 info.path = text.split(".");
391 }
392 var DIGITS = /^\d+$/;
393 for (var i = 0; i < info.path.length; i++) { 403 for (var i = 0; i < info.path.length; i++) {
394 var e = info.path[i]; 404 var v = info.path[i];
395 if (typeof(e) == "string") { 405 // TODO: replace with MochiKit.Format.strip?
396 // TODO: replace with MochiKit.Format.strip? 406 v = v.replace(/^\s+/, "").replace(/\s+$/, "");
397 e = e.replace(/^\s+/, "").replace(/\s+$/, ""); 407 if (v == "" && info.path.length == 1) {
398 if (e == "" && info.path.length == 1) { 408 v = 0;
399 e = 0; 409 } else if (v == "") {
400 } else if (e == "") { 410 var msg = "format value path contains blanks";
401 var msg = "format value path contains blanks"; 411 throw new self.FormatPatternError(pattern, startPos, msg);
402 throw new self.FormatPatternError(pattern, startPos, msg); 412 } else if (/^\d+$/.test(v)) {
403 } else if (DIGITS.test(e)) { 413 v = parseInt(v, 10);
404 e = parseInt(e);
405 }
406 } 414 }
407 info.path[i] = e; 415 info.path[i] = v;
408 } 416 }
409 if (info.path.length < 0 || typeof(info.path[0]) != "number") { 417 if (info.path.length <= 0 || typeof(info.path[0]) != "number") {
410 info.path.unshift(0); 418 info.path.unshift(0);
411 } 419 }
412 return info; 420 return info;
413} 421};
414 422
415/** 423/**
416 * Parses a string with format flags and returns a format info object. 424 * Parses a string with format flags and returns a format info object.
@@ -424,81 +432,52 @@ MochiKit.Text._parseFormat = function (pattern, startPos, endPos) {
424 * @throws FormatPatternError if the format pattern was invalid 432 * @throws FormatPatternError if the format pattern was invalid
425 */ 433 */
426MochiKit.Text._parseFormatFlags = function (pattern, startPos, endPos) { 434MochiKit.Text._parseFormatFlags = function (pattern, startPos, endPos) {
427 var self = MochiKit.Text; 435 var update = MochiKit.Base.update;
428 var info = { numeric: false, format: "s", width: 0, precision: -1, 436 var info = { type: "string", format: "s", width: 0, precision: -1,
429 align: ">", sign: "-", padding: " ", grouping: false }; 437 align: ">", sign: "", padding: " ", group: false };
430 // TODO: replace with MochiKit.Format.rstrip? 438 // TODO: replace with MochiKit.Format.rstrip?
431 var flags = pattern.substring(startPos, endPos).replace(/\s+$/, ""); 439 var text = pattern.substring(startPos, endPos).replace(/\s+$/, "");
432 while (flags.length > 0) { 440 var m = /^([<>+ 0,-]+)?(\d+)?(\.\d*)?([srbdoxXf%])?(.*)$/.exec(text);
433 switch (flags.charAt(0)) { 441 var flags = m[1];
434 case ">": 442 var width = m[2];
435 case "<": 443 var precision = m[3];
436 info.align = flags.charAt(0); 444 var type = m[4];
437 flags = flags.substring(1); 445 var unmatched = m[5];
438 break; 446 for (var i = 0; flags && i < flags.length; i++) {
439 case "+": 447 var chr = flags.charAt(i);
440 case "-": 448 if (chr == "<" || chr == ">") {
441 case " ": 449 info.align = chr;
442 info.sign = flags.charAt(0); 450 } else if (chr == "+" || chr == "-" || chr == " ") {
443 flags = flags.substring(1); 451 info.sign = (chr == "-") ? "" : chr;
444 break; 452 } else if (chr == "0") {
445 case ",": 453 info.padding = chr;
446 info.grouping = true; 454 } else if (chr == ",") {
447 flags = flags.substring(1); 455 info.group = true;
448 break;
449 case ".":
450 var chars = /^\d*/.exec(flags.substring(1))[0];
451 info.precision = parseInt(chars);
452 flags = flags.substring(1 + chars.length);
453 break;
454 case "0":
455 info.padding = flags.charAt(0);
456 flags = flags.substring(1);
457 break;
458 case "1":
459 case "2":
460 case "3":
461 case "4":
462 case "5":
463 case "6":
464 case "7":
465 case "8":
466 case "9":
467 var chars = /^\d*/.exec(flags)[0];
468 info.width = parseInt(chars);
469 flags = flags.substring(chars.length);
470 break;
471 case "s":
472 case "r":
473 info.format = flags.charAt(0);
474 flags = flags.substring(1);
475 break;
476 case "b":
477 case "d":
478 case "o":
479 case "x":
480 case "X":
481 case "f":
482 case "%":
483 info.numeric = true;
484 info.format = flags.charAt(0);
485 info.radix = 10;
486 if (info.format === "b") {
487 info.radix = 2;
488 } else if (info.format === "o") {
489 info.radix = 8;
490 } else if (info.format === "x" || info.format === "X") {
491 info.radix = 16;
492 }
493 flags = flags.substring(1);
494 break;
495 default:
496 var msg = "unsupported format flag: " + flags.charAt(0);
497 throw new self.FormatPatternError(pattern, startPos, msg);
498 } 456 }
499 } 457 }
458 if (width) {
459 info.width = parseInt(width, 10);
460 }
461 if (precision && precision.length > 1) {
462 info.precision = parseInt(precision.substring(1), 10);
463 }
464 if (type == "s" || type == "r") {
465 info.format = type;
466 } else if (type == "b") {
467 update(info, { type: "number", format: type, radix: 2 });
468 } else if (type == "o") {
469 update(info, { type: "number", format: type, radix: 8 });
470 } else if (type == "x" || type == "X") {
471 update(info, { type: "number", format: type, radix: 16 });
472 } else if (type == "d" || type == "f" || type == "%") {
473 update(info, { type: "number", format: type, radix: 10 });
474 }
475 if (unmatched) {
476 var msg = "unsupported format flag: " + unmatched.charAt(0);
477 throw new MochiKit.Text.FormatPatternError(pattern, startPos, msg);
478 }
500 return info; 479 return info;
501} 480};
502 481
503/** 482/**
504 * Formats a value as a percentage. This method avoids multiplication 483 * Formats a value as a percentage. This method avoids multiplication
@@ -510,33 +489,23 @@ MochiKit.Text._parseFormatFlags = function (pattern, startPos, endPos) {
510 * @param {Number} precision the number of precision digits 489 * @param {Number} precision the number of precision digits
511 */ 490 */
512MochiKit.Text._truncToPercent = function (value, precision) { 491MochiKit.Text._truncToPercent = function (value, precision) {
513 // TODO: This can be simplified by using the same helper function 492 // TODO: This can be simplified by using MochiKit.Format._shiftNumber
514 // as roundToFixed now does. 493 // as roundToFixed does.
515 var str; 494 var str;
516 if (precision >= 0) { 495 if (precision >= 0) {
517 str = MochiKit.Format.roundToFixed(value, precision + 2); 496 str = MochiKit.Format.roundToFixed(value, precision + 2);
518 } else { 497 } else {
519 str = (value == null) ? "0" : value.toString(); 498 str = (value == null) ? "0" : value.toString();
520 } 499 }
521 var fracPos = str.indexOf("."); 500 var arr = MochiKit.Text.split(str, ".", 2);
522 if (fracPos < 0) { 501 var frac = MochiKit.Text.padRight(arr[1], 2, "0");
523 str = str + "00"; 502 var whole = arr[0] + frac.substring(0, 2);
524 } else if (fracPos + 3 >= str.length) { 503 frac = frac.substring(2);
525 var fraction = str.substring(fracPos + 1); 504 while (/^0[0-9]/.test(whole)) {
526 while (fraction.length < 2) { 505 whole = whole.substring(1);
527 fraction = fraction + "0";
528 }
529 str = str.substring(0, fracPos) + fraction;
530 } else {
531 var fraction = str.substring(fracPos + 1);
532 str = str.substring(0, fracPos) + fraction.substring(0, 2) +
533 "." + fraction.substring(2);
534 }
535 while (str.length > 1 && str.charAt(0) == "0" && str.charAt(1) != ".") {
536 str = str.substring(1);
537 } 506 }
538 return str; 507 return (frac.length <= 0) ? whole : whole + "." + frac;
539} 508};
540 509
541/** 510/**
542 * Creates a new format pattern error. 511 * Creates a new format pattern error.
@@ -558,13 +527,13 @@ MochiKit.Text.FormatPatternError = function (pattern, pos, message) {
558 this.pattern = pattern; 527 this.pattern = pattern;
559 this.pos = pos; 528 this.pos = pos;
560 this.message = message; 529 this.message = message;
561} 530};
562MochiKit.Text.FormatPatternError.prototype =
563 new MochiKit.Base.NamedError("MochiKit.Text.FormatPatternError");
564 531
532MochiKit.Text.FormatPatternError.prototype = new MochiKit.Base.NamedError("MochiKit.Text.FormatPatternError");
533MochiKit.Text.FormatPatternError.constructor = MochiKit.Text.FormatPatternError;
565 534
566// 535//
567//XXX: Internet Explorer exception handling blows 536//XXX: Internet Explorer export fix
568// 537//
569if (MochiKit.__export__) { 538if (MochiKit.__export__) {
570 formatter = MochiKit.Text.formatter; 539 formatter = MochiKit.Text.formatter;