[
  {
    "path": ".gitignore",
    "content": "/node_modules\n"
  },
  {
    "path": "LICENSE.MD",
    "content": "MIT License\n\nCopyright (c) 2019 Léon Gersen\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "wNumb\n=====\n\nwNumb - JavaScript Number &amp; Money formatting\n\n# Documentation\n\nDocumentation and examples are available on [refreshless.com/wnumb](https://refreshless.com/wnumb/).\n\n# Changelog\n\n### 1.2.0 (*2019-10-29*)\n- Changed: License is now MIT\n- Added: Prettier code formatter\n- Added: Minified version\n\n### 1.1.0 (*2017-02-04*)\n- Changed: Renamed `postfix` option to the proper `suffix`. `postfix` is remapped internally for backward compatibility;\n\n# License\n\nLicensed MIT, so free for personal and commercial use.\n"
  },
  {
    "path": "bower.json",
    "content": "{\n  \"name\": \"wnumb\",\n  \"main\": \"wNumb.js\",\n  \"version\": \"1.1.0\",\n  \"homepage\": \"https://refreshless.com/wnumb/\",\n  \"description\": \"wNumb - JavaScript Number & Money formatting\",\n  \"keywords\": [\n    \"javascript\",\n    \"js\",\n    \"number\",\n    \"money\",\n    \"formatting\"\n  ],\n  \"authors\": [\n    \"Leon Gersen\"\n  ],\n  \"license\": \"WTFPL\",\n  \"ignore\": [\n    \"**/.*\",\n    \"node_modules\",\n    \"bower_components\",\n    \"test\",\n    \"tests\"\n  ]\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"wnumb\",\n  \"version\": \"1.2.0\",\n  \"description\": \"wNumb - JavaScript Number & Money formatting\",\n  \"main\": \"wNumb.js\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/leongersen/wnumb.git\"\n  },\n  \"author\": \"leongersen\",\n  \"license\": \"MIT\",\n  \"scripts\": {\n    \"format\": \"prettier wNumb.js --write --print-width=120\",\n    \"minify\": \"uglifyjs wNumb.js --compress --mangle --output wNumb.min.js\",\n    \"build\": \"npm run format && npm run minify\"\n  },\n  \"files\": [\n    \"wNumb.js\",\n    \"wNumb.min.js\"\n  ],\n  \"bugs\": {\n    \"url\": \"https://github.com/leongersen/wnumb/issues\"\n  },\n  \"devDependencies\": {\n    \"prettier\": \"^1.18.2\",\n    \"uglify-js\": \"^3.6.5\"\n  }\n}\n"
  },
  {
    "path": "test.html",
    "content": "<!DOCTYPE html>\n\n\t<head>\n\t\t<link href=\"http://code.jquery.com/qunit/qunit-1.12.0.css\" rel=\"stylesheet\">\n\t\t<script src=\"http://code.jquery.com/qunit/qunit-1.12.0.js\"></script>\n\t\t<script src=\"wNumb.min.js\"></script>\n\t</head>\n\n\t<div id=\"qunit\"></div>\n\n\t<script>\n\n\t\ttest( \"Testing mark, thousand, decimals\", function(){\n\n\t\t\tvar Tester = wNumb({\n\t\t\t\tmark: '_',\n\t\t\t\tthousand: '?',\n\t\t\t\tdecimals: 3\n\t\t\t});\n\n\t\t\tequal ( Tester.to ( 9129 ), '9?129_000' );\n\t\t\tequal ( Tester.from ( '9?129_000' ), 9129 );\n\n\t\t\tequal ( Tester.to ( 100000000000.99999999 ), '100?000?000?001_000' );\n\t\t\tequal ( Tester.from ( '100?000?000?001_000' ), 100000000000.99999999 );\n\n\t\t\tequal ( Tester.to ( 7 ), '7_000' );\n\t\t\tequal ( Tester.from ( '7_000' ), 7 );\n\n\t\t\tequal ( Tester.to ( 'q' ), false );\n\n\t\t\tequal ( Tester.to ( 8000.001 ), '8?000_001' );\n\t\t\tequal ( Tester.from ( '8?000_001' ), 8000.001 );\n\n\t\t\tequal ( Tester.to ( -700 ), '-700_000' );\n\t\t\tequal ( Tester.from ( '-700_000' ), -700.000 );\n\n\t\t\tequal ( Tester.to ( -79900.0405 ), '-79?900_041' );\n\t\t\tequal ( Tester.from ( '-79?900_041' ), -79900.041 );\n\t\t});\n\n\t\ttest( \"Testing 0 decimals\", function(){\n\n\t\t\tvar Tester = wNumb({\n\t\t\t\tdecimals: 0\n\t\t\t});\n\n\t\t\tequal ( Tester.to ( -50.999845 ), '-51' );\n\t\t\tequal ( Tester.to ( -0.0000001 ), '0' );\n\t\t});\n\n\t\ttest( \"Testing rounding\", function(){\n\n\t\t\tvar Tester = wNumb({\n\t\t\t\tdecimals: 2\n\t\t\t});\n\n\t\t\tequal ( Tester.to ( 8.905 ), '8.91' );\n\t\t\tequal ( Tester.to ( 8.9049999 ), '8.90' );\n\t\t\tequal ( Tester.to ( 8.9045 ), '8.90' );\n\t\t\tequal ( Tester.to ( 8.9044 ), '8.90' );\n\t\t\tequal ( Tester.to ( 8.9 ), '8.90' );\n\t\t\tequal ( Tester.to ( 1.275 ), '1.28' );\n\t\t\tequal ( Tester.to ( 1.27499 ), '1.27' );\n\t\t});\n\n\t\ttest( \"Testing mark and thousand with longer strings\", function(){\n\n\t\t\tvar Tester = wNumb({\n\t\t\t\tmark: '/**',\n\t\t\t\tthousand: '-+A',\n\t\t\t\tdecimals: 2\n\t\t\t});\n\n\t\t\tequal ( Tester.to ( 450 ), '450/**00' );\n\t\t\tequal ( Tester.from ( '450/**00' ), 450.00 );\n\n\t\t\tequal ( Tester.to ( 80000 ), '80-+A000/**00' );\n\t\t\tequal ( Tester.from ( '80-+A000/**00' ), 80000 );\n\n\t\t});\n\n\t\ttest( \"Testing prefix and suffix\", function(){\n\n\t\t\tvar Tester = wNumb({\n\t\t\t\tprefix: '$',\n\t\t\t\tsuffix: ' p.p.',\n\t\t\t\tdecimals: 5\n\t\t\t});\n\n\t\t\tequal ( Tester.to ( 230.089044 ), '$230.08904 p.p.' );\n\t\t\tequal ( Tester.from ( '$230.08904 p.p.' ), 230.08904 );\n\n\t\t\tequal ( Tester.to ( 1 ), '$1.00000 p.p.' );\n\t\t\tequal ( Tester.from ( '$1.00000 p.p.' ), 1.00000 );\n\n\t\t\tequal ( Tester.to ( 16.5 ), '$16.50000 p.p.' );\n\n\t\t\tequal ( Tester.from ( '$1500' ), 1500 );\n\t\t\tequal ( Tester.from ( '1500' ), 1500 );\n\t\t\tequal ( Tester.from ( '1500 p.p.' ), 1500 );\n\t\t\tequal ( Tester.from ( '1500 ' ), 1500 );\n\t\t\tequal ( Tester.from ( '  1500 ' ), 1500 );\n\t\t\tequal ( Tester.from ( ' 1.50.0 ' ), false );\n\n\t\t\tvar Tester2 = wNumb({\n\t\t\t\tpostfix: ' postfix!',\n\t\t\t\tdecimals: 1\n\t\t\t});\n\n\t\t\tequal ( Tester2.to ( 1 ), '1.0 postfix!' );\n\t\t});\n\n\t\ttest( \"Testing prefix and with negativeBefore\", function(){\n\n\t\t\tvar Tester = wNumb({\n\t\t\t\tprefix: '$',\n\t\t\t\tnegativeBefore: '[NEGATIVE] '\n\t\t\t});\n\n\t\t\tequal ( Tester.to ( 260 ), '$260' );\n\t\t\tequal ( Tester.from ( '$260' ), 260 );\n\n\t\t\tequal ( Tester.to ( -260 ), '[NEGATIVE] $260' );\n\t\t\tequal ( Tester.from ( '[NEGATIVE] $260' ), -260 );\n\n\t\t});\n\n\t\ttest( \"Testing prefix and with negative\", function(){\n\n\t\t\tvar Tester = wNumb({\n\t\t\t\tprefix: 'Price: '\n\t\t\t});\n\n\t\t\tequal ( Tester.to ( 380.6 ), 'Price: 380.6' );\n\t\t\tequal ( Tester.from ( 'Price: 380.6' ), 380.6 );\n\n\t\t\tequal ( Tester.to ( -9506 ), 'Price: -9506' );\n\t\t\tequal ( Tester.from ( 'Price: -9506' ), -9506 );\n\n\t\t});\n\n\t\ttest( \"Testing encoder, decoder\", function(){\n\n\t\t\tvar Tester = wNumb({\n\t\t\t\tthousand: '.',\n\t\t\t\tencoder: function( a ){\n\t\t\t\t\treturn a * 1E7;\n\t\t\t\t},\n\t\t\t\tdecoder: function( a ){\n\t\t\t\t\treturn a / 1E7;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tequal ( Tester.to ( 10 ), '100.000.000' );\n\t\t\tequal ( Tester.from ( '100.000.000' ), 10 );\n\n\t\t\tequal ( Tester.to ( -9506 ), '-95.060.000.000' );\n\t\t\tequal ( Tester.from ( '-95.060.000.000' ), -9506 );\n\n\t\t});\n\n\t\ttest( \"Testing edit, undo\", function(){\n\n\t\t\tvar Tester = wNumb({\n\t\t\t\tedit: function( value, originalValue ){\n\t\t\t\t\tif ( originalValue > 100000 ) {\n\t\t\t\t\t\treturn value + 'm';\n\t\t\t\t\t} else if ( originalValue > 1000 ) {\n\t\t\t\t\t\treturn value + 'k';\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn value;\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tundo: function( value ){\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tequal ( Tester.to ( 15000 ), '15000k' );\n\t\t\tequal ( Tester.from ( '15000k' ), 15000 );\n\n\t\t\tequal ( Tester.to ( 180 ), '180' );\n\t\t\tequal ( Tester.from ( '180' ), 180 );\n\n\t\t\tequal ( Tester.to ( 1058009 ), '1058009m' );\n\t\t});\n\n\t</script>\n"
  },
  {
    "path": "wNumb.js",
    "content": "(function(factory) {\n  if (typeof define === \"function\" && define.amd) {\n    // AMD. Register as an anonymous module.\n    define([], factory);\n  } else if (typeof exports === \"object\") {\n    // Node/CommonJS\n    module.exports = factory();\n  } else {\n    // Browser globals\n    window.wNumb = factory();\n  }\n})(function() {\n  \"use strict\";\n\n  var FormatOptions = [\n    \"decimals\",\n    \"thousand\",\n    \"mark\",\n    \"prefix\",\n    \"suffix\",\n    \"encoder\",\n    \"decoder\",\n    \"negativeBefore\",\n    \"negative\",\n    \"edit\",\n    \"undo\"\n  ];\n\n  // General\n\n  // Reverse a string\n  function strReverse(a) {\n    return a\n      .split(\"\")\n      .reverse()\n      .join(\"\");\n  }\n\n  // Check if a string starts with a specified prefix.\n  function strStartsWith(input, match) {\n    return input.substring(0, match.length) === match;\n  }\n\n  // Check is a string ends in a specified suffix.\n  function strEndsWith(input, match) {\n    return input.slice(-1 * match.length) === match;\n  }\n\n  // Throw an error if formatting options are incompatible.\n  function throwEqualError(F, a, b) {\n    if ((F[a] || F[b]) && F[a] === F[b]) {\n      throw new Error(a);\n    }\n  }\n\n  // Check if a number is finite and not NaN\n  function isValidNumber(input) {\n    return typeof input === \"number\" && isFinite(input);\n  }\n\n  // Provide rounding-accurate toFixed method.\n  // Borrowed: http://stackoverflow.com/a/21323330/775265\n  function toFixed(value, exp) {\n    value = value.toString().split(\"e\");\n    value = Math.round(+(value[0] + \"e\" + (value[1] ? +value[1] + exp : exp)));\n    value = value.toString().split(\"e\");\n    return (+(value[0] + \"e\" + (value[1] ? +value[1] - exp : -exp))).toFixed(exp);\n  }\n\n  // Formatting\n\n  // Accept a number as input, output formatted string.\n  function formatTo(\n    decimals,\n    thousand,\n    mark,\n    prefix,\n    suffix,\n    encoder,\n    decoder,\n    negativeBefore,\n    negative,\n    edit,\n    undo,\n    input\n  ) {\n    var originalInput = input,\n      inputIsNegative,\n      inputPieces,\n      inputBase,\n      inputDecimals = \"\",\n      output = \"\";\n\n    // Apply user encoder to the input.\n    // Expected outcome: number.\n    if (encoder) {\n      input = encoder(input);\n    }\n\n    // Stop if no valid number was provided, the number is infinite or NaN.\n    if (!isValidNumber(input)) {\n      return false;\n    }\n\n    // Rounding away decimals might cause a value of -0\n    // when using very small ranges. Remove those cases.\n    if (decimals !== false && parseFloat(input.toFixed(decimals)) === 0) {\n      input = 0;\n    }\n\n    // Formatting is done on absolute numbers,\n    // decorated by an optional negative symbol.\n    if (input < 0) {\n      inputIsNegative = true;\n      input = Math.abs(input);\n    }\n\n    // Reduce the number of decimals to the specified option.\n    if (decimals !== false) {\n      input = toFixed(input, decimals);\n    }\n\n    // Transform the number into a string, so it can be split.\n    input = input.toString();\n\n    // Break the number on the decimal separator.\n    if (input.indexOf(\".\") !== -1) {\n      inputPieces = input.split(\".\");\n\n      inputBase = inputPieces[0];\n\n      if (mark) {\n        inputDecimals = mark + inputPieces[1];\n      }\n    } else {\n      // If it isn't split, the entire number will do.\n      inputBase = input;\n    }\n\n    // Group numbers in sets of three.\n    if (thousand) {\n      inputBase = strReverse(inputBase).match(/.{1,3}/g);\n      inputBase = strReverse(inputBase.join(strReverse(thousand)));\n    }\n\n    // If the number is negative, prefix with negation symbol.\n    if (inputIsNegative && negativeBefore) {\n      output += negativeBefore;\n    }\n\n    // Prefix the number\n    if (prefix) {\n      output += prefix;\n    }\n\n    // Normal negative option comes after the prefix. Defaults to '-'.\n    if (inputIsNegative && negative) {\n      output += negative;\n    }\n\n    // Append the actual number.\n    output += inputBase;\n    output += inputDecimals;\n\n    // Apply the suffix.\n    if (suffix) {\n      output += suffix;\n    }\n\n    // Run the output through a user-specified post-formatter.\n    if (edit) {\n      output = edit(output, originalInput);\n    }\n\n    // All done.\n    return output;\n  }\n\n  // Accept a sting as input, output decoded number.\n  function formatFrom(\n    decimals,\n    thousand,\n    mark,\n    prefix,\n    suffix,\n    encoder,\n    decoder,\n    negativeBefore,\n    negative,\n    edit,\n    undo,\n    input\n  ) {\n    var originalInput = input,\n      inputIsNegative,\n      output = \"\";\n\n    // User defined pre-decoder. Result must be a non empty string.\n    if (undo) {\n      input = undo(input);\n    }\n\n    // Test the input. Can't be empty.\n    if (!input || typeof input !== \"string\") {\n      return false;\n    }\n\n    // If the string starts with the negativeBefore value: remove it.\n    // Remember is was there, the number is negative.\n    if (negativeBefore && strStartsWith(input, negativeBefore)) {\n      input = input.replace(negativeBefore, \"\");\n      inputIsNegative = true;\n    }\n\n    // Repeat the same procedure for the prefix.\n    if (prefix && strStartsWith(input, prefix)) {\n      input = input.replace(prefix, \"\");\n    }\n\n    // And again for negative.\n    if (negative && strStartsWith(input, negative)) {\n      input = input.replace(negative, \"\");\n      inputIsNegative = true;\n    }\n\n    // Remove the suffix.\n    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice\n    if (suffix && strEndsWith(input, suffix)) {\n      input = input.slice(0, -1 * suffix.length);\n    }\n\n    // Remove the thousand grouping.\n    if (thousand) {\n      input = input.split(thousand).join(\"\");\n    }\n\n    // Set the decimal separator back to period.\n    if (mark) {\n      input = input.replace(mark, \".\");\n    }\n\n    // Prepend the negative symbol.\n    if (inputIsNegative) {\n      output += \"-\";\n    }\n\n    // Add the number\n    output += input;\n\n    // Trim all non-numeric characters (allow '.' and '-');\n    output = output.replace(/[^0-9\\.\\-.]/g, \"\");\n\n    // The value contains no parse-able number.\n    if (output === \"\") {\n      return false;\n    }\n\n    // Covert to number.\n    output = Number(output);\n\n    // Run the user-specified post-decoder.\n    if (decoder) {\n      output = decoder(output);\n    }\n\n    // Check is the output is valid, otherwise: return false.\n    if (!isValidNumber(output)) {\n      return false;\n    }\n\n    return output;\n  }\n\n  // Framework\n\n  // Validate formatting options\n  function validate(inputOptions) {\n    var i,\n      optionName,\n      optionValue,\n      filteredOptions = {};\n\n    if (inputOptions[\"suffix\"] === undefined) {\n      inputOptions[\"suffix\"] = inputOptions[\"postfix\"];\n    }\n\n    for (i = 0; i < FormatOptions.length; i += 1) {\n      optionName = FormatOptions[i];\n      optionValue = inputOptions[optionName];\n\n      if (optionValue === undefined) {\n        // Only default if negativeBefore isn't set.\n        if (optionName === \"negative\" && !filteredOptions.negativeBefore) {\n          filteredOptions[optionName] = \"-\";\n          // Don't set a default for mark when 'thousand' is set.\n        } else if (optionName === \"mark\" && filteredOptions.thousand !== \".\") {\n          filteredOptions[optionName] = \".\";\n        } else {\n          filteredOptions[optionName] = false;\n        }\n\n        // Floating points in JS are stable up to 7 decimals.\n      } else if (optionName === \"decimals\") {\n        if (optionValue >= 0 && optionValue < 8) {\n          filteredOptions[optionName] = optionValue;\n        } else {\n          throw new Error(optionName);\n        }\n\n        // These options, when provided, must be functions.\n      } else if (\n        optionName === \"encoder\" ||\n        optionName === \"decoder\" ||\n        optionName === \"edit\" ||\n        optionName === \"undo\"\n      ) {\n        if (typeof optionValue === \"function\") {\n          filteredOptions[optionName] = optionValue;\n        } else {\n          throw new Error(optionName);\n        }\n\n        // Other options are strings.\n      } else {\n        if (typeof optionValue === \"string\") {\n          filteredOptions[optionName] = optionValue;\n        } else {\n          throw new Error(optionName);\n        }\n      }\n    }\n\n    // Some values can't be extracted from a\n    // string if certain combinations are present.\n    throwEqualError(filteredOptions, \"mark\", \"thousand\");\n    throwEqualError(filteredOptions, \"prefix\", \"negative\");\n    throwEqualError(filteredOptions, \"prefix\", \"negativeBefore\");\n\n    return filteredOptions;\n  }\n\n  // Pass all options as function arguments\n  function passAll(options, method, input) {\n    var i,\n      args = [];\n\n    // Add all options in order of FormatOptions\n    for (i = 0; i < FormatOptions.length; i += 1) {\n      args.push(options[FormatOptions[i]]);\n    }\n\n    // Append the input, then call the method, presenting all\n    // options as arguments.\n    args.push(input);\n    return method.apply(\"\", args);\n  }\n\n  function wNumb(options) {\n    if (!(this instanceof wNumb)) {\n      return new wNumb(options);\n    }\n\n    if (typeof options !== \"object\") {\n      return;\n    }\n\n    options = validate(options);\n\n    // Call 'formatTo' with proper arguments.\n    this.to = function(input) {\n      return passAll(options, formatTo, input);\n    };\n\n    // Call 'formatFrom' with proper arguments.\n    this.from = function(input) {\n      return passAll(options, formatFrom, input);\n    };\n  }\n\n  return wNumb;\n});\n"
  }
]