1 // Copyright 2013 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 // limitations under the License. 28 29 // ECMAScript 402 API implementation is broken into separate files for 30 // each service. The build system combines them together into one 31 // Intl namespace. 32 33 34 // Save references to Intl objects and methods we use, for added security. 35 var savedObjects = { 36 'collator': Intl.Collator, 37 'numberformat': Intl.NumberFormat, 38 'dateformatall': Intl.DateTimeFormat, 39 'dateformatdate': Intl.DateTimeFormat, 40 'dateformattime': Intl.DateTimeFormat 41 }; 42 43 44 // Default (created with undefined locales and options parameters) collator, 45 // number and date format instances. They'll be created as needed. 46 var defaultObjects = { 47 'collator': undefined, 48 'numberformat': undefined, 49 'dateformatall': undefined, 50 'dateformatdate': undefined, 51 'dateformattime': undefined, 52 }; 53 54 55 /** 56 * Returns cached or newly created instance of a given service. 57 * We cache only default instances (where no locales or options are provided). 58 */ 59 function cachedOrNewService(service, locales, options, defaults) { 60 var useOptions = (defaults === undefined) ? options : defaults; 61 if (locales === undefined && options === undefined) { 62 if (defaultObjects[service] === undefined) { 63 defaultObjects[service] = new savedObjects[service](locales, useOptions); 64 } 65 return defaultObjects[service]; 66 } 67 return new savedObjects[service](locales, useOptions); 68 } 69 70 71 /** 72 * Compares this and that, and returns less than 0, 0 or greater than 0 value. 73 * Overrides the built-in method. 74 */ 75 Object.defineProperty(String.prototype, 'localeCompare', { 76 value: function(that) { 77 if (%_IsConstructCall()) { 78 throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR); 79 } 80 81 if (this === undefined || this === null) { 82 throw new TypeError('Method invoked on undefined or null value.'); 83 } 84 85 var locales = arguments[1]; 86 var options = arguments[2]; 87 var collator = cachedOrNewService('collator', locales, options); 88 return compare(collator, this, that); 89 }, 90 writable: true, 91 configurable: true, 92 enumerable: false 93 }); 94 %FunctionSetName(String.prototype.localeCompare, 'localeCompare'); 95 %FunctionRemovePrototype(String.prototype.localeCompare); 96 %SetNativeFlag(String.prototype.localeCompare); 97 98 99 /** 100 * Formats a Number object (this) using locale and options values. 101 * If locale or options are omitted, defaults are used. 102 */ 103 Object.defineProperty(Number.prototype, 'toLocaleString', { 104 value: function() { 105 if (%_IsConstructCall()) { 106 throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR); 107 } 108 109 if (!(this instanceof Number) && typeof(this) !== 'number') { 110 throw new TypeError('Method invoked on an object that is not Number.'); 111 } 112 113 var locales = arguments[0]; 114 var options = arguments[1]; 115 var numberFormat = cachedOrNewService('numberformat', locales, options); 116 return formatNumber(numberFormat, this); 117 }, 118 writable: true, 119 configurable: true, 120 enumerable: false 121 }); 122 %FunctionSetName(Number.prototype.toLocaleString, 'toLocaleString'); 123 %FunctionRemovePrototype(Number.prototype.toLocaleString); 124 %SetNativeFlag(Number.prototype.toLocaleString); 125 126 127 /** 128 * Returns actual formatted date or fails if date parameter is invalid. 129 */ 130 function toLocaleDateTime(date, locales, options, required, defaults, service) { 131 if (!(date instanceof Date)) { 132 throw new TypeError('Method invoked on an object that is not Date.'); 133 } 134 135 if (isNaN(date)) { 136 return 'Invalid Date'; 137 } 138 139 var internalOptions = toDateTimeOptions(options, required, defaults); 140 141 var dateFormat = 142 cachedOrNewService(service, locales, options, internalOptions); 143 144 return formatDate(dateFormat, date); 145 } 146 147 148 /** 149 * Formats a Date object (this) using locale and options values. 150 * If locale or options are omitted, defaults are used - both date and time are 151 * present in the output. 152 */ 153 Object.defineProperty(Date.prototype, 'toLocaleString', { 154 value: function() { 155 if (%_IsConstructCall()) { 156 throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR); 157 } 158 159 var locales = arguments[0]; 160 var options = arguments[1]; 161 return toLocaleDateTime( 162 this, locales, options, 'any', 'all', 'dateformatall'); 163 }, 164 writable: true, 165 configurable: true, 166 enumerable: false 167 }); 168 %FunctionSetName(Date.prototype.toLocaleString, 'toLocaleString'); 169 %FunctionRemovePrototype(Date.prototype.toLocaleString); 170 %SetNativeFlag(Date.prototype.toLocaleString); 171 172 173 /** 174 * Formats a Date object (this) using locale and options values. 175 * If locale or options are omitted, defaults are used - only date is present 176 * in the output. 177 */ 178 Object.defineProperty(Date.prototype, 'toLocaleDateString', { 179 value: function() { 180 if (%_IsConstructCall()) { 181 throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR); 182 } 183 184 var locales = arguments[0]; 185 var options = arguments[1]; 186 return toLocaleDateTime( 187 this, locales, options, 'date', 'date', 'dateformatdate'); 188 }, 189 writable: true, 190 configurable: true, 191 enumerable: false 192 }); 193 %FunctionSetName(Date.prototype.toLocaleDateString, 'toLocaleDateString'); 194 %FunctionRemovePrototype(Date.prototype.toLocaleDateString); 195 %SetNativeFlag(Date.prototype.toLocaleDateString); 196 197 198 /** 199 * Formats a Date object (this) using locale and options values. 200 * If locale or options are omitted, defaults are used - only time is present 201 * in the output. 202 */ 203 Object.defineProperty(Date.prototype, 'toLocaleTimeString', { 204 value: function() { 205 if (%_IsConstructCall()) { 206 throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR); 207 } 208 209 var locales = arguments[0]; 210 var options = arguments[1]; 211 return toLocaleDateTime( 212 this, locales, options, 'time', 'time', 'dateformattime'); 213 }, 214 writable: true, 215 configurable: true, 216 enumerable: false 217 }); 218 %FunctionSetName(Date.prototype.toLocaleTimeString, 'toLocaleTimeString'); 219 %FunctionRemovePrototype(Date.prototype.toLocaleTimeString); 220 %SetNativeFlag(Date.prototype.toLocaleTimeString); 221