1 // ========================================================================== 2 // Project: SproutCore Costello - Property Observing Library 3 // Copyright: ©2006-2011 Strobe Inc. and contributors. 4 // Portions ©2008-2011 Apple Inc. All rights reserved. 5 // License: Licensed under MIT license (see license.js) 6 // ========================================================================== 7 8 /** 9 @class 10 11 Implements support methods useful when working with strings in SproutCore 12 applications. 13 */ 14 SC.String = /** @scope SC.String.prototype */ { 15 16 /** 17 This finds the value for a key in a formatting string. 18 19 Keys take the form: 20 21 key[:argument to formatter] 22 */ 23 _scs_valueForKey: function(key, data, /* for debugging purposes: */ string) { 24 var arg, value, formatter, argsplit = key.indexOf(':'); 25 if (argsplit > -1) { 26 arg = key.substr(argsplit + 1); 27 key = key.substr(0, argsplit); 28 } 29 30 value = data.get ? data.get(key): data[key]; 31 formatter = data[key + 'Formatter']; 32 33 // formatters are optional 34 if (formatter) value = formatter(value, arg); 35 else if (arg) { 36 throw new Error("String.fmt was given a formatting string, but key `" + key + "` has no formatter! String: " + string); 37 } 38 39 return value; 40 }, 41 42 /** 43 Formats a string. You can format either with named parameters or 44 indexed, but not both. 45 46 Indexed Parameters 47 -------------------- 48 Indexed parameters are just arguments you pass into format. For example: 49 50 "%@1 %@3 %@2".fmt(1, 2, 3) 51 52 // -> "1 3 2" 53 54 If you don't supply a number, it will use them in the order you supplied. For example: 55 56 "%@, %@".fmt("Iskander", "Alex") 57 58 // -> "Iskander, Alex" 59 60 Named Paramters 61 -------------------- 62 You can use named parameters like this: 63 64 "Value: %{key_name}".fmt({ key_name: "A Value" }) 65 66 // -> "Value: A Value" 67 68 You can supply formatters for each field. A formatter is a method to get applied 69 to the parameter: 70 71 Currency = function(v) { return "$" + v; }; 72 "Value: %{val}".fmt({ val: 12.00, valFormatter: Currency }) 73 74 // -> $12.00 75 76 Formatters can also use arguments: 77 78 Currency = function(v, sign) { return sign + v; }; 79 "Value: %{val:£}".fmt({ val: 12.00, valFormatter: Currency }) 80 81 // -> £12.00 82 83 You can supply a different formatter for each named parameter. Formatters can ONLY be 84 used with named parameters (not indexed parameters). 85 86 */ 87 fmt: function(string, args) { 88 var i = 0, data, hasHadNamedArguments; 89 if (args) { 90 data = args[0]; 91 } 92 93 return string.replace(/%\{(.*?)\}/g, function(match, propertyPath) { 94 hasHadNamedArguments = YES; 95 if (!data) { 96 throw new Error("Cannot use named parameters with `fmt` without a data hash. String: '" + string + "'"); 97 } 98 99 var ret = SC.String._scs_valueForKey(propertyPath, data, string); 100 // If a value was found, return that; otherwise return the original matched text to retain it in the string 101 // for future formatting. 102 if (!SC.none(ret)) { return ret; } 103 else { return match; } 104 }).replace(/%@([0-9]+)?/g, function(match, index) { 105 if (hasHadNamedArguments) { 106 throw new Error("Invalid attempt to use both named parameters and indexed parameters. String: '" + string + "'"); 107 } 108 index = index ? parseInt(index, 10) - 1 : i++; 109 if(args[index]!==undefined) return args[index]; 110 else return ""; 111 }); 112 }, 113 114 /** 115 Splits the string into words, separated by spaces. Empty strings are 116 removed from the results. 117 118 @returns {Array} An array of non-empty strings 119 */ 120 w: function(str) { 121 var ary = [], ary2 = str.split(' '), len = ary2.length, string, idx=0; 122 for (idx=0; idx<len; ++idx) { 123 string = ary2[idx] ; 124 if (string.length !== 0) ary.push(string) ; // skip empty strings 125 } 126 return ary ; 127 } 128 }; 129