vendor: 8,209 bytes, lines 1-335
1(function(){ 2 3 'use strict'; 4 5var 6/** @const */ FormatOptions = [ 7 'decimals', 8 'thousand', 9 'mark', 10 'prefix', 11 'postfix', 12 'encoder', 13 'decoder', 14 'negativeBefore', 15 'negative', 16 'edit', 17 'undo' 18]; 19 20// General 21 22 // Reverse a string 23 function strReverse ( a ) { 24 return a.split('').reverse().join(''); 25 } 26 27 // Check if a string starts with a specified prefix. 28 function strStartsWith ( input, match ) { 29 return input.substring(0, match.length) === match; 30 } 31 32 // Check is a string ends in a specified postfix. 33 function strEndsWith ( input, match ) { 34 return input.slice(-1 * match.length) === match; 35 } 36 37 // Throw an error if formatting options are incompatible. 38 function throwEqualError( F, a, b ) { 39 if ( (F[a] || F[b]) && (F[a] === F[b]) ) { 40 throw new Error(a); 41 } 42 } 43 44 // Check if a number is finite and not NaN 45 function isValidNumber ( input ) { 46 return typeof input === 'number' && isFinite( input ); 47 } 48 49 // Provide rounding-accurate toFixed method. 50 function toFixed ( value, decimals ) { 51 var scale = Math.pow(10, decimals); 52 return ( Math.round(value * scale) / scale).toFixed( decimals ); 53 } 54 55 56// Formatting 57 58 // Accept a number as input, output formatted string. 59 function formatTo ( decimals, thousand, mark, prefix, postfix, encoder, decoder, negativeBefore, negative, edit, undo, input ) { 60 61 var originalInput = input, inputIsNegative, inputPieces, inputBase, inputDecimals = '', output = ''; 62 63 // Apply user encoder to the input. 64 // Expected outcome: number. 65 if ( encoder ) { 66 input = encoder(input); 67 } 68 69 // Stop if no valid number was provided, the number is infinite or NaN. 70 if ( !isValidNumber(input) ) { 71 return false; 72 } 73 74 // Rounding away decimals might cause a value of -0 75 // when using very small ranges. Remove those cases. 76 if ( decimals !== false && parseFloat(input.toFixed(decimals)) === 0 ) { 77 input = 0; 78 } 79 80 // Formatting is done on absolute numbers, 81 // decorated by an optional negative symbol. 82 if ( input < 0 ) { 83 inputIsNegative = true; 84 input = Math.abs(input); 85 } 86 87 // Reduce the number of decimals to the specified option. 88 if ( decimals !== false ) { 89 input = toFixed( input, decimals ); 90 } 91 92 // Transform the number into a string, so it can be split. 93 input = input.toString(); 94 95 // Break the number on the decimal separator. 96 if ( input.indexOf('.') !== -1 ) { 97 inputPieces = input.split('.'); 98 99 inputBase = inputPieces[0]; 100 101 if ( mark ) { 102 inputDecimals = mark + inputPieces[1]; 103 } 104 105 } else { 106 107 // If it isn't split, the entire number will do. 108 inputBase = input; 109 } 110 111 // Group numbers in sets of three. 112 if ( thousand ) { 113 inputBase = strReverse(inputBase).match(/.{1,3}/g); 114 inputBase = strReverse(inputBase.join( strReverse( thousand ) )); 115 } 116 117 // If the number is negative, prefix with negation symbol. 118 if ( inputIsNegative && negativeBefore ) { 119 output += negativeBefore; 120 } 121 122 // Prefix the number 123 if ( prefix ) { 124 output += prefix; 125 } 126 127 // Normal negative option comes after the prefix. Defaults to '-'. 128 if ( inputIsNegative && negative ) { 129 output += negative; 130 } 131 132 // Append the actual number. 133 output += inputBase; 134 output += inputDecimals; 135 136 // Apply the postfix. 137 if ( postfix ) { 138 output += postfix; 139 } 140 141 // Run the output through a user-specified post-formatter. 142 if ( edit ) { 143 output = edit ( output, originalInput ); 144 } 145 146 // All done. 147 return output; 148 } 149 150 // Accept a sting as input, output decoded number. 151 function formatFrom ( decimals, thousand, mark, prefix, postfix, encoder, decoder, negativeBefore, negative, edit, undo, input ) { 152 153 var originalInput = input, inputIsNegative, output = ''; 154 155 // User defined pre-decoder. Result must be a non empty string. 156 if ( undo ) { 157 input = undo(input); 158 } 159 160 // Test the input. Can't be empty. 161 if ( !input || typeof input !== 'string' ) { 162 return false; 163 } 164 165 // If the string starts with the negativeBefore value: remove it. 166 // Remember is was there, the number is negative. 167 if ( negativeBefore && strStartsWith(input, negativeBefore) ) { 168 input = input.replace(negativeBefore, ''); 169 inputIsNegative = true; 170 } 171 172 // Repeat the same procedure for the prefix. 173 if ( prefix && strStartsWith(input, prefix) ) { 174 input = input.replace(prefix, ''); 175 } 176 177 // And again for negative. 178 if ( negative && strStartsWith(input, negative) ) { 179 input = input.replace(negative, ''); 180 inputIsNegative = true; 181 } 182 183 // Remove the postfix. 184 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice 185 if ( postfix && strEndsWith(input, postfix) ) { 186 input = input.slice(0, -1 * postfix.length); 187 } 188 189 // Remove the thousand grouping. 190 if ( thousand ) { 191 input = input.split(thousand).join(''); 192 } 193 194 // Set the decimal separator back to period. 195 if ( mark ) { 196 input = input.replace(mark, '.'); 197 } 198 199 // Prepend the negative symbol. 200 if ( inputIsNegative ) { 201 output += '-'; 202 } 203 204 // Add the number 205 output += input; 206 207 // Trim all non-numeric characters (allow '.' and '-'); 208 output = output.replace(/[^0-9\.\-.]/g, ''); 209 210 // The value contains no parse-able number. 211 if ( output === '' ) { 212 return false; 213 } 214 215 // Covert to number. 216 output = Number(output); 217 218 // Run the user-specified post-decoder. 219 if ( decoder ) { 220 output = decoder(output); 221 } 222 223 // Check is the output is valid, otherwise: return false. 224 if ( !isValidNumber(output) ) { 225 return false; 226 } 227 228 return output; 229 } 230 231 232// Framework 233 234 // Validate formatting options 235 function validate ( inputOptions ) { 236 237 var i, optionName, optionValue, 238 filteredOptions = {}; 239 240 for ( i = 0; i < FormatOptions.length; i+=1 ) { 241 242 optionName = FormatOptions[i]; 243 optionValue = inputOptions[optionName]; 244 245 if ( optionValue === undefined ) { 246 247 // Only default if negativeBefore isn't set. 248 if ( optionName === 'negative' && !filteredOptions.negativeBefore ) { 249 filteredOptions[optionName] = '-'; 250 // Don't set a default for mark when 'thousand' is set. 251 } else if ( optionName === 'mark' && filteredOptions.thousand !== '.' ) { 252 filteredOptions[optionName] = '.'; 253 } else { 254 filteredOptions[optionName] = false; 255 } 256 257 // Floating points in JS are stable up to 7 decimals. 258 } else if ( optionName === 'decimals' ) { 259 if ( optionValue >= 0 && optionValue < 8 ) { 260 filteredOptions[optionName] = optionValue; 261 } else { 262 throw new Error(optionName); 263 } 264 265 // These options, when provided, must be functions. 266 } else if ( optionName === 'encoder' || optionName === 'decoder' || optionName === 'edit' || optionName === 'undo' ) { 267 if ( typeof optionValue === 'function' ) { 268 filteredOptions[optionName] = optionValue; 269 } else { 270 throw new Error(optionName); 271 } 272 273 // Other options are strings. 274 } else { 275 276 if ( typeof optionValue === 'string' ) { 277 filteredOptions[optionName] = optionValue; 278 } else { 279 throw new Error(optionName); 280 } 281 } 282 } 283 284 // Some values can't be extracted from a 285 // string if certain combinations are present. 286 throwEqualError(filteredOptions, 'mark', 'thousand'); 287 throwEqualError(filteredOptions, 'prefix', 'negative'); 288 throwEqualError(filteredOptions, 'prefix', 'negativeBefore'); 289 290 return filteredOptions; 291 } 292 293 // Pass all options as function arguments 294 function passAll ( options, method, input ) { 295 var i, args = []; 296 297 // Add all options in order of FormatOptions 298 for ( i = 0; i < FormatOptions.length; i+=1 ) { 299 args.push(options[FormatOptions[i]]); 300 } 301 302 // Append the input, then call the method, presenting all 303 // options as arguments. 304 args.push(input); 305 return method.apply('', args); 306 } 307 308 /** @constructor */ 309 function wNumb ( options ) { 310 311 if ( !(this instanceof wNumb) ) { 312 return new wNumb ( options ); 313 } 314 315 if ( typeof options !== "object" ) { 316 return; 317 } 318 319 options = validate(options); 320 321 // Call 'formatTo' with proper arguments. 322 this.to = function ( input ) { 323 return passAll(options, formatTo, input); 324 }; 325 326 // Call 'formatFrom' with proper arguments. 327 this.from = function ( input ) { 328 return passAll(options, formatFrom, input); 329 }; 330 } 331 332 /** @export */ 333 window.wNumb = wNumb; 334 335}());
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.