├── .eslintignore ├── .eslintrc ├── .gitattributes ├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ └── issue-report.md ├── .gitignore ├── .npmrc ├── .prettierignore ├── .prettierrc.json ├── .vscode ├── launch.json └── settings.json ├── Changelog.md ├── Gruntfile.js ├── LICENSE.txt ├── README.md ├── bower.json ├── bundle.colormask.js ├── bundle.jquery.js ├── bundle.js ├── composer.json ├── dist ├── bindings │ └── inputmask.binding.js ├── colormask.css ├── colormask.js ├── colormask.min.js ├── inputmask.es6.js ├── inputmask.js ├── inputmask.min.js ├── jquery.inputmask.js └── jquery.inputmask.min.js ├── index.html ├── inputmask-pages ├── .env ├── .eslintrc.json ├── .gitignore ├── .prettierignore ├── .prettierrc.json ├── .vscode │ └── launch.json ├── README.md ├── generate-react-cli.json ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ ├── manifest.json │ └── robots.txt └── src │ ├── App.js │ ├── App.module.scss │ ├── App.test.js │ ├── Components │ ├── Changelog │ │ ├── Changelog.js │ │ ├── Changelog.lazy.js │ │ ├── Changelog.module.scss │ │ └── ChangelogToc.js │ ├── Colormask │ │ ├── Colormask.js │ │ ├── Colormask.lazy.js │ │ ├── Colormask.module.scss │ │ └── ColormaskToc.js │ ├── DatetimeAlias │ │ ├── DatetimeAlias.js │ │ ├── DatetimeAlias.lazy.js │ │ ├── DatetimeAlias.module.scss │ │ └── DatetimeAliasToc.js │ ├── Demo │ │ ├── Demo.js │ │ ├── Demo.lazy.js │ │ └── Demo.module.scss │ ├── DemoMask │ │ ├── DemoMask.js │ │ ├── DemoMask.lazy.js │ │ └── DemoMask.module.scss │ ├── Documentation │ │ ├── Documentation.js │ │ ├── Documentation.lazy.js │ │ ├── Documentation.module.scss │ │ ├── DocumentationToc.js │ │ └── DocumentationToc.module scss │ ├── Extensions │ │ ├── Extensions.js │ │ ├── Extensions.lazy.js │ │ ├── Extensions.module.scss │ │ └── ExtensionsToc.js │ ├── Footer │ │ ├── Footer.js │ │ ├── Footer.lazy.js │ │ ├── Footer.module.scss │ │ └── Footer.test.js │ ├── Header │ │ ├── Header.js │ │ ├── Header.lazy.js │ │ └── Header.module.scss │ ├── Introduction │ │ ├── Introduction.js │ │ ├── Introduction.lazy.js │ │ └── Introduction.module.scss │ ├── MarkDownPage │ │ ├── MarkDownPage.js │ │ ├── MarkDownPage.lazy.js │ │ ├── MarkDownPage.module.scss │ │ └── MarkDownPageContext.js │ ├── Navigation │ │ ├── Navigation.js │ │ ├── Navigation.lazy.js │ │ └── Navigation.module.scss │ ├── NumericAlias │ │ ├── NumericAlias.js │ │ ├── NumericAlias.lazy.js │ │ ├── NumericAlias.module.scss │ │ └── NumericAliasToc.js │ ├── Toc │ │ ├── Toc.js │ │ ├── Toc.lazy.js │ │ └── Toc.module.scss │ └── ViewPort │ │ ├── ViewPort.js │ │ └── ViewPortContext.js │ ├── ErrorBoundary.js │ ├── RoutingProvider.js │ ├── Shared │ ├── HashFragments.js │ ├── RouteNames.js │ ├── Throttle.js │ ├── colors.scss │ └── constants.module.scss │ ├── assets │ ├── Changelog.md │ ├── Colormask.md │ ├── DatetimeExtension.md │ ├── Documentation.md │ ├── Introduction.md │ ├── NumericExtension.md │ ├── OtherExtensions.md │ ├── browserstack-logo-600x315.png │ ├── github-mark-white.svg │ ├── inputmask.svg │ └── jb_beam.svg │ ├── index.js │ ├── index.scss │ ├── logo.svg │ ├── reportWebVitals.js │ └── setupTests.js ├── karma.conf.js ├── lib ├── bindings │ ├── inputmask.binding.js │ └── inputmask.es6.js ├── defaults.js ├── definitions.js ├── dependencyLibs │ ├── data.js │ ├── events.js │ ├── extend.js │ ├── inputmask.dependencyLib.jquery.js │ └── inputmask.dependencyLib.js ├── environment.js ├── escapeRegex.js ├── eventhandlers.js ├── eventruler.js ├── extensions │ ├── colormask.css │ ├── colormask.js │ ├── inputmask.date.extensions.js │ ├── inputmask.date.i18n.js │ ├── inputmask.extensions.js │ └── inputmask.numeric.extensions.js ├── global │ ├── FormData.js │ └── window.js ├── inputHandling.js ├── inputmask.js ├── inputmaskElement.js ├── jquery.inputmask.js ├── keycode.js ├── mask-lexer.js ├── mask.js ├── masktoken.js ├── polyfills │ ├── Array.includes.js │ ├── Object.entries.js │ ├── Object.getPrototypeOf.js │ └── String.includes.js ├── positioning.js ├── validation-tests.js └── validation.js ├── micromasks └── mm.js ├── nodetest.js ├── nuspecs ├── Inputmask.nuspec ├── Readme.txt └── jquery.inputmask.nuspec ├── package-lock.json ├── package.json ├── qunit ├── index.js ├── prototypeExtensions.js ├── qunit.html ├── simulator.js ├── tests_alternations.js ├── tests_attributes.js ├── tests_base.js ├── tests_date.js ├── tests_dynamic.js ├── tests_escape.js ├── tests_formatvalidate.js ├── tests_initialvalue.js ├── tests_inputeventonly.js ├── tests_ip.js ├── tests_jitmasking.js ├── tests_jquery_inputmask.js ├── tests_keepStatic.js ├── tests_multi.js ├── tests_numeric.js ├── tests_numericinput.js ├── tests_option.js ├── tests_optional.js ├── tests_paste.js ├── tests_regex.js └── tests_setvalue.js └── webpack.config.js /.eslintignore: -------------------------------------------------------------------------------- 1 | build 2 | node_modules/ 3 | .eslintrc.js 4 | webpack.config.js 5 | inputmask-pages/ -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "env": { 4 | "browser": true, 5 | "commonjs": true, 6 | "node": true 7 | }, 8 | "extends": [ 9 | "eslint:recommended", 10 | "standard", 11 | "plugin:import/errors", 12 | "plugin:import/warnings", 13 | "plugin:prettier/recommended" 14 | ], 15 | "parser": "@babel/eslint-parser", 16 | "parserOptions": { 17 | "requireConfigFile": false, 18 | "ecmaVersion": "latest", 19 | "sourceType": "module" 20 | }, 21 | "rules": { 22 | "react/prop-types": "off", 23 | "space-before-function-paren": [ 24 | "error", 25 | { 26 | "anonymous": "always", 27 | "named": "never", 28 | "asyncArrow": "always" 29 | } 30 | ], 31 | "semi": [ 32 | "error", 33 | "always", 34 | { 35 | "omitLastInOneLineBlock": true 36 | } 37 | ], 38 | "react/jsx-uses-react": "off", 39 | "react/react-in-jsx-scope": "off", 40 | "comma-dangle": "off", 41 | "import/order": [ 42 | "error", 43 | { 44 | "newlines-between": "always", 45 | "alphabetize": { 46 | "order": "asc", 47 | "caseInsensitive": true 48 | } 49 | } 50 | ], 51 | "import/named": "error", 52 | "prettier/prettier": ["error", { "singleQuote": false }], 53 | "one-var": ["error", "consecutive"], 54 | "no-use-before-define": "off", 55 | "no-unmodified-loop-condition": "off", 56 | "eqeqeq": "warn", 57 | "prefer-const": "warn", 58 | "no-proto": "warn" 59 | }, 60 | "globals": { 61 | "Inputmask": true, 62 | "jQuery": false, 63 | "define": false, 64 | "require": false 65 | } 66 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # These settings are for any web project 2 | 3 | # Handle line endings automatically for files detected as text 4 | # and leave all files detected as binary untouched. 5 | * text=auto 6 | 7 | # 8 | # The above will handle all files NOT found below 9 | # 10 | 11 | # These files are text and should be normalized (Convert crlf => lf) 12 | *.php text 13 | *.css text 14 | *.js text 15 | *.htm text 16 | *.html text 17 | *.xml text 18 | *.txt text 19 | *.ini text 20 | *.inc text 21 | .htaccess text 22 | 23 | # These files are binary and should be left untouched 24 | # (binary is a macro for -text -diff) 25 | *.png binary 26 | *.jpg binary 27 | *.jpeg binary 28 | *.gif binary 29 | *.ico binary 30 | *.mov binary 31 | *.mp4 binary 32 | *.mp3 binary 33 | *.flv binary 34 | *.fla binary 35 | *.swf binary 36 | *.gz binary 37 | *.zip binary 38 | *.7z binary 39 | *.ttf binary 40 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: [ 2 | "https://PayPal.Me/robinherbots", 3 | "https://www.buymeacoffee.com/robinherbots"] 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Issue report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | - Describe the bug 11 | - Add a link to a codepen, jsfiddle or other example page which shows the problem 12 | - OS: 13 | - Browser 14 | - Inputmask version 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | test.html 3 | jquery-1.10.2.js 4 | dist/jQuery.InputMask.*.nupkg 5 | node_modules/ 6 | bower_components/ 7 | npm-debug.log 8 | .idea/ 9 | *.iml 10 | qunit/qunit.js 11 | qunit/qunit.js.map 12 | **/*.map 13 | dist/*.LICENSE 14 | local.log 15 | browserstack.err 16 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.npmjs.org -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .husky 2 | build 3 | node_modules 4 | public 5 | *.svg 6 | package.json 7 | package-lock.json 8 | *.snap 9 | *.ttf 10 | *.otf -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 2, 3 | "singleQuote": false, 4 | "jsxBracketSameLine": true, 5 | "trailingComma": "none", 6 | "endOfLine": "auto" 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Launch Chrome", 9 | "request": "launch", 10 | "type": "chrome", 11 | "url": "file://${file}", 12 | "webRoot": "${workspaceFolder}" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "workbench.colorCustomizations": { 3 | "titleBar.activeBackground": "#12dee6", 4 | "titleBar.inactiveBackground": "#12dee6", 5 | "titleBar.activeForeground": "#ffffff", 6 | "activityBar.border": "#12dee6", 7 | "activityBar.foreground": "#12dee6", 8 | "titleBar.border": "#12dee6", 9 | "statusBar.border": "#12dee6" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | const webpackConfig = require("./webpack.config"); 2 | 3 | module.exports = function (grunt) { 4 | // Project configuration. 5 | grunt.initConfig({ 6 | pkg: grunt.file.readJSON("package.json"), 7 | clean: ["dist"], 8 | bump: { 9 | options: { 10 | files: ["package.json", "bower.json", "composer.json"], 11 | updateConfigs: ["pkg"], 12 | commit: false, 13 | createTag: false, 14 | push: false, 15 | prereleaseName: "beta" 16 | } 17 | }, 18 | release: { 19 | options: { 20 | bump: false, 21 | commit: false, 22 | add: false 23 | } 24 | }, 25 | nugetpack: { 26 | dist: { 27 | src: (function () { 28 | return "nuspecs/Inputmask.nuspec"; 29 | })(), 30 | dest: "build/", 31 | options: { 32 | version: "<%= pkg.version %>" 33 | } 34 | }, 35 | dist2: { 36 | src: (function () { 37 | return "nuspecs/jquery.inputmask.nuspec"; 38 | })(), 39 | dest: "build/", 40 | options: { 41 | version: "<%= pkg.version %>" 42 | } 43 | } 44 | }, 45 | nugetpush: { 46 | dist: { 47 | src: "build/InputMask.<%= pkg.version %>.nupkg", 48 | options: { 49 | source: "https://www.nuget.org" 50 | } 51 | }, 52 | dist2: { 53 | src: "build/jquery.inputMask.<%= pkg.version %>.nupkg", 54 | options: { 55 | source: "https://www.nuget.org" 56 | } 57 | } 58 | }, 59 | karma: { 60 | options: { 61 | configFile: "karma.conf.js" 62 | }, 63 | unit: { 64 | singleRun: true 65 | } 66 | }, 67 | eslint: { 68 | target: "lib/*.js" 69 | }, 70 | availabletasks: { 71 | tasks: { 72 | options: { 73 | filter: "exclude", 74 | tasks: ["availabletasks", "default"], 75 | showTasks: ["user"] 76 | } 77 | } 78 | }, 79 | webpack: { 80 | main: webpackConfig("production")[0], 81 | jquery: webpackConfig("production")[1], 82 | colormask: webpackConfig("production")[2] 83 | }, 84 | copy: { 85 | extensions: { 86 | files: [ 87 | { 88 | src: "lib/bindings/inputmask.binding.js", 89 | dest: "dist/bindings/inputmask.binding.js" 90 | }, 91 | { 92 | src: "lib/bindings/inputmask.es6.js", 93 | dest: "dist/inputmask.es6.js" 94 | }, 95 | { src: "lib/extensions/colormask.css", dest: "dist/colormask.css" }, 96 | { 97 | src: "Changelog.md", 98 | dest: "inputmask-pages/src/assets/Changelog.md" 99 | } 100 | ] 101 | } 102 | } 103 | }); 104 | 105 | // Load the plugin that provides the tasks. 106 | require("load-grunt-tasks")(grunt); 107 | 108 | grunt.registerTask("publish", ["release", "nugetpack", "nugetpush"]); 109 | grunt.registerTask("publishnext", function () { 110 | grunt.config("release.options.npmtag", "next"); 111 | grunt.task.run("release"); 112 | }); 113 | grunt.registerTask("validate", ["webpack", "copy", "eslint", "karma"]); 114 | grunt.registerTask("build", ["bump:prerelease", "clean", "webpack", "copy"]); 115 | grunt.registerTask("build:patch", ["bump:patch", "clean", "webpack", "copy"]); 116 | grunt.registerTask("build:minor", ["bump:minor", "clean", "webpack", "copy"]); 117 | grunt.registerTask("build:major", ["bump:major", "clean", "webpack", "copy"]); 118 | grunt.registerTask("default", ["availabletasks"]); 119 | }; 120 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 - 2018 Robin Herbots 2 | 3 | Permission 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE 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. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Inputmask 2 | 3 | Copyright (c) 2010 - 2023 Robin Herbots Licensed under the MIT license (<https://opensource.org/licenses/MIT>) 4 | 5 | The Inputmask has a very permissive license and this will stay that way. But when you use the Inputmask in a commercial setting, be so honest to make a small donation. 6 | This will be appreciated very much. 7 | 8 | [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=ZNR3EB6JTMMSS) 9 | 10 |    11 | 12 | Inputmask is a javascript library that creates an input mask. Inputmask can run against vanilla javascript, jQuery, and jqlite. 13 | 14 | An inputmask helps the user with the input by ensuring a predefined format. This can be useful for dates, numerics, phone numbers, ... 15 | 16 | Thanks to [Browserstack](https://www.browserstack.com) for providing a free license, so we can automate testing in different browsers and devices. 17 | 18 | <a href="https://www.browserstack.com"> 19 | <img src="https://www.browserstack.com/images/layout/browserstack-logo-600x315.png" alt="Browserstack" width="150"> 20 | </a> 21 | 22 | ## Documentation and demo page 23 | 24 | <https://robinherbots.github.io/Inputmask/> 25 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "inputmask", 3 | 4 | "version": "5.0.10-beta.48", 5 | "main": [ 6 | "./index.js", 7 | "./css/inputmask.css" 8 | ], 9 | "keywords": ["jquery", "plugins", "input", "form", "inputmask", "mask"], 10 | "description": "Inputmask is a javascript library which creates an input mask. Inputmask can run against vanilla javascript, jQuery and jqlite.", 11 | "license": "http://opensource.org/licenses/mit-license.php", 12 | "ignore": [ 13 | "**/*", 14 | "!index.js", 15 | "!bundle.js", 16 | "!bundle.jquery.js", 17 | "!css/**/*", 18 | "!dist/**/*", 19 | "!lib/**/*" 20 | ], 21 | "dependencies": { 22 | "jquery": ">=1.7" 23 | }, 24 | "authors": [{ 25 | "name": "Robin Herbots" 26 | }], 27 | "homepage": "http://robinherbots.github.io/Inputmask" 28 | } 29 | -------------------------------------------------------------------------------- /bundle.colormask.js: -------------------------------------------------------------------------------- 1 | import "./bundle"; 2 | import Colormask from "./lib/extensions/colormask"; 3 | export default Colormask; 4 | -------------------------------------------------------------------------------- /bundle.jquery.js: -------------------------------------------------------------------------------- 1 | import Inputmask from "./bundle"; 2 | import "./lib/jquery.inputmask"; 3 | 4 | export default Inputmask; 5 | -------------------------------------------------------------------------------- /bundle.js: -------------------------------------------------------------------------------- 1 | import "./lib/polyfills/Object.getPrototypeOf"; 2 | import "./lib/polyfills/Array.includes"; 3 | import "./lib/polyfills/Object.entries"; 4 | import "./lib/polyfills/String.includes"; 5 | 6 | import "./lib/global/FormData"; 7 | 8 | import "./lib/extensions/inputmask.extensions"; 9 | import "./lib/extensions/inputmask.date.extensions"; 10 | import "./lib/extensions/inputmask.numeric.extensions"; 11 | import "./lib/inputmaskElement"; 12 | import Inputmask from "./lib/inputmask"; 13 | 14 | export default Inputmask; 15 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "robinherbots/inputmask", 3 | "description": "Inputmask is a javascript library which creates an input mask. Inputmask can run against vanilla javascript, jQuery and jqlite.", 4 | "version": "5.0.10-beta.48", 5 | "type": "library", 6 | "keywords": ["jquery", "plugins", "input", "form", "inputmask", "mask"], 7 | "homepage": "http://robinherbots.github.io/Inputmask", 8 | "license": "MIT", 9 | "authors": [{ 10 | "name": "Robin Herbots" 11 | }] 12 | } 13 | -------------------------------------------------------------------------------- /dist/bindings/inputmask.binding.js: -------------------------------------------------------------------------------- 1 | /* 2 | Input Mask plugin binding 3 | http://github.com/RobinHerbots/jquery.inputmask 4 | Copyright (c) Robin Herbots 5 | Licensed under the MIT license 6 | */ 7 | (function (factory) { 8 | factory(jQuery, window.Inputmask, window); 9 | })(function ($, Inputmask, window) { 10 | $(window.document) 11 | .ajaxComplete(function (event, xmlHttpRequest, ajaxOptions) { 12 | if ($.inArray("html", ajaxOptions.dataTypes) !== -1) { 13 | $( 14 | ".inputmask, [data-inputmask], [data-inputmask-mask], [data-inputmask-alias], [data-inputmask-regex]" 15 | ).each(function (ndx, lmnt) { 16 | if (lmnt.inputmask === undefined) { 17 | Inputmask().mask(lmnt); 18 | } 19 | }); 20 | } 21 | }) 22 | .ready(function () { 23 | $( 24 | ".inputmask, [data-inputmask], [data-inputmask-mask], [data-inputmask-alias],[data-inputmask-regex]" 25 | ).each(function (ndx, lmnt) { 26 | if (lmnt.inputmask === undefined) { 27 | Inputmask().mask(lmnt); 28 | } 29 | }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /dist/colormask.css: -------------------------------------------------------------------------------- 1 | mark.im-caret { 2 | animation: 1s blink step-end infinite !important; 3 | } 4 | 5 | mark.im-caret-select { 6 | background-color: rgba(0, 0, 0, 0.25); 7 | } 8 | 9 | @keyframes blink { 10 | from, to { 11 | border-right-color: black; 12 | } 13 | 50% { 14 | /*border-right-color: transparent;*/ 15 | border-right-color: white; 16 | } 17 | } 18 | 19 | span.im-static { 20 | color: grey; 21 | } 22 | 23 | div.im-colormask { 24 | display: inline-block; 25 | border-style: groove; 26 | border-width: 1px; 27 | appearance: textfield; 28 | cursor: text; 29 | } 30 | 31 | div.im-colormask > input, div.im-colormask > input:-webkit-autofill { 32 | position: absolute !important; 33 | display: inline-block; 34 | background-color: transparent; 35 | color: transparent; 36 | -webkit-text-fill-color: transparent; 37 | transition: background-color 5000s ease-in-out 0s; 38 | caret-color: transparent; 39 | text-shadow: none; 40 | appearance: textfield; 41 | border-style: none; 42 | left: 0; /*calculated*/ 43 | } 44 | 45 | div.im-colormask > input:focus { 46 | outline: none; 47 | } 48 | 49 | div.im-colormask > input::selection { 50 | background: none; 51 | } 52 | 53 | div.im-colormask > input::-moz-selection { 54 | background: none; 55 | } 56 | 57 | div.im-colormask > input:-webkit-autofill ~ div { 58 | background-color: rgb(255, 255, 255); 59 | } 60 | 61 | div.im-colormask > div { 62 | color: black; 63 | display: inline-block; 64 | width: 100px; /*calculated*/ 65 | } -------------------------------------------------------------------------------- /dist/inputmask.es6.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line import/no-unresolved 2 | import "./inputmask.js"; 3 | 4 | const inputmask = window.Inputmask; 5 | window.Inputmask = undefined; 6 | export default inputmask; 7 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | <!DOCTYPE html> 2 | <html lang="en"> 3 | <head> 4 | <meta charset="UTF-8"> 5 | <title>Title</title> 6 | </head> 7 | <body> 8 | <input-mask alias="datetime" inputFormat="mm/dd/yyyy"></input-mask> 9 | <input-mask alias="currency" prefix="$ "></input-mask> 10 | <input-mask alias="email"></input-mask> 11 | <br/> 12 | <script type="text/javascript" src="dist/inputmask.js" charset="utf-8"></script> 13 | </body> 14 | </html> 15 | -------------------------------------------------------------------------------- /inputmask-pages/.env: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinHerbots/Inputmask/55dcd7e87bc74bbd9cdd67669fa6a6a589ba98eb/inputmask-pages/.env -------------------------------------------------------------------------------- /inputmask-pages/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "env": { 4 | "browser": true, 5 | "es2024": true, 6 | "jest": true 7 | }, 8 | "extends": [ 9 | "standard", 10 | "plugin:react/recommended", 11 | "plugin:react-hooks/recommended", 12 | "plugin:import/errors", 13 | "plugin:import/warnings", 14 | "plugin:prettier/recommended", 15 | "plugin:jest/recommended" 16 | ], 17 | "overrides": [], 18 | "parserOptions": { 19 | "ecmaVersion": "latest", 20 | "sourceType": "module" 21 | }, 22 | "plugins": ["react", "jest"], 23 | "settings": { 24 | "react": { 25 | "version": "detect" 26 | } 27 | }, 28 | "rules": { 29 | "react/prop-types": "off", 30 | "quotes": ["error", "double"], 31 | "space-before-function-paren": [ 32 | "error", 33 | { 34 | "anonymous": "always", 35 | "named": "never", 36 | "asyncArrow": "always" 37 | } 38 | ], 39 | "semi": [ 40 | "error", 41 | "always", 42 | { 43 | "omitLastInOneLineBlock": true 44 | } 45 | ], 46 | "react/jsx-uses-react": "off", 47 | "react/react-in-jsx-scope": "off", 48 | "comma-dangle": "off", 49 | "import/order": [ 50 | "error", 51 | { 52 | "newlines-between": "always", 53 | "alphabetize": { 54 | "order": "asc", 55 | "caseInsensitive": true 56 | } 57 | } 58 | ], 59 | "import/named": "error", 60 | "prettier/prettier": ["error", { "singleQuote": false }], 61 | "one-var": ["error", "consecutive"] 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /inputmask-pages/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /inputmask-pages/.prettierignore: -------------------------------------------------------------------------------- 1 | .husky 2 | build 3 | node_modules 4 | public 5 | *.svg 6 | package.json 7 | package-lock.json 8 | *.snap 9 | *.ttf 10 | *.otf -------------------------------------------------------------------------------- /inputmask-pages/.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 2, 3 | "singleQuote": false, 4 | "jsxBracketSameLine": true, 5 | "trailingComma": "none", 6 | "endOfLine": "auto" 7 | } 8 | -------------------------------------------------------------------------------- /inputmask-pages/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "chrome", 9 | "request": "launch", 10 | "name": "Launch Chrome against localhost", 11 | "url": "http://localhost:3000", 12 | "webRoot": "${workspaceFolder}" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /inputmask-pages/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Create React App 2 | 3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 4 | 5 | ## Available Scripts 6 | 7 | In the project directory, you can run: 8 | 9 | ### `npm start` 10 | 11 | Runs the app in the development mode.\ 12 | Open [http://localhost:3000](http://localhost:3000) to view it in your browser. 13 | 14 | The page will reload when you make changes.\ 15 | You may also see any lint errors in the console. 16 | 17 | ### `npm test` 18 | 19 | Launches the test runner in the interactive watch mode.\ 20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 21 | 22 | ### `npm run build` 23 | 24 | Builds the app for production to the `build` folder.\ 25 | It correctly bundles React in production mode and optimizes the build for the best performance. 26 | 27 | The build is minified and the filenames include the hashes.\ 28 | Your app is ready to be deployed! 29 | 30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 31 | 32 | ### `npm run eject` 33 | 34 | **Note: this is a one-way operation. Once you `eject`, you can't go back!** 35 | 36 | If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 37 | 38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own. 39 | 40 | You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it. 41 | 42 | ## Learn More 43 | 44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 45 | 46 | To learn React, check out the [React documentation](https://reactjs.org/). 47 | 48 | ### Code Splitting 49 | 50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) 51 | 52 | ### Analyzing the Bundle Size 53 | 54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) 55 | 56 | ### Making a Progressive Web App 57 | 58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) 59 | 60 | ### Advanced Configuration 61 | 62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) 63 | 64 | ### Deployment 65 | 66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) 67 | 68 | ### `npm run build` fails to minify 69 | 70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) 71 | -------------------------------------------------------------------------------- /inputmask-pages/generate-react-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "usesTypeScript": false, 3 | "usesCssModule": true, 4 | "cssPreprocessor": "scss", 5 | "testLibrary": "Testing Library", 6 | "component": { 7 | "default": { 8 | "path": "src/Components", 9 | "withStyle": true, 10 | "withTest": true, 11 | "withStory": false, 12 | "withLazy": true 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /inputmask-pages/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "inputmask-pages", 3 | "version": "0.1.0", 4 | "private": true, 5 | "homepage": "/Inputmask/#/", 6 | "devDependencies": { 7 | "@testing-library/jest-dom": "^5.17.0", 8 | "@testing-library/react": "^14.0.0", 9 | "@testing-library/user-event": "^14.4.3", 10 | "eslint": "^8.46.0", 11 | "eslint-config-prettier": "^8.9.0", 12 | "eslint-config-standard": "^17.1.0", 13 | "eslint-plugin-header": "^3.1.1", 14 | "eslint-plugin-import": "^2.28.0", 15 | "eslint-plugin-jest": "^27.4.2", 16 | "eslint-plugin-n": "^16.0.1", 17 | "eslint-plugin-prettier": "^5.0.0", 18 | "eslint-plugin-promise": "^6.1.1", 19 | "eslint-plugin-react": "^7.33.1", 20 | "eslint-plugin-react-hooks": "^4.6.0", 21 | "gh-pages": "^6.3.0", 22 | "history": "^5.3.0", 23 | "inputmask": "^5.0.10-beta.22", 24 | "postcss-normalize": "^10.0.1", 25 | "prettier": "3.0.0", 26 | "react": "^18.2.0", 27 | "react-dom": "^18.2.0", 28 | "react-remark": "^2.1.0", 29 | "react-router-dom": "^6.14.2", 30 | "react-scripts": "^5.0.1", 31 | "rehype-autolink-headings": "^6.1.1", 32 | "rehype-highlight": "^6.0.0", 33 | "rehype-react": "^7.2.0", 34 | "rehype-slug": "^5.1.0", 35 | "remark-gfm": "^3.0.1", 36 | "remark-parse": "^10.0.2", 37 | "remark-rehype": "^10.1.0", 38 | "sass": "^1.64.2", 39 | "unified": "^10.1.2", 40 | "web-vitals": "^3.4.0", 41 | "@babel/plugin-proposal-private-property-in-object": "^7.21.11" 42 | }, 43 | "scripts": { 44 | "start": "react-scripts start", 45 | "build": "set \"GENERATE_SOURCEMAP=false\" && react-scripts build", 46 | "test": "react-scripts test", 47 | "eject": "react-scripts eject", 48 | "deploy": "gh-pages -d build" 49 | }, 50 | "eslintConfig": { 51 | "extends": [ 52 | "react-app", 53 | "react-app/jest" 54 | ] 55 | }, 56 | "browserslist": { 57 | "production": [ 58 | ">0.2%", 59 | "not dead", 60 | "not op_mini all" 61 | ], 62 | "development": [ 63 | "last 1 chrome version", 64 | "last 1 firefox version", 65 | "last 1 safari version" 66 | ] 67 | }, 68 | "jest": { 69 | "transformIgnorePatterns": [ 70 | "node_modules/(?!(rehype-autolink-headings))" 71 | ] 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /inputmask-pages/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinHerbots/Inputmask/55dcd7e87bc74bbd9cdd67669fa6a6a589ba98eb/inputmask-pages/public/favicon.ico -------------------------------------------------------------------------------- /inputmask-pages/public/index.html: -------------------------------------------------------------------------------- 1 | <!DOCTYPE html> 2 | <html lang="en"> 3 | 4 | <head> 5 | <meta charset="utf-8" /> 6 | <link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> 7 | <meta name="viewport" content="width=device-width, initial-scale=1" /> 8 | <meta name="theme-color" content="#000000" /> 9 | <meta name="description" content="Inputmask documentation pages" /> 10 | <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> 11 | <!-- 12 | manifest.json provides metadata used when your web app is installed on a 13 | user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ 14 | --> 15 | <link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> 16 | <!-- 17 | Notice the use of %PUBLIC_URL% in the tags above. 18 | It will be replaced with the URL of the `public` folder during the build. 19 | Only files inside the `public` folder can be referenced from the HTML. 20 | 21 | Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will 22 | work correctly both with client-side routing and a non-root public URL. 23 | Learn how to configure a non-root public URL by running `npm run build`. 24 | --> 25 | <title>Inputmask documentation</title> 26 | <script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4533828508581714" 27 | crossorigin="anonymous"></script> 28 | </head> 29 | 30 | <body> 31 | <noscript>You need to enable JavaScript to run this app.</noscript> 32 | <div id="root"></div> 33 | <!-- 34 | This HTML file is a template. 35 | If you open it directly in the browser, you will see an empty page. 36 | 37 | You can add webfonts, meta tags, or analytics to this file. 38 | The build step will place the bundled scripts into the <body> tag. 39 | 40 | To begin the development, run `npm start` or `yarn start`. 41 | To create a production bundle, use `npm run build` or `yarn build`. 42 | --> 43 | </body> 44 | 45 | </html> -------------------------------------------------------------------------------- /inputmask-pages/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Inputmask Docs", 3 | "name": "Inputmask Documentation", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /inputmask-pages/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /inputmask-pages/src/App.js: -------------------------------------------------------------------------------- 1 | import { useContext } from "react"; 2 | import { Routes } from "react-router-dom"; 3 | 4 | import styles from "./App.module.scss"; 5 | import { Footer } from "./Components/Footer/Footer"; 6 | import { Header } from "./Components/Header/Header"; 7 | import { Navigation } from "./Components/Navigation/Navigation"; 8 | import { useViewPort } from "./Components/ViewPort/ViewPort"; 9 | import { RoutingContext } from "./RoutingProvider"; 10 | import constants from "./Shared/constants.module.scss"; 11 | 12 | function App() { 13 | const { routes, asideRoutes } = useContext(RoutingContext), 14 | { width } = useViewPort(); 15 | 16 | return ( 17 | <div id="app" data-testid="app-container"> 18 | <Header /> 19 | <div className={styles.content}> 20 | <Navigation /> 21 | <article className={`${styles.article} ${styles.scrollable}`}> 22 | <Routes>{routes}</Routes> 23 | </article> 24 | {width > constants.AsideThreshold && ( 25 | <aside className={`${styles.asideright} ${styles.scrollable}`}> 26 | <Routes>{asideRoutes}</Routes> 27 | </aside> 28 | )} 29 | </div> 30 | <Footer /> 31 | </div> 32 | ); 33 | } 34 | 35 | export default App; 36 | -------------------------------------------------------------------------------- /inputmask-pages/src/App.module.scss: -------------------------------------------------------------------------------- 1 | @import "Shared/colors.scss"; 2 | @import "Shared/constants.module.scss"; 3 | 4 | .content { 5 | display: flex; 6 | flex-direction: column; 7 | flex-grow: 1; 8 | overflow: hidden; 9 | @media only screen and (min-width: ($ScreenThreshold + 0px)) { 10 | flex-direction: row; 11 | } 12 | } 13 | 14 | .article { 15 | display: flex; 16 | flex-grow: 2; 17 | padding-left: 0.9375rem; 18 | padding-right: 0.9375rem; 19 | @media only screen and (min-width: ($ScreenThreshold + 0px)) { 20 | flex-basis: 34.375rem; 21 | } 22 | } 23 | 24 | .asideright { 25 | display: flex; 26 | flex-grow: 1; 27 | flex-basis: 200px; 28 | border-left-style: solid; 29 | border-left-width: 1px; 30 | border-left-color: $main-color; 31 | padding-left: 0.9375rem; 32 | padding-right: 0.9375rem; 33 | min-width: min-content; 34 | } 35 | 36 | .scrollable { 37 | overflow-y: auto; 38 | overflow-x: hidden; 39 | scrollbar-gutter: auto; 40 | scrollbar-color: $scrollbar-thumb $scrollbar-track; 41 | scrollbar-width: thin; 42 | &::-webkit-scrollbar-thumb { 43 | background-color: $scrollbar-thumb; 44 | } 45 | &::-webkit-scrollbar-track { 46 | background-color: $scrollbar-track; 47 | } 48 | &::-webkit-scrollbar-corner { 49 | background-color: $scrollbar-track; 50 | } 51 | &::-webkit-scrollbar { 52 | width: 0.5rem; 53 | height: 0.5rem; 54 | } 55 | @media only screen and (min-width: ($ScreenThreshold + 0px)) { 56 | margin-right: 5px; 57 | } 58 | scroll-behavior: smooth; 59 | } 60 | 61 | :global(#app) { 62 | display: flex; 63 | flex-direction: column; 64 | overflow: hidden; 65 | flex-grow: 1; 66 | } 67 | 68 | :global(a) { 69 | color: $link-color; 70 | &:visited { 71 | color: $link-color-visited; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /inputmask-pages/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | 3 | import App from "./App"; 4 | 5 | test("renders App", () => { 6 | render(<App></App>); 7 | const appContainer = screen.getByTestId("app-container"); 8 | expect(appContainer).toBeInTheDocument(); 9 | }); 10 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Changelog/Changelog.js: -------------------------------------------------------------------------------- 1 | import changelogMD from "../../assets/Changelog.md"; 2 | import { MarkDownPage } from "../MarkDownPage/MarkDownPage"; 3 | 4 | import styles from "./Changelog.module.scss"; 5 | 6 | export const Changelog = () => { 7 | return ( 8 | <MarkDownPage 9 | className={styles.Changelog} 10 | md={changelogMD} 11 | data-testid="Changelog"></MarkDownPage> 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Changelog/Changelog.lazy.js: -------------------------------------------------------------------------------- 1 | import React, { lazy, Suspense } from 'react'; 2 | 3 | const LazyChangelog = lazy(() => import('./Changelog')); 4 | 5 | const Changelog = props => ( 6 | <Suspense fallback={null}> 7 | <LazyChangelog {...props} /> 8 | </Suspense> 9 | ); 10 | 11 | export default Changelog; 12 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Changelog/Changelog.module.scss: -------------------------------------------------------------------------------- 1 | .Changelog { 2 | display: initial; 3 | } 4 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Changelog/ChangelogToc.js: -------------------------------------------------------------------------------- 1 | import stylesApp from "../../App.module.scss"; 2 | import { Toc } from "../Toc/Toc"; 3 | 4 | import styles from "./Changelog.module.scss"; 5 | 6 | export const ChangelogToc = () => { 7 | return ( 8 | <Toc 9 | contentSelector={`.${styles.Changelog}`} 10 | data-testid="ChangelogToc" 11 | scrollContainer={`.${stylesApp.article}`}></Toc> 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Colormask/Colormask.js: -------------------------------------------------------------------------------- 1 | import documentationMD from "../../assets/Colormask.md"; 2 | import { MarkDownPage } from "../MarkDownPage/MarkDownPage"; 3 | 4 | import styles from "./Colormask.module.scss"; 5 | 6 | export const Colormask = () => { 7 | return ( 8 | <MarkDownPage 9 | className={styles.Colormask} 10 | md={documentationMD} 11 | data-testid="Colormask"></MarkDownPage> 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Colormask/Colormask.lazy.js: -------------------------------------------------------------------------------- 1 | import { lazy, Suspense } from "react"; 2 | 3 | const LazyColormask = lazy(() => import("./Colormask")), 4 | Colormask = (props) => ( 5 | <Suspense fallback={null}> 6 | <LazyColormask {...props} /> 7 | </Suspense> 8 | ); 9 | 10 | export default Colormask; 11 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Colormask/Colormask.module.scss: -------------------------------------------------------------------------------- 1 | .Colormask { 2 | display: initial; 3 | } 4 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Colormask/ColormaskToc.js: -------------------------------------------------------------------------------- 1 | import stylesApp from "../../App.module.scss"; 2 | import { Toc } from "../Toc/Toc"; 3 | 4 | import styles from "./Colormask.module.scss"; 5 | 6 | export const ColormaskToc = () => { 7 | return ( 8 | <Toc 9 | contentSelector={`.${styles.Colormask}`} 10 | data-testid="ColormaskToc" 11 | scrollContainer={`.${stylesApp.article}`}></Toc> 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/DatetimeAlias/DatetimeAlias.js: -------------------------------------------------------------------------------- 1 | import documentationMD from "../../assets/DatetimeExtension.md"; 2 | import { MarkDownPage } from "../MarkDownPage/MarkDownPage"; 3 | 4 | import styles from "./DatetimeAlias.module.scss"; 5 | 6 | export const DatetimeAlias = () => { 7 | return ( 8 | <MarkDownPage 9 | className={styles.DatetimeAlias} 10 | md={documentationMD} 11 | data-testid="DatetimeAlias"></MarkDownPage> 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/DatetimeAlias/DatetimeAlias.lazy.js: -------------------------------------------------------------------------------- 1 | import { lazy, Suspense } from "react"; 2 | 3 | const LazyDatetimeAlias = lazy(() => import("./DatetimeAlias")), 4 | DatetimeAlias = (props) => ( 5 | <Suspense fallback={null}> 6 | <LazyDatetimeAlias {...props} /> 7 | </Suspense> 8 | ); 9 | 10 | export default DatetimeAlias; 11 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/DatetimeAlias/DatetimeAlias.module.scss: -------------------------------------------------------------------------------- 1 | .DatetimeAlias { 2 | display: initial; 3 | } 4 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/DatetimeAlias/DatetimeAliasToc.js: -------------------------------------------------------------------------------- 1 | import stylesApp from "../../App.module.scss"; 2 | import { Toc } from "../Toc/Toc"; 3 | 4 | import styles from "./DatetimeAlias.module.scss"; 5 | 6 | export const DatetimeAliasToc = () => { 7 | return ( 8 | <Toc 9 | contentSelector={`.${styles.DatetimeAlias}`} 10 | data-testid="DatetimeAliasToc" 11 | scrollContainer={`.${stylesApp.article}`}></Toc> 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Demo/Demo.js: -------------------------------------------------------------------------------- 1 | import { DemoMask } from "../DemoMask/DemoMask"; 2 | 3 | import styles from "./Demo.module.scss"; 4 | 5 | export const Demo = () => { 6 | return ( 7 | <div className={styles.Demo} data-testid="Demo"> 8 | <DemoMask 9 | label="Date:" 10 | maskOptions={{ alias: "datetime", inputFormat: "dd/mm/yyyy" }} 11 | /> 12 | <DemoMask 13 | label="Date:" 14 | maskOptions={{ alias: "datetime", inputFormat: "mm/dd/yyyy" }} 15 | /> 16 | <DemoMask 17 | label="Date:" 18 | maskOptions={{ 19 | alias: "datetime", 20 | inputFormat: "dd mmm yyyy", 21 | inputmode: "text" 22 | }} 23 | /> 24 | <DemoMask 25 | label="Date:" 26 | maskOptions={{ 27 | alias: "datetime", 28 | inputFormat: "dd mmmm yyyy", 29 | inputmode: "text" 30 | }} 31 | /> 32 | <DemoMask 33 | label="Currency:" 34 | maskOptions={{ 35 | alias: "numeric", 36 | groupSeparator: ",", 37 | digits: 2, 38 | digitsOptional: false, 39 | prefix: "quot;, 40 | placeholer: "0" 41 | }} 42 | /> 43 | <DemoMask 44 | label="License plate:" 45 | maskOptions={{ mask: "[9-]AAA-999" }} 46 | comment="[9-]AAA-999" 47 | /> 48 | <DemoMask 49 | label="Decimal:" 50 | maskOptions={{ alias: "decimal", groupSeparator: "," }} 51 | comment="Group separator: , RadixPoint: ." 52 | /> 53 | <DemoMask 54 | label="IP address:" 55 | maskOptions={{ alias: "ip", greedy: true }} 56 | comment="greedy: true" 57 | /> 58 | <DemoMask label="Email address:" maskOptions={{ alias: "email" }} /> 59 | </div> 60 | ); 61 | }; 62 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Demo/Demo.lazy.js: -------------------------------------------------------------------------------- 1 | import { lazy, Suspense } from "react"; 2 | 3 | const LazyDemo = lazy(() => import("./Demo")), 4 | Demo = (props) => ( 5 | <Suspense fallback={null}> 6 | <LazyDemo {...props} /> 7 | </Suspense> 8 | ); 9 | 10 | export default Demo; 11 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Demo/Demo.module.scss: -------------------------------------------------------------------------------- 1 | .Demo { 2 | width: 100%; 3 | & > div { 4 | display: flex; 5 | flex-direction: row; 6 | margin: 15px; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/DemoMask/DemoMask.js: -------------------------------------------------------------------------------- 1 | import Inputmask from "inputmask"; 2 | import { useRef, useEffect, useState } from "react"; 3 | 4 | import styles from "./DemoMask.module.scss"; 5 | 6 | export const DemoMask = (props) => { 7 | const { label, comment, maskOptions } = props, 8 | inputRef = useRef(), 9 | [Complete, setComplete] = useState(), 10 | [Incomplete, setIncomplete] = useState(), 11 | [Cleared, setCleared] = useState(), 12 | [KeyValidation, setKeyValidation] = useState(); 13 | 14 | useEffect(() => { 15 | Inputmask({ 16 | ...maskOptions, 17 | oncomplete: () => { 18 | setComplete("fired"); 19 | setIncomplete(""); 20 | }, 21 | onincomplete: () => { 22 | setIncomplete("fired"); 23 | setComplete(""); 24 | }, 25 | oncleared: () => { 26 | setCleared("fired"); 27 | setComplete(""); 28 | setIncomplete(""); 29 | }, 30 | onKeyValidation: (key, result, opts) => { 31 | setKeyValidation(result ? "fired" : ""); 32 | } 33 | }).mask(inputRef.current); 34 | }, [maskOptions]); 35 | 36 | return ( 37 | <div className={styles.DemoMask} data-testid="DemoMask"> 38 | <div className="demoField"> 39 | <div> 40 | <span>{label}</span> 41 | <input ref={inputRef} /> 42 | </div> 43 | <span className="comment">{comment}</span> 44 | </div> 45 | <div className="eventIndicator"> 46 | <span className={Complete}>Complete</span> 47 | <span className={Incomplete}>Incomplete</span> 48 | <span className={Cleared}>Cleared</span> 49 | <span className={KeyValidation}>Valid</span> 50 | </div> 51 | </div> 52 | ); 53 | }; 54 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/DemoMask/DemoMask.lazy.js: -------------------------------------------------------------------------------- 1 | import React, { lazy, Suspense } from 'react'; 2 | 3 | const LazyDemoMask = lazy(() => import('./DemoMask')); 4 | 5 | const DemoMask = props => ( 6 | <Suspense fallback={null}> 7 | <LazyDemoMask {...props} /> 8 | </Suspense> 9 | ); 10 | 11 | export default DemoMask; 12 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/DemoMask/DemoMask.module.scss: -------------------------------------------------------------------------------- 1 | @import "../../Shared/colors.scss"; 2 | 3 | .DemoMask { 4 | display: flex; 5 | flex-direction: row; 6 | justify-content: space-between; 7 | flex-flow: wrap; 8 | margin: 15px; 9 | & > div { 10 | margin: 5px; 11 | } 12 | 13 | :global { 14 | & .demoField { 15 | display: flex; 16 | flex-direction: column; 17 | & > div { 18 | & > span { 19 | display: inline-block; 20 | width: 150px; 21 | } 22 | & > input { 23 | width: 250px; 24 | } 25 | } 26 | } 27 | 28 | & .eventIndicator { 29 | display: flex; 30 | flex-flow: wrap; 31 | & > span { 32 | margin: 0 5px 0 5px; 33 | padding: 2px 7px 2px 7px; 34 | background-color: $main-background; 35 | color: $main-color; 36 | border-radius: 5px; 37 | 38 | &.fired { 39 | background-color: $fired-background !important; 40 | color: $main-color !important; 41 | font-weight: bold !important; 42 | } 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Documentation/Documentation.js: -------------------------------------------------------------------------------- 1 | import documentationMD from "../../assets/Documentation.md"; 2 | import { MarkDownPage } from "../MarkDownPage/MarkDownPage"; 3 | 4 | import styles from "./Documentation.module.scss"; 5 | 6 | export const Documentation = () => { 7 | return ( 8 | <MarkDownPage 9 | className={styles.Documentation} 10 | md={documentationMD} 11 | data-testid="Documentation"></MarkDownPage> 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Documentation/Documentation.lazy.js: -------------------------------------------------------------------------------- 1 | import { lazy, Suspense } from "react"; 2 | 3 | const LazyDocumentation = lazy(() => import("./Documentation")), 4 | Documentation = (props) => ( 5 | <Suspense fallback={null}> 6 | <LazyDocumentation {...props} /> 7 | </Suspense> 8 | ); 9 | 10 | export default Documentation; 11 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Documentation/Documentation.module.scss: -------------------------------------------------------------------------------- 1 | .Documentation { 2 | display: initial; 3 | } 4 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Documentation/DocumentationToc.js: -------------------------------------------------------------------------------- 1 | import stylesApp from "../../App.module.scss"; 2 | import { Toc } from "../Toc/Toc"; 3 | 4 | import styles from "./Documentation.module.scss"; 5 | 6 | export const DocumentationToc = () => { 7 | return ( 8 | <Toc 9 | contentSelector={`.${styles.Documentation}`} 10 | data-testid="DocumentationToc" 11 | scrollContainer={`.${stylesApp.article}`}></Toc> 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Documentation/DocumentationToc.module scss: -------------------------------------------------------------------------------- 1 | .Documentation { 2 | display: inline-flex; 3 | flex-grow: 1; 4 | flex-direction: column; 5 | max-width: inherit; 6 | & > a { 7 | vertical-align: middle; 8 | } 9 | & > pre { 10 | white-space: pre-wrap; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Extensions/Extensions.js: -------------------------------------------------------------------------------- 1 | import documentationMD from "../../assets/OtherExtensions.md"; 2 | import { MarkDownPage } from "../MarkDownPage/MarkDownPage"; 3 | 4 | import styles from "./Extensions.module.scss"; 5 | 6 | export const Extensions = () => { 7 | return ( 8 | <MarkDownPage 9 | className={styles.Extensions} 10 | md={documentationMD} 11 | data-testid="Extensions"></MarkDownPage> 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Extensions/Extensions.lazy.js: -------------------------------------------------------------------------------- 1 | import { lazy, Suspense } from "react"; 2 | 3 | const LazyExtensions = lazy(() => import("./Extensions")), 4 | Extensions = (props) => ( 5 | <Suspense fallback={null}> 6 | <LazyExtensions {...props} /> 7 | </Suspense> 8 | ); 9 | 10 | export default Extensions; 11 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Extensions/Extensions.module.scss: -------------------------------------------------------------------------------- 1 | .Extentions { 2 | display: initial; 3 | } 4 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Extensions/ExtensionsToc.js: -------------------------------------------------------------------------------- 1 | import stylesApp from "../../App.module.scss"; 2 | import { Toc } from "../Toc/Toc"; 3 | 4 | import styles from "./Extensions.module.scss"; 5 | 6 | export const ExtensionsToc = () => { 7 | return ( 8 | <Toc 9 | contentSelector={`.${styles.Extensions}`} 10 | data-testid="ExtensionsToc" 11 | scrollContainer={`.${stylesApp.article}`}></Toc> 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Footer/Footer.js: -------------------------------------------------------------------------------- 1 | import styles from "./Footer.module.scss"; 2 | 3 | export const Footer = () => ( 4 | <div className={styles.Footer} data-testid="Footer"> 5 | Robin Herbots 6 | </div> 7 | ); 8 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Footer/Footer.lazy.js: -------------------------------------------------------------------------------- 1 | import React, { lazy, Suspense } from 'react'; 2 | 3 | const LazyFooter = lazy(() => import('./Footer')); 4 | 5 | const Footer = props => ( 6 | <Suspense fallback={null}> 7 | <LazyFooter {...props} /> 8 | </Suspense> 9 | ); 10 | 11 | export default Footer; 12 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Footer/Footer.module.scss: -------------------------------------------------------------------------------- 1 | @import "../../Shared/colors.scss"; 2 | 3 | .Footer { 4 | display: flex; 5 | flex-direction: row; 6 | border-top-color: $main-color; 7 | border-top-style: solid; 8 | border-top-width: 1px; 9 | margin: 10px 15px 0 15px; 10 | align-items: flex-end; 11 | justify-content: space-between; 12 | } 13 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Footer/Footer.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | import "@testing-library/jest-dom/extend-expect"; 3 | import { Footer } from "./Footer"; 4 | 5 | describe("<Footer />", () => { 6 | test("it should mount", () => { 7 | render(<Footer />); 8 | 9 | const footer = screen.getByTestId("Footer"); 10 | 11 | expect(footer).toBeInTheDocument(); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Header/Header.js: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom"; 2 | 3 | import logo from "../../assets/inputmask.svg"; 4 | import constants from "../../Shared/constants.module.scss"; 5 | import RouteNames from "../../Shared/RouteNames"; 6 | import { useViewPort } from "../ViewPort/ViewPort"; 7 | 8 | import styles from "./Header.module.scss"; 9 | 10 | export const Header = () => { 11 | const { width } = useViewPort(); 12 | 13 | return ( 14 | <div className={styles.Header} data-testid="Header"> 15 | {width <= constants.ScreenThreshold && ( 16 | <> 17 | <h3> 18 | <Link to={RouteNames.Home}>Inputmask</Link> 19 | </h3> 20 | <nav className={styles.navContainer}> 21 | <ul> 22 | <li> 23 | <a 24 | href="https://github.com/RobinHerbots/inputmask" 25 | target="_blank" 26 | rel="noreferrer"> 27 | View On <strong>GitHub</strong> 28 | </a> 29 | </li> 30 | </ul> 31 | </nav> 32 | </> 33 | )} 34 | {width > constants.ScreenThreshold && ( 35 | <> 36 | <h1> 37 | <Link to={RouteNames.Home}> 38 | <img src={logo} alt="Inputmask" width={120} /> 39 | </Link> 40 | </h1> 41 | <nav className={styles.navContainer}> 42 | <ul> 43 | <li> 44 | <a href="https://github.com/RobinHerbots/inputmask/zipball/5.x"> 45 | Download <strong>ZIP File</strong> 46 | </a> 47 | </li> 48 | <li> 49 | <a href="https://github.com/RobinHerbots/inputmask/tarball/5.x"> 50 | Download <strong>TAR Ball</strong> 51 | </a> 52 | </li> 53 | <li> 54 | <a 55 | href="https://github.com/RobinHerbots/inputmask" 56 | target="_blank" 57 | rel="noreferrer"> 58 | View On <strong>GitHub</strong> 59 | </a> 60 | </li> 61 | </ul> 62 | </nav> 63 | </> 64 | )} 65 | </div> 66 | ); 67 | }; 68 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Header/Header.lazy.js: -------------------------------------------------------------------------------- 1 | import { lazy, Suspense } from "react"; 2 | 3 | const LazyHeader = lazy(() => import("./Header")), 4 | Header = (props) => ( 5 | <Suspense fallback={null}> 6 | <LazyHeader {...props} /> 7 | </Suspense> 8 | ); 9 | 10 | export default Header; 11 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Header/Header.module.scss: -------------------------------------------------------------------------------- 1 | @import "../../Shared/colors.scss"; 2 | @import "../../Shared/constants.module.scss"; 3 | 4 | .Header { 5 | display: flex; 6 | flex-direction: row; 7 | border-bottom-color: $main-color; 8 | border-bottom-style: solid; 9 | border-bottom-width: 1px; 10 | margin: 0 15px 0 15px; 11 | align-items: flex-end; 12 | justify-content: space-between; 13 | @media only screen and (min-width: ($ScreenThreshold + 0px)) { 14 | margin-bottom: 10px; 15 | } 16 | 17 | & > H1, 18 | > H3 { 19 | user-select: none; 20 | margin-left: 20px; 21 | cursor: pointer; 22 | & > a { 23 | color: $main-color; 24 | text-decoration: none; 25 | } 26 | } 27 | } 28 | 29 | .navContainer { 30 | @media only screen and (min-width: ($ScreenThreshold + 0px)) { 31 | border-color: $main-color; 32 | border-style: solid; 33 | border-width: 1px; 34 | margin: 5px; 35 | border-radius: 5px; 36 | } 37 | 38 | & > ul { 39 | display: flex; 40 | flex-direction: row; 41 | list-style-type: none; 42 | padding: 0; 43 | margin: 0; 44 | margin-bottom: 1px; 45 | 46 | & > li { 47 | user-select: none; 48 | padding: 0; 49 | & > a { 50 | padding: 5px 10px 5px 10px; 51 | text-decoration: none; 52 | line-height: 1; 53 | font-size: 11px; 54 | color: $nav-link; 55 | display: block; 56 | text-align: center; 57 | & > strong { 58 | display: block; 59 | color: lighten($nav-link, 10); 60 | } 61 | & > img { 62 | height: 25px; 63 | width: 25px; 64 | vertical-align: middle; 65 | } 66 | } 67 | 68 | &:hover { 69 | background-color: $nav-background-hover; 70 | } 71 | } 72 | } 73 | 74 | & > a > img { 75 | height: 25px; 76 | width: 25px; 77 | vertical-align: middle; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Introduction/Introduction.js: -------------------------------------------------------------------------------- 1 | import browserstackLogo from "../../assets/browserstack-logo-600x315.png"; 2 | import introductionMD from "../../assets/Introduction.md"; 3 | // import jetbrainsLogo from "../../assets/jb_beam.svg"; 4 | import { MarkDownPage } from "../MarkDownPage/MarkDownPage"; 5 | 6 | export const Introduction = () => { 7 | return ( 8 | <MarkDownPage md={introductionMD} data-testid="Introduction"> 9 | {/* <a href="https://www.jetbrains.com/?from=inputmask"> 10 | <img src={jetbrainsLogo} alt="Jetbrains" width="65" /> 11 | </a> */} 12 | <a href="https://www.browserstack.com"> 13 | <img src={browserstackLogo} alt="Browserstack" width="150" /> 14 | </a> 15 | </MarkDownPage> 16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Introduction/Introduction.lazy.js: -------------------------------------------------------------------------------- 1 | import { lazy, Suspense } from "react"; 2 | 3 | const LazyIntroduction = lazy(() => import("./Introduction")); 4 | 5 | const Introduction = (props) => ( 6 | <Suspense fallback={null}> 7 | <LazyIntroduction {...props} /> 8 | </Suspense> 9 | ); 10 | 11 | export default Introduction; 12 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Introduction/Introduction.module.scss: -------------------------------------------------------------------------------- 1 | .Introduction { 2 | display: inline-flex; 3 | flex-grow: 1; 4 | flex-direction: column; 5 | max-width: inherit; 6 | & > a { 7 | vertical-align: middle; 8 | } 9 | & > pre { 10 | white-space: pre-wrap; 11 | } 12 | } -------------------------------------------------------------------------------- /inputmask-pages/src/Components/MarkDownPage/MarkDownPage.js: -------------------------------------------------------------------------------- 1 | import { createElement, Fragment, useEffect, useContext } from "react"; 2 | import rehypeAutolinkHeadings from "rehype-autolink-headings"; 3 | import rehypeHighlight from "rehype-highlight"; 4 | import rehypeReact from "rehype-react"; 5 | import rehypeSlug from "rehype-slug"; 6 | import remarkGfm from "remark-gfm"; 7 | import remarkParse from "remark-parse"; 8 | import remarkRehype from "remark-rehype"; 9 | import { unified } from "unified"; 10 | 11 | import styles from "./MarkDownPage.module.scss"; 12 | import "highlight.js/scss/github-dark-dimmed.scss"; 13 | import { MarkDownPageContext } from "./MarkDownPageContext"; 14 | 15 | export const MarkDownPage = (props) => { 16 | const { className, md, children } = props, 17 | { Content, setContent } = useContext(MarkDownPageContext); 18 | 19 | useEffect(() => { 20 | fetch(md) 21 | .then((res) => res.text()) 22 | .then((text) => 23 | unified() 24 | .use(remarkParse) 25 | .use(remarkGfm) 26 | .use(remarkRehype, { Fragment: true }) 27 | .use(rehypeSlug) 28 | .use(rehypeAutolinkHeadings) 29 | .use(rehypeHighlight, { detect: true }) 30 | .use(rehypeReact, { createElement, Fragment }) 31 | .process(text.replace(/{{year}}/g, new Date().getFullYear())) 32 | .then((file) => { 33 | setContent(file.result); 34 | }) 35 | ); 36 | return () => { 37 | setContent(<></>); 38 | }; 39 | }, [md, setContent]); 40 | 41 | return ( 42 | <div 43 | className={`${styles.MarkDownPage} ${className}`} 44 | data-testid="MarkDownPage"> 45 | {Content} 46 | {children} 47 | </div> 48 | ); 49 | }; 50 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/MarkDownPage/MarkDownPage.lazy.js: -------------------------------------------------------------------------------- 1 | import { lazy, Suspense } from "react"; 2 | 3 | const LazyMarkDownPage = lazy(() => import("./MarkDownPage")); 4 | 5 | const MarkDownPage = (props) => ( 6 | <Suspense fallback={null}> 7 | <LazyMarkDownPage {...props} /> 8 | </Suspense> 9 | ); 10 | 11 | export default MarkDownPage; 12 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/MarkDownPage/MarkDownPage.module.scss: -------------------------------------------------------------------------------- 1 | .MarkDownPage { 2 | display: flex; 3 | flex-grow: 1; 4 | flex-direction: column; 5 | & > pre { 6 | white-space: pre-wrap; 7 | } 8 | width: 100%; 9 | } -------------------------------------------------------------------------------- /inputmask-pages/src/Components/MarkDownPage/MarkDownPageContext.js: -------------------------------------------------------------------------------- 1 | import { createContext, useState, Fragment } from "react"; 2 | 3 | export const MarkDownPageContext = createContext(); 4 | 5 | export function MarkDownPageContextProvider({ children }) { 6 | const [Content, setContent] = useState(Fragment); 7 | 8 | return ( 9 | <MarkDownPageContext.Provider 10 | value={{ 11 | Content, 12 | setContent 13 | }}> 14 | {children} 15 | </MarkDownPageContext.Provider> 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Navigation/Navigation.js: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom"; 2 | 3 | import constants from "../../Shared/constants.module.scss"; 4 | import RouteNames from "../../Shared/RouteNames"; 5 | import { useViewPort } from "../ViewPort/ViewPort"; 6 | 7 | import styles from "./Navigation.module.scss"; 8 | 9 | export const Navigation = () => { 10 | const { width } = useViewPort(); 11 | return ( 12 | <nav className={styles.Navigation} data-testid="Navigation"> 13 | <ul> 14 | <li> 15 | <Link to={RouteNames.Documentation}> 16 | Open <strong>Documentation</strong> 17 | </Link> 18 | </li> 19 | <ul> 20 | <li> 21 | <Link to={RouteNames.Documentation_Extensions}> 22 | <strong>Extensions</strong> 23 | </Link> 24 | </li> 25 | <li> 26 | <Link to={RouteNames.Documentation_Datetime}> 27 | <strong>Datetime</strong> 28 | </Link> 29 | </li> 30 | <li> 31 | <Link to={RouteNames.Documentation_Numeric}> 32 | <strong>Numeric</strong> 33 | </Link> 34 | </li> 35 | <li> 36 | <Link to={RouteNames.Documentation_Colormask}> 37 | <strong>Colormask</strong> 38 | </Link> 39 | </li> 40 | </ul> 41 | {width > constants.ScreenThreshold && <hr />} 42 | </ul> 43 | <ul> 44 | <li> 45 | <Link to={RouteNames.Demo}> 46 | Open <strong>Demo</strong> 47 | </Link> 48 | </li> 49 | </ul> 50 | <ul> 51 | <li> 52 | <Link to={RouteNames.Changelog}> 53 | Open <strong>Changelog</strong> 54 | </Link> 55 | </li> 56 | </ul> 57 | </nav> 58 | ); 59 | }; 60 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Navigation/Navigation.lazy.js: -------------------------------------------------------------------------------- 1 | import { lazy, Suspense } from "react"; 2 | 3 | const LazyNavigation = lazy(() => import("./Navigation")), 4 | Navigation = (props) => ( 5 | <Suspense fallback={null}> 6 | <LazyNavigation {...props} /> 7 | </Suspense> 8 | ); 9 | 10 | export default Navigation; 11 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Navigation/Navigation.module.scss: -------------------------------------------------------------------------------- 1 | @import "../../Shared/colors.scss"; 2 | @import "../../Shared/constants.module.scss"; 3 | 4 | .Navigation { 5 | display: flex; 6 | flex-grow: 1; 7 | flex-direction: row; 8 | margin: 5px; 9 | border-bottom-style: solid; 10 | border-bottom-width: 1px; 11 | border-bottom-color: $main-color; 12 | min-width: min-content; 13 | align-self: center; 14 | @media only screen and (min-width: ($ScreenThreshold + 0px)) { 15 | align-self: initial; 16 | flex-direction: column; 17 | border-bottom-style: none; 18 | border-right-style: solid; 19 | border-right-width: 1px; 20 | border-right-color: $main-color; 21 | padding-right: 10px; 22 | } 23 | 24 | & ul { 25 | & > hr { 26 | width: 100%; 27 | } 28 | & > ul { 29 | flex-direction: row; 30 | @media only screen and (min-width: ($ScreenThreshold + 0px)) { 31 | flex-direction: column; 32 | margin-top: 10px; 33 | } 34 | } 35 | display: flex; 36 | flex-direction: column; 37 | list-style-type: none; 38 | padding: 0; 39 | margin: 0; 40 | @media only screen and (min-width: ($ScreenThreshold + 0px)) { 41 | margin-bottom: 15px; 42 | } 43 | 44 | & > li { 45 | padding: 0; 46 | user-select: none; 47 | & > a { 48 | padding: 5px 10px 5px 10px; 49 | text-decoration: none; 50 | line-height: 1; 51 | font-size: 11px; 52 | color: $nav-link; 53 | display: block; 54 | text-align: center; 55 | & > strong { 56 | display: block; 57 | color: lighten($nav-link, 10); 58 | } 59 | & > img { 60 | height: 25px; 61 | width: 25px; 62 | vertical-align: middle; 63 | } 64 | } 65 | 66 | &:hover { 67 | background-color: $nav-background-hover; 68 | } 69 | } 70 | } 71 | 72 | & > a > img { 73 | height: 25px; 74 | width: 25px; 75 | vertical-align: middle; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/NumericAlias/NumericAlias.js: -------------------------------------------------------------------------------- 1 | import documentationMD from "../../assets/NumericExtension.md"; 2 | import { MarkDownPage } from "../MarkDownPage/MarkDownPage"; 3 | 4 | import styles from "./NumericAlias.module.scss"; 5 | 6 | export const NumericAlias = () => { 7 | return ( 8 | <MarkDownPage 9 | className={styles.Numeric} 10 | md={documentationMD} 11 | data-testid="NumericAlias"></MarkDownPage> 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/NumericAlias/NumericAlias.lazy.js: -------------------------------------------------------------------------------- 1 | import { lazy, Suspense } from "react"; 2 | 3 | const LazyNumericAlias = lazy(() => import("./NumericAlias")), 4 | NumericAlias = (props) => ( 5 | <Suspense fallback={null}> 6 | <LazyNumericAlias {...props} /> 7 | </Suspense> 8 | ); 9 | 10 | export default NumericAlias; 11 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/NumericAlias/NumericAlias.module.scss: -------------------------------------------------------------------------------- 1 | .Numeric { 2 | display: inherit; 3 | } 4 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/NumericAlias/NumericAliasToc.js: -------------------------------------------------------------------------------- 1 | import stylesApp from "../../App.module.scss"; 2 | import { Toc } from "../Toc/Toc"; 3 | 4 | import styles from "./NumericAlias.module.scss"; 5 | 6 | export const NumericAliasToc = () => { 7 | return ( 8 | <Toc 9 | contentSelector={`.${styles.Numeric}`} 10 | data-testid="NumericAliasToc" 11 | scrollContainer={`.${stylesApp.article}`}></Toc> 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Toc/Toc.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useContext, useState, useCallback, useRef } from "react"; 2 | import { Link } from "react-router-dom"; 3 | 4 | import { MarkDownPageContext } from "../MarkDownPage/MarkDownPageContext"; 5 | 6 | import styles from "./Toc.module.scss"; 7 | 8 | export const Toc = (props) => { 9 | const { 10 | contentSelector, 11 | headingSelector = "h2, h3", 12 | title = "Table of contents", 13 | className = "", 14 | scrollContainer 15 | } = props, 16 | { Content } = useContext(MarkDownPageContext), 17 | lastSection = useRef([]), 18 | [Toc, setToc] = useState(), 19 | tocBuilder = useCallback((nodes, selectors, className = "") => { 20 | const [selector, ...other] = selectors, 21 | node = selector ? nodes.shift() : undefined; 22 | 23 | if (node) { 24 | if (node.tagName.toLowerCase() !== selector.toLowerCase()) { 25 | nodes.unshift(node); 26 | return <></>; 27 | } 28 | } 29 | 30 | return ( 31 | node && ( 32 | <> 33 | {node.tagName.toLowerCase() === selector.toLowerCase() && ( 34 | <ul> 35 | <li key={node.id} className={className}> 36 | <Link to={`#${node.id}`}>{node.innerText}</Link> 37 | {tocBuilder(nodes, other)} 38 | </li> 39 | </ul> 40 | )} 41 | {selector && tocBuilder(nodes, selectors, className)} 42 | </> 43 | ) 44 | ); 45 | }, []), 46 | scrollSpy = useCallback( 47 | (container, sections) => { 48 | function scrollSpyHandler() { 49 | sections.forEach((section) => { 50 | const top = section.offsetTop, 51 | id = section.getAttribute("id"), 52 | link = document.querySelector(`.${styles.Toc} a[href$="#${id}"]`); 53 | if (link) { 54 | if ( 55 | top >= container.scrollTop + container.offsetTop && 56 | top < container.scrollTop + container.offsetHeight 57 | ) { 58 | if ([...link.parentNode.classList].indexOf("close") !== -1) { 59 | link.parentNode.classList.remove("close"); 60 | link.parentNode.classList.add("open"); 61 | if (lastSection.current.indexOf(link.parentNode) === -1) 62 | lastSection.current.push(link.parentNode); 63 | } 64 | link.parentNode.classList.add("active"); 65 | } else { 66 | link.parentNode.classList.remove("active"); 67 | if ( 68 | lastSection.current.length > 1 && 69 | lastSection.current[0].querySelectorAll(".active").length === 70 | 0 71 | ) { 72 | const ulSection = lastSection.current.shift(); 73 | if ([...ulSection.classList].indexOf("open") !== -1) { 74 | ulSection.classList.remove("open"); 75 | ulSection.classList.add("close"); 76 | } 77 | } 78 | } 79 | } 80 | }); 81 | } 82 | container.addEventListener("scroll", scrollSpyHandler); 83 | return () => { 84 | container.removeEventListener("scroll", scrollSpyHandler); 85 | }; 86 | }, 87 | [lastSection] 88 | ); 89 | 90 | useEffect(() => { 91 | const contentContainer = document.querySelector(contentSelector), 92 | tocElements = contentContainer.querySelectorAll(headingSelector); 93 | setToc(tocBuilder([...tocElements], headingSelector.split(", "), "close")); 94 | scrollSpy(contentContainer.parentNode, [...tocElements]); 95 | setTimeout(() => { 96 | contentContainer.parentNode.dispatchEvent(new Event("scroll")); 97 | }, 0); 98 | 99 | return () => { 100 | setToc(<></>); 101 | }; 102 | }, [ 103 | Content, 104 | contentSelector, 105 | headingSelector, 106 | scrollContainer, 107 | scrollSpy, 108 | tocBuilder 109 | ]); 110 | 111 | return ( 112 | <div className={`${styles.Toc} ${className}`} data-testid="Toc"> 113 | <span>{title}</span> 114 | {Toc} 115 | </div> 116 | ); 117 | }; 118 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Toc/Toc.lazy.js: -------------------------------------------------------------------------------- 1 | import { lazy, Suspense } from "react"; 2 | 3 | const LazyToc = lazy(() => import("./Toc")); 4 | 5 | const Toc = (props) => ( 6 | <Suspense fallback={null}> 7 | <LazyToc {...props} /> 8 | </Suspense> 9 | ); 10 | 11 | export default Toc; 12 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/Toc/Toc.module.scss: -------------------------------------------------------------------------------- 1 | @import "../../Shared/colors.scss"; 2 | 3 | .Toc { 4 | :global { 5 | & ul { 6 | color: $main-color; 7 | & > li { 8 | &:hover { 9 | color: cyan; 10 | } 11 | &.close { 12 | list-style-type: disclosure-closed; 13 | & > ul { 14 | display: none; 15 | } 16 | } 17 | &.open { 18 | list-style-type: disclosure-open; 19 | color: cyan; 20 | } 21 | &.active { 22 | color: cyan; 23 | } 24 | list-style-type: square; 25 | } 26 | } 27 | 28 | & a { 29 | color: $main-color; 30 | text-decoration: none; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/ViewPort/ViewPort.js: -------------------------------------------------------------------------------- 1 | import { useContext } from "react"; 2 | 3 | import { ViewPortContext } from "./ViewPortContext"; 4 | 5 | export const useViewPort = () => { 6 | const { width, height } = { ...useContext(ViewPortContext) }; 7 | 8 | return { width, height }; 9 | }; 10 | -------------------------------------------------------------------------------- /inputmask-pages/src/Components/ViewPort/ViewPortContext.js: -------------------------------------------------------------------------------- 1 | import { createContext, useState, useEffect } from "react"; 2 | 3 | import { throttle } from "../../Shared/Throttle"; 4 | 5 | export const ViewPortContext = createContext({}); 6 | 7 | // eslint-disable-next-line one-var 8 | export const ViewPortProvider = ({ children }) => { 9 | // This is the exact same logic that we previously had in our hook 10 | 11 | const [width, setWidth] = useState(window.innerWidth), 12 | [height, setHeight] = useState(window.innerHeight), 13 | handleWindowResize = throttle(() => { 14 | setWidth(window.innerWidth); 15 | setHeight(window.innerHeight); 16 | }); 17 | 18 | useEffect(() => { 19 | window.addEventListener("resize", handleWindowResize); 20 | return () => window.removeEventListener("resize", handleWindowResize); 21 | }, [handleWindowResize]); 22 | 23 | return ( 24 | <ViewPortContext.Provider 25 | value={{ 26 | width, 27 | setWidth, 28 | height, 29 | setHeight 30 | }}> 31 | {children} 32 | </ViewPortContext.Provider> 33 | ); 34 | }; 35 | -------------------------------------------------------------------------------- /inputmask-pages/src/ErrorBoundary.js: -------------------------------------------------------------------------------- 1 | import { Component } from "react"; 2 | 3 | export class ErrorBoundary extends Component { 4 | constructor(props) { 5 | super(props); 6 | this.state = { hasError: false }; 7 | } 8 | 9 | // eslint-disable-next-line n/handle-callback-err 10 | static getDerivedStateFromError(error) { 11 | // Update state so the next render will show the fallback UI. 12 | return { hasError: true }; 13 | } 14 | 15 | componentDidCatch(error, errorInfo) { 16 | // You can also log the error to an error reporting service 17 | console.log(error, errorInfo); 18 | } 19 | 20 | render() { 21 | if (this.state.hasError) { 22 | // You can render any custom fallback UI 23 | return <h1>Something went wrong.</h1>; 24 | } 25 | 26 | return this.props.children; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /inputmask-pages/src/RoutingProvider.js: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | import { Route, Navigate, HashRouter } from "react-router-dom"; 3 | 4 | import { Changelog } from "./Components/Changelog/Changelog"; 5 | import { ChangelogToc } from "./Components/Changelog/ChangelogToc"; 6 | import { Colormask } from "./Components/Colormask/Colormask"; 7 | import { ColormaskToc } from "./Components/Colormask/ColormaskToc"; 8 | import { DatetimeAlias } from "./Components/DatetimeAlias/DatetimeAlias"; 9 | import { DatetimeAliasToc } from "./Components/DatetimeAlias/DatetimeAliasToc"; 10 | import { Demo } from "./Components/Demo/Demo"; 11 | import { Documentation } from "./Components/Documentation/Documentation"; 12 | import { DocumentationToc } from "./Components/Documentation/DocumentationToc"; 13 | import { Extensions } from "./Components/Extensions/Extensions"; 14 | import { ExtensionsToc } from "./Components/Extensions/ExtensionsToc"; 15 | import { Introduction } from "./Components/Introduction/Introduction"; 16 | import { NumericAlias } from "./Components/NumericAlias/NumericAlias"; 17 | import { NumericAliasToc } from "./Components/NumericAlias/NumericAliasToc"; 18 | import { HashFragments } from "./Shared/HashFragments"; 19 | import RouteNames from "./Shared/RouteNames"; 20 | 21 | export const RoutingContext = createContext({}); 22 | 23 | // eslint-disable-next-line one-var 24 | export const RoutingProvider = ({ children }) => { 25 | const routes = [ 26 | <Route 27 | key={RouteNames.Home} 28 | path={RouteNames.Home} 29 | element={<Introduction />} 30 | />, 31 | <Route 32 | key={RouteNames.Documentation} 33 | path={RouteNames.Documentation} 34 | element={ 35 | <HashFragments> 36 | <Documentation /> 37 | </HashFragments> 38 | } 39 | />, 40 | <Route 41 | key={RouteNames.Documentation_Extensions} 42 | path={RouteNames.Documentation_Extensions} 43 | element={ 44 | <HashFragments> 45 | <Extensions /> 46 | </HashFragments> 47 | } 48 | />, 49 | <Route 50 | key={RouteNames.Documentation_Datetime} 51 | path={RouteNames.Documentation_Datetime} 52 | element={ 53 | <HashFragments> 54 | <DatetimeAlias /> 55 | </HashFragments> 56 | } 57 | />, 58 | <Route 59 | key={RouteNames.Documentation_Numeric} 60 | path={RouteNames.Documentation_Numeric} 61 | element={ 62 | <HashFragments> 63 | <NumericAlias /> 64 | </HashFragments> 65 | } 66 | />, 67 | <Route 68 | key={RouteNames.Documentation_Colormask} 69 | path={RouteNames.Documentation_Colormask} 70 | element={ 71 | <HashFragments> 72 | <Colormask /> 73 | </HashFragments> 74 | } 75 | />, 76 | <Route key={RouteNames.Demo} path={RouteNames.Demo} element={<Demo />} />, 77 | <Route 78 | key={RouteNames.Changelog} 79 | path={RouteNames.Changelog} 80 | element={ 81 | <HashFragments> 82 | <Changelog /> 83 | </HashFragments> 84 | } 85 | />, 86 | <Route 87 | key="fallback" 88 | path="*" 89 | element={<Navigate to={RouteNames.Home} />} 90 | /> 91 | ], 92 | asideRoutes = [ 93 | <Route 94 | key={RouteNames.Documentation} 95 | path={RouteNames.Documentation} 96 | element={<DocumentationToc />} 97 | />, 98 | <Route 99 | key={RouteNames.Documentation_Extensions} 100 | path={RouteNames.Documentation_Extensions} 101 | element={<ExtensionsToc />} 102 | />, 103 | <Route 104 | key={RouteNames.Documentation_Datetime} 105 | path={RouteNames.Documentation_Datetime} 106 | element={<DatetimeAliasToc />} 107 | />, 108 | <Route 109 | key={RouteNames.Documentation_Numeric} 110 | path={RouteNames.Documentation_Numeric} 111 | element={<NumericAliasToc />} 112 | />, 113 | <Route 114 | key={RouteNames.Documentation_Colormask} 115 | path={RouteNames.Documentation_Colormask} 116 | element={<ColormaskToc />} 117 | />, 118 | <Route 119 | key={RouteNames.Changelog} 120 | path={RouteNames.Changelog} 121 | element={<ChangelogToc />} 122 | />, 123 | <Route key="fallback" path="*" element={<></>} /> 124 | ]; 125 | 126 | return ( 127 | <HashRouter> 128 | <RoutingContext.Provider 129 | value={{ 130 | routes, 131 | asideRoutes 132 | }}> 133 | {children} 134 | </RoutingContext.Provider> 135 | </HashRouter> 136 | ); 137 | }; 138 | -------------------------------------------------------------------------------- /inputmask-pages/src/Shared/HashFragments.js: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | import { useLocation } from "react-router-dom"; 3 | 4 | import styles from "../App.module.scss"; 5 | 6 | export const HashFragments = (props) => { 7 | const location = useLocation(), 8 | scrollToHashElement = () => { 9 | let { hash } = window.location; 10 | if (hash !== "") { 11 | setTimeout(() => { 12 | hash = hash.match(/#[^#]*$/)[0]; 13 | const id = hash.replace("#", ""), 14 | element = document.getElementById(id); 15 | if (element) { 16 | element.scrollIntoView(); 17 | } else { 18 | [ 19 | ...document.getElementsByClassName(`${styles.scrollable}`) 20 | ].forEach((element) => { 21 | element.scrollTo(0, 0); 22 | }); 23 | } 24 | }, 100); 25 | } 26 | }; 27 | 28 | useEffect(() => { 29 | scrollToHashElement(); 30 | }, [location]); 31 | 32 | return <>{props.children}</>; 33 | }; 34 | -------------------------------------------------------------------------------- /inputmask-pages/src/Shared/RouteNames.js: -------------------------------------------------------------------------------- 1 | export default { 2 | Home: "/", 3 | Documentation: "/documentation", 4 | Documentation_Extensions: "/documentation/extensions", 5 | Documentation_Datetime: "/documentation/datetime", 6 | Documentation_Numeric: "/documentation/numeric", 7 | Documentation_Colormask: "/documentation/colormask", 8 | Demo: "/demo", 9 | Factory: "/factory", 10 | Changelog: "/changelog" 11 | }; 12 | -------------------------------------------------------------------------------- /inputmask-pages/src/Shared/Throttle.js: -------------------------------------------------------------------------------- 1 | export function throttle(callbackFn, limit = 100) { 2 | let wait = false; 3 | return function () { 4 | if (!wait) { 5 | callbackFn.call(); 6 | wait = true; 7 | setTimeout(function () { 8 | wait = false; 9 | }, limit); 10 | } 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /inputmask-pages/src/Shared/colors.scss: -------------------------------------------------------------------------------- 1 | $main-background: black; 2 | $main-color: #c9d1d9; 3 | $link-color: lightblue; 4 | $link-color-visited: darken($color: lightblue, $amount: 25); 5 | $nav-link: lightgray; 6 | $nav-background-hover: #ffffff6e; 7 | $scrollbar-thumb: gray; 8 | $scrollbar-track: #ffffff40; 9 | $fired-background: #f58220; 10 | -------------------------------------------------------------------------------- /inputmask-pages/src/Shared/constants.module.scss: -------------------------------------------------------------------------------- 1 | $ScreenThreshold: 600; 2 | $AsideThreshold: 950; 3 | 4 | :export { 5 | ScreenThreshold: $ScreenThreshold; 6 | AsideThreshold: $AsideThreshold; 7 | } 8 | -------------------------------------------------------------------------------- /inputmask-pages/src/assets/Colormask.md: -------------------------------------------------------------------------------- 1 | # Colormask 2 | 3 | The colormask is the same as inputmask but allows you to specify a color for the mask. This is useful when you want to have a different color for the mask than the input text. 4 | 5 | ## Setup 6 | 7 | ### Classic web with <script\> tag 8 | 9 | Include the files which you can find in the `dist` folder. 10 | 11 | ```html 12 | <link rel="stylesheet" href="colormask.css" /> 13 | <script src="colormask.js"></script> 14 | ``` 15 | 16 | ### In your modules 17 | 18 | If you want to include the Inputmask and all extensions. 19 | 20 | ```javascript 21 | import "inputmask/dist/colormask.css"; 22 | import Colormask from "inputmask/dist/colormask.js"; 23 | ``` 24 | 25 | ## Usage 26 | 27 | First have a look at the stylesheet `colormask.css` to see how you can style the mask. Adjust the colors to your needs. 28 | 29 | Use it like the inputmask but with Colormask instead of Inputmask. 30 | -------------------------------------------------------------------------------- /inputmask-pages/src/assets/DatetimeExtension.md: -------------------------------------------------------------------------------- 1 | # datetime extensions 2 | 3 | Date and Time masks. 4 | 5 | ## Aliases 6 | 7 | - ### datetime 8 | 9 | ## Options 10 | 11 | ### inputFormat 12 | 13 | Format used to input the date 14 | 15 | ex: 16 | 17 | - dd/MM/yyyy 18 | - MM/dd/yyyy 19 | - dd.MM.yyyy HH:MM:ss 20 | 21 | ### Supported symbols 22 | 23 | - d 24 | Day of the month as digits; no leading zero for single-digit days. 25 | - dd 26 | Day of the month as digits; leading zero for single-digit days. 27 | - ddd 28 | Day of the week as a three-letter abbreviation. 29 | - dddd 30 | Day of the week as its full name. 31 | - m 32 | Month as digits; no leading zero for single-digit months. 33 | - MM 34 | Month as digits; leading zero for single-digit months. 35 | - MMM 36 | Month as a three-letter abbreviation. 37 | - MMMM 38 | Month as its full name. 39 | - yy 40 | Year as last two digits; leading zero for years less than 10. 41 | - yyyy 42 | Year as 4 digits. 43 | - h 44 | Hours; no leading zero for single-digit hours (12-hour clock). 45 | - hh 46 | Hours; leading zero for single-digit hours (12-hour clock). 47 | - hx 48 | Hours; no limit; x = number of digits ~ use as h2, h3, ... 49 | -H 50 | Hours; no leading zero for single-digit hours (24-hour clock). 51 | - HH 52 | Hours; leading zero for single-digit hours (24-hour clock). 53 | - Hx 54 | Hours; no limit; x = number of digits ~ use as H2, H3, ... 55 | - m 56 | Minutes; no leading zero for single-digit minutes. 57 | - mm 58 | Minutes; leading zero for single-digit minutes. 59 | - s 60 | Seconds; no leading zero for single-digit seconds. 61 | - ss 62 | Seconds; leading zero for single-digit seconds. 63 | - l 64 | Milliseconds. 3 digits. 65 | - L 66 | Milliseconds. 2 digits. 67 | - t 68 | Lowercase, single-character time marker string: a or p. 69 | - tt 70 | Two-character time marker string: am or pm. 71 | - T 72 | Single-character time marker string: A or P. 73 | - TT 74 | Two-character time marker string: AM or PM. 75 | - Z 76 | US timezone abbreviation, e.g. EST or MDT. With non-US timezones or in the Opera browser, the GMT/UTC offset is returned, e.g. GMT-0500 77 | - o 78 | GMT/UTC timezone offset, e.g. -0500 or +0230. 79 | - S 80 | The date's ordinal suffix (st, nd, rd, or th). Works well with d. 81 | 82 | ### Optional parts 83 | 84 | To mark a part of the inputFormat as optional, use the [] as you would for other masks. 85 | 86 | Ex. 87 | inputFormat: "dd/MM/yyyy [HH]" 88 | 89 | ### displayFormat 90 | 91 | Visual format when the input looses focus 92 | 93 | ### outputFormat 94 | 95 | Unmasking format 96 | 97 | ### min 98 | 99 | Minimum value. 100 | This needs to be in the same format as the inputformat. 101 | 102 | ### max 103 | 104 | Maximum value. 105 | This needs to be in the same format as the inputformat. 106 | 107 | ### prefillYear 108 | 109 | Enable/disable prefilling of the year. 110 | Default: true 111 | 112 | Although you can just over type the proposed value without deleting, many seems to see a problem with the year prediction. 113 | This options is to disable this feature. 114 | -------------------------------------------------------------------------------- /inputmask-pages/src/assets/Introduction.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 - {{year}} Robin Herbots Licensed under the MIT license (<https://opensource.org/licenses/MIT>) 2 | 3 | The Inputmask has a very permissive license and this will stay that way. But when you use the Inputmask in a commercial setting, be so honest to make a small donation. 4 | This will be appreciated very much. 5 | 6 | [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=ZNR3EB6JTMMSS) 7 | 8 |    9 | 10 | Inputmask is a javascript library that creates an input mask. Inputmask can run against vanilla javascript, jQuery, and jqlite. 11 | 12 | An inputmask helps the user with the input by ensuring a predefined format. This can be useful for dates, numerics, phone numbers, ... 13 | 14 | Highlights: 15 | 16 | - easy to use 17 | - optional parts anywhere in the mask 18 | - possibility to define aliases which hide the complexity 19 | - date / DateTime masks 20 | - numeric masks 21 | - lots of callbacks 22 | - non-greedy masks 23 | - many features can be enabled/disabled/configured by options 24 | - supports read-only/disabled/dir="rtl" attributes 25 | - support data-inputmask attribute(s) 26 | - alternator-mask 27 | - regex-mask 28 | - dynamic-mask 29 | - preprocessing-mask 30 | - JIT-masking 31 | - value formatting / validating without input element 32 | - AMD/CommonJS support 33 | - dependencyLibs: vanilla javascript, jQuery, jqlite 34 | - \<input-mask\> htmlelement 35 | 36 | Thanks to [Browserstack](https://www.browserstack.com) for providing a free license, so we can automate testing in different browsers and devices. 37 | -------------------------------------------------------------------------------- /inputmask-pages/src/assets/NumericExtension.md: -------------------------------------------------------------------------------- 1 | # numeric extensions 2 | 3 | ## Aliases 4 | 5 | - ### numeric 6 | 7 | - ### currency 8 | 9 | - ### decimal 10 | 11 | - ### integer 12 | 13 | - ### percentage 14 | 15 | The defaults are those defined in the base numeric alias. 16 | The currency alias and others are derived from the numeric alias and can have other defaults. 17 | Have a look in the inputmask.numeric.extensions.js for more details about which defaults are used. (At the end of the file) 18 | 19 | ## Options 20 | 21 | ### digits 22 | 23 | Number of fractionalDigits 24 | Default: "\*" 25 | 26 | The value can be a number, \*, or a quantifier syntax like 2,4 27 | When the quantifier syntax is used, the digitsOptional option is ignored 28 | 29 | Setting the numericInput option will make the digits a fixed length. 30 | Ex: passing digits: 2,4 will make the digits set to 2. 31 | 32 | ### digitsOptional 33 | 34 | Specify wheter the digits are optional. 35 | Default: true 36 | 37 | ### enforceDigitsOnBlur 38 | 39 | Enforces the decimal part when leaving the input field. 40 | Default: false 41 | 42 | ### radixPoint 43 | 44 | default: "." 45 | 46 | ### positionCaretOnClick 47 | 48 | Default: "radixFocus" 49 | 50 | ### groupSeparator 51 | 52 | Default: "" 53 | 54 | ### allowMinus 55 | 56 | Allow to enter -. 57 | Default: true 58 | 59 | ### negationSymbol 60 | 61 | Define your negationSymbol. 62 | Default: { 63 | front: "-", //"(" 64 | back: "" //")" 65 | } 66 | 67 | ### prefix 68 | 69 | Define a prefix. 70 | Default: "" 71 | 72 | ### suffix 73 | 74 | Define a suffix. 75 | Default: "" 76 | 77 | ### min 78 | 79 | Minimum value 80 | Default: undefined 81 | 82 | ### max 83 | 84 | Maximum value 85 | Default: undefined 86 | 87 | ### SetMaxOnOverflow 88 | 89 | Set the maximum value when the user types a number which is greater that the value of max. 90 | 91 | Default: false 92 | 93 | ### step 94 | 95 | Define the step the ctrl-up & ctrl-down must take. 96 | Default: 1 97 | 98 | ### inputType 99 | 100 | Specify that values which are set are in textform (radix point is same as in the options) or in numberform (radixpoint = .) 101 | 102 | Default: "text" 103 | 104 | text: radixpoint should be the same as in the options 105 | number: radixpoint should be a . as the default for a number in js 106 | 107 | ### unmaskAsNumber 108 | 109 | Make unmasking returning a number instead of a string. 110 | Default: false 111 | 112 | Be warned that using the unmaskAsNumber option together with jQuery.serialize will fail as serialize expects a string. (See issue [#1288]) 113 | 114 | [#1288]: https://github.com/RobinHerbots/jquery.inputmask/issues/1288 115 | 116 | ### roundingFN 117 | 118 | Set the fn for rounding the values when set. 119 | Default: Math.round 120 | 121 | Other examples: 122 | 123 | - Math.floor 124 | - fn(x) { /_do your own rounding logic_/ return x; } 125 | 126 | ### inputmode 127 | 128 | Default: "decimal" 129 | 130 | ### shortcuts 131 | 132 | Default: {k: "1000", m: "1000000"} 133 | 134 | Define shortcuts. 135 | This will allow typing 1k => 1000, 2m => 2000000 136 | 137 | To disable just pass shortcuts: null as option 138 | 139 | ### stripLeadingZeroes 140 | 141 | Default: true 142 | 143 | Strip leading zeroes. 144 | 145 | ### substituteRadixPoint 146 | 147 | Default: true 148 | 149 | Substitude the radixpoint to allow , for . and vice versa. 150 | 151 | ### Setting initial values 152 | 153 | When initializing the mask with a value, you need to take some rules into account. 154 | Depending of the option inputType the value will be interpreted as text or as a number. 155 | 156 | When inputType is text, the symbol of the radixPoint must be correct. When using number the . (dot) is used as radixpoint. 157 | 158 | Setting a number will always work when using vanilla javascript setters. 159 | 160 | Example with komma (,) as radixpoint 161 | 162 | ``` 163 | /html 164 | <input name="npt" value="123456,789"/> 165 | 166 | //js 167 | Inputmask("decimal", { 168 | radixPoint: ',', 169 | inputtype: "text" 170 | }).mask("input"); 171 | 172 | $("input").val("123456,789"); 173 | $("input").val(123456.789); //this doesn't work because jQuery converts the number to a string 174 | before passing it along to the Inputmask. 175 | 176 | document.getElementsByName("npt")[0].value = "123456,789"; 177 | document.getElementsByName("npt")[0].value = 123456.789; //type number 178 | 179 | ``` 180 | -------------------------------------------------------------------------------- /inputmask-pages/src/assets/OtherExtensions.md: -------------------------------------------------------------------------------- 1 | # other extensions 2 | 3 | ## Definitions 4 | 5 | - ### A : alphabetical uppercasing 6 | 7 | - ### & : alfanumeric uppercasing 8 | 9 | - ### \# : hexadecimal 10 | 11 | ## Aliases 12 | 13 | ### URL 14 | 15 | An URL mask for entering valid FTP, HTTP or HTTPS addresses. 16 | 17 | ```javascript 18 | Inputmask("url").mask(selector); 19 | ``` 20 | 21 | ### IP address 22 | 23 | An IP address alias for entering valid IP addresses. 24 | 25 | ```javascript 26 | Inputmask("ip").mask(selector); 27 | ``` 28 | 29 | ### Email 30 | 31 | An email mask for entering valid email addresses. 32 | 33 | ```javascript 34 | Inputmask("email").mask(selector); 35 | ``` 36 | 37 | ### MAC 38 | 39 | An MAC mask for entering valid MAC addresses. 40 | 41 | ```javascript 42 | Inputmask("mac").mask(selector); 43 | ``` 44 | 45 | ### VIN (Vehicle identification number) 46 | 47 | An VIN mask for entering valid VIN codes. 48 | 49 | ```javascript 50 | Inputmask("vin").mask(selector); 51 | ``` 52 | 53 | ### SSN (Social security number) 54 | 55 | An SSN mask for entering valid SSN numbers. 56 | 57 | ```javascript 58 | Inputmask("ssn").mask(selector); 59 | ``` 60 | 61 | You can find/modify/extend these aliases in the inputmask.extensions.js 62 | -------------------------------------------------------------------------------- /inputmask-pages/src/assets/browserstack-logo-600x315.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinHerbots/Inputmask/55dcd7e87bc74bbd9cdd67669fa6a6a589ba98eb/inputmask-pages/src/assets/browserstack-logo-600x315.png -------------------------------------------------------------------------------- /inputmask-pages/src/assets/github-mark-white.svg: -------------------------------------------------------------------------------- 1 | <svg width="98" height="96" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill="#fff"/></svg> -------------------------------------------------------------------------------- /inputmask-pages/src/assets/jb_beam.svg: -------------------------------------------------------------------------------- 1 | <svg height="180" viewBox="0 0 180 180" width="180" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="32.64" x2="82.77" y1="61.16" y2="85.54"><stop offset=".21" stop-color="#fe2857"/><stop offset="1" stop-color="#293896"/></linearGradient><linearGradient id="b" gradientUnits="userSpaceOnUse" x1="17.38" x2="82.95" y1="69.86" y2="21.23"><stop offset="0" stop-color="#fe2857"/><stop offset=".01" stop-color="#fe2857"/><stop offset=".86" stop-color="#ff318c"/></linearGradient><linearGradient id="c" gradientUnits="userSpaceOnUse" x1="74.17" x2="160.27" y1="21.58" y2="99.76"><stop offset=".02" stop-color="#ff318c"/><stop offset=".21" stop-color="#fe2857"/><stop offset=".86" stop-color="#fdb60d"/></linearGradient><linearGradient id="d" gradientUnits="userSpaceOnUse" x1="155.46" x2="55.07" y1="89.8" y2="158.9"><stop offset=".01" stop-color="#fdb60d"/><stop offset=".86" stop-color="#fcf84a"/></linearGradient><path d="m81.56 83.71-41.35-35a15 15 0 1 0 -14.47 25.7h.15l.39.12 52.16 15.89a3.53 3.53 0 0 0 1.18.21 3.73 3.73 0 0 0 1.93-6.91z" fill="url(#a)"/><path d="m89.85 25.93a10.89 10.89 0 0 0 -16.85-9.18l-50.5 30.66a15 15 0 1 0 17.9 24l45.27-36.89.36-.3a10.93 10.93 0 0 0 3.82-8.29z" fill="url(#b)"/><path d="m163.29 92-76.62-73.79a10.91 10.91 0 1 0 -14.81 16l.14.12 81.4 68.58a7.36 7.36 0 0 0 12.09-5.65 7.39 7.39 0 0 0 -2.2-5.26z" fill="url(#c)"/><path d="m165.5 97.29a7.35 7.35 0 0 0 -11.67-6l-92.71 45.3a15 15 0 1 0 15.48 25.59l85.73-58.84a7.35 7.35 0 0 0 3.17-6.05z" fill="url(#d)"/><path d="m60 60h60v60h-60z"/><g fill="#fff"><path d="m66.53 108.75h22.5v3.75h-22.5z"/><path d="m65.59 75.47 1.67-1.58a1.88 1.88 0 0 0 1.47.87c.64 0 1.06-.45 1.06-1.32v-5.92h2.58v5.94a3.44 3.44 0 0 1 -.92 2.63 3.52 3.52 0 0 1 -2.57 1 3.84 3.84 0 0 1 -3.29-1.62z"/><path d="m73.53 67.52h7.53v2.19h-5v1.43h4.49v2h-4.45v1.49h5v2.2h-7.6z"/><path d="m84.73 69.79h-2.8v-2.27h8.21v2.27h-2.81v7.09h-2.6z"/><path d="m66.63 80.58h4.42a3.47 3.47 0 0 1 2.55.83 2.09 2.09 0 0 1 .61 1.52 2.18 2.18 0 0 1 -1.45 2.09 2.27 2.27 0 0 1 1.86 2.29c0 1.69-1.31 2.69-3.55 2.69h-4.44zm5 2.89c0-.52-.42-.8-1.18-.8h-1.29v1.64h1.25c.78 0 1.24-.27 1.24-.81zm-.9 2.66h-1.57v1.73h1.62c.8 0 1.24-.31 1.24-.86-.02-.53-.4-.87-1.27-.87z"/><path d="m75.45 80.58h4.15a4.14 4.14 0 0 1 3.05 1 2.92 2.92 0 0 1 .83 2.18 3 3 0 0 1 -1.93 2.89l2.24 3.35h-3l-1.89-2.84h-.87v2.84h-2.6zm4 4.5c.87 0 1.4-.43 1.4-1.12 0-.75-.55-1.13-1.41-1.13h-1.39v2.27z"/><path d="m87.09 80.51h2.5l4 9.44h-2.79l-.67-1.69h-3.63l-.67 1.74h-2.71zm2.28 5.73-1.05-2.65-1.06 2.65z"/><path d="m94 80.55h2.6v9.37h-2.6z"/><path d="m97.56 80.55h2.44l3.37 5v-5h2.57v9.37h-2.27l-3.53-5.14v5.14h-2.58z"/><path d="m106.37 88.53 1.44-1.73a4.86 4.86 0 0 0 3 1.13c.71 0 1.08-.25 1.08-.65 0-.41-.3-.61-1.59-.91-2-.46-3.53-1-3.53-2.93 0-1.74 1.38-3 3.63-3a5.88 5.88 0 0 1 3.85 1.25l-1.25 1.78a4.56 4.56 0 0 0 -2.62-.92c-.63 0-.94.25-.94.6 0 .43.32.62 1.63.91 2.15.47 3.48 1.17 3.48 2.92 0 1.91-1.51 3-3.78 3a6.56 6.56 0 0 1 -4.4-1.45z"/></g><path d="m0 0h180v180h-180z" fill="none"/></svg> -------------------------------------------------------------------------------- /inputmask-pages/src/index.js: -------------------------------------------------------------------------------- 1 | import { Suspense, StrictMode } from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | 4 | import "./index.scss"; 5 | import App from "./App"; 6 | import { MarkDownPageContextProvider } from "./Components/MarkDownPage/MarkDownPageContext"; 7 | import { ViewPortProvider } from "./Components/ViewPort/ViewPortContext"; 8 | import { ErrorBoundary } from "./ErrorBoundary"; 9 | import reportWebVitals from "./reportWebVitals"; 10 | import { RoutingProvider } from "./RoutingProvider"; 11 | 12 | const root = ReactDOM.createRoot(document.getElementById("root")); 13 | root.render( 14 | <StrictMode> 15 | <ErrorBoundary> 16 | <ViewPortProvider> 17 | <RoutingProvider> 18 | <MarkDownPageContextProvider> 19 | <Suspense fallback="loading..."> 20 | <App /> 21 | </Suspense> 22 | </MarkDownPageContextProvider> 23 | </RoutingProvider> 24 | </ViewPortProvider> 25 | </ErrorBoundary> 26 | </StrictMode> 27 | ); 28 | 29 | // If you want to start measuring performance in your app, pass a function 30 | // to log results (for example: reportWebVitals(console.log)) 31 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 32 | reportWebVitals(); 33 | -------------------------------------------------------------------------------- /inputmask-pages/src/index.scss: -------------------------------------------------------------------------------- 1 | @import-normalize; 2 | @import "Shared/colors.scss"; 3 | 4 | html { 5 | background-color: $main-background; 6 | color: $main-color; 7 | height: 100vh; 8 | } 9 | 10 | body { 11 | height: inherit; 12 | margin: 0; 13 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 14 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 15 | sans-serif; 16 | -webkit-font-smoothing: antialiased; 17 | -moz-osx-font-smoothing: grayscale; 18 | overflow: hidden; 19 | } 20 | 21 | code { 22 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 23 | monospace; 24 | } 25 | 26 | #root { 27 | height: inherit; 28 | display: flex; 29 | } 30 | -------------------------------------------------------------------------------- /inputmask-pages/src/logo.svg: -------------------------------------------------------------------------------- 1 | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg> -------------------------------------------------------------------------------- /inputmask-pages/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = (onPerfEntry) => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import("web-vitals").then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /inputmask-pages/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import "@testing-library/jest-dom"; 6 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Thu Feb 10 2022 10:05:16 GMT+0100 (GMT+01:00) 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | // base path that will be used to resolve all patterns (eg. files, exclude) 7 | basePath: "", 8 | 9 | // frameworks to use 10 | // available frameworks: https://www.npmjs.com/search?q=keywords:karma-adapter 11 | frameworks: ["qunit"], 12 | 13 | // list of files / patterns to load in the browser 14 | files: ["node_modules/jquery/dist/jquery.js", "qunit/qunit.js"], 15 | 16 | // list of files / patterns to exclude 17 | exclude: [], 18 | 19 | // preprocess matching files before serving them to the browser 20 | // available preprocessors: https://www.npmjs.com/search?q=keywords:karma-preprocessor 21 | preprocessors: {}, 22 | 23 | // test results reporter to use 24 | // possible values: 'dots', 'progress' 25 | // available reporters: https://www.npmjs.com/search?q=keywords:karma-reporter 26 | reporters: ["progress", "BrowserStack"], 27 | 28 | // web server port 29 | port: 9876, 30 | 31 | // enable / disable colors in the output (reporters and logs) 32 | colors: true, 33 | 34 | // level of logging 35 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 36 | logLevel: config.LOG_INFO, 37 | 38 | // enable / disable watching file and executing tests whenever any file changes 39 | autoWatch: false, 40 | 41 | // start these browsers 42 | // available browser launchers: https://www.npmjs.com/search?q=keywords:karma-launcher 43 | // global config of your BrowserStack account 44 | browserStack: { 45 | username: "BROWSERSTACK_USERNAME", 46 | accessKey: "BROWSERSTACK_ACCESS_KEY" 47 | }, 48 | 49 | // define browsers 50 | customLaunchers: { 51 | bs_chrome96_win11: { 52 | base: "BrowserStack", 53 | browser: "chrome", 54 | browser_version: "96", 55 | os: "Windows", 56 | os_version: "11" 57 | }, 58 | bs_chrome_win11: { 59 | base: "BrowserStack", 60 | browser: "chrome", 61 | os: "Windows", 62 | os_version: "11" 63 | }, 64 | bs_chrome_mac_Monterey: { 65 | base: "BrowserStack", 66 | browser: "chrome", 67 | os: "OS X", 68 | os_version: "Monterey" 69 | }, 70 | bs_firefox_win11: { 71 | base: "BrowserStack", 72 | browser: "firefox", 73 | os: "Windows", 74 | os_version: "11" 75 | }, 76 | bs_edge_win11: { 77 | base: "BrowserStack", 78 | browser: "edge", 79 | os: "Windows", 80 | os_version: "11" 81 | }, 82 | bs_safari_mac_Monterey: { 83 | base: "BrowserStack", 84 | browser: "safari", 85 | os: "OS X", 86 | os_version: "Monterey" 87 | }, 88 | bs_opera_win11: { 89 | base: "BrowserStack", 90 | browser: "opera", 91 | os: "Windows", 92 | os_version: "11" 93 | }, 94 | bs_yandex_win11: { 95 | base: "BrowserStack", 96 | browser: "yandex", 97 | os: "Windows", 98 | os_version: "11" 99 | }, 100 | bs_ie_win10: { 101 | base: "BrowserStack", 102 | browser: "ie", 103 | browser_version: "11", 104 | os: "Windows", 105 | os_version: "10" 106 | }, 107 | bs_chrome_pixel6: { 108 | base: "BrowserStack", 109 | device: "Google Pixel 6", 110 | browser: "chrome", 111 | os: "Android", 112 | os_version: "12.0", 113 | realMobile: true 114 | }, 115 | bs_chrome_samsung_galaxy_S21: { 116 | base: "BrowserStack", 117 | device: "Samsung Galaxy S21", 118 | browser: "chrome", 119 | os: "Android", 120 | os_version: "11.0", 121 | realMobile: true 122 | }, 123 | bs_iPhoneXS: { 124 | base: "BrowserStack", 125 | device: "iPhone XS", 126 | browser: "safari", 127 | os: "IOS", 128 | os_version: "15", 129 | realMobile: true 130 | } 131 | }, 132 | browsers: [ 133 | "Chrome", 134 | "bs_chrome_win11", 135 | "bs_chrome_mac_Monterey", 136 | "bs_firefox_win11", 137 | "bs_edge_win11", 138 | "bs_safari_mac_Monterey", 139 | "bs_opera_win11", 140 | // "bs_yandex_win11", 141 | "bs_ie_win10", 142 | "bs_chrome_pixel6", 143 | "bs_chrome_samsung_galaxy_S21", 144 | "bs_iPhoneXS" 145 | ], 146 | 147 | // Continuous Integration mode 148 | // if true, Karma captures browsers, runs the tests and exits 149 | singleRun: false, 150 | 151 | // Concurrency level 152 | // how many browser instances should be started simultaneously 153 | concurrency: Infinity 154 | }); 155 | }; 156 | -------------------------------------------------------------------------------- /lib/bindings/inputmask.binding.js: -------------------------------------------------------------------------------- 1 | /* 2 | Input Mask plugin binding 3 | http://github.com/RobinHerbots/jquery.inputmask 4 | Copyright (c) Robin Herbots 5 | Licensed under the MIT license 6 | */ 7 | (function (factory) { 8 | factory(jQuery, window.Inputmask, window); 9 | })(function ($, Inputmask, window) { 10 | $(window.document) 11 | .ajaxComplete(function (event, xmlHttpRequest, ajaxOptions) { 12 | if ($.inArray("html", ajaxOptions.dataTypes) !== -1) { 13 | $( 14 | ".inputmask, [data-inputmask], [data-inputmask-mask], [data-inputmask-alias], [data-inputmask-regex]" 15 | ).each(function (ndx, lmnt) { 16 | if (lmnt.inputmask === undefined) { 17 | Inputmask().mask(lmnt); 18 | } 19 | }); 20 | } 21 | }) 22 | .ready(function () { 23 | $( 24 | ".inputmask, [data-inputmask], [data-inputmask-mask], [data-inputmask-alias],[data-inputmask-regex]" 25 | ).each(function (ndx, lmnt) { 26 | if (lmnt.inputmask === undefined) { 27 | Inputmask().mask(lmnt); 28 | } 29 | }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /lib/bindings/inputmask.es6.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line import/no-unresolved 2 | import "./inputmask.js"; 3 | 4 | const inputmask = window.Inputmask; 5 | window.Inputmask = undefined; 6 | export default inputmask; 7 | -------------------------------------------------------------------------------- /lib/defaults.js: -------------------------------------------------------------------------------- 1 | export default { 2 | _maxTestPos: 500, 3 | placeholder: "_", 4 | optionalmarker: ["[", "]"], 5 | quantifiermarker: ["{", "}"], 6 | groupmarker: ["(", ")"], 7 | alternatormarker: "|", 8 | escapeChar: "\\", 9 | mask: null, // needs tobe null instead of undefined as the extend method does not consider props with the undefined value 10 | regex: null, // regular expression as a mask 11 | oncomplete: () => {}, // executes when the mask is complete 12 | onincomplete: () => {}, // executes when the mask is incomplete and focus is lost 13 | oncleared: () => {}, // executes when the mask is cleared 14 | repeat: 0, // repetitions of the mask: * ~ forever, otherwise specify an integer 15 | greedy: false, // true: allocated buffer for the mask and repetitions - false: allocate only if needed 16 | autoUnmask: false, // automatically unmask when retrieving the value with $.fn.val or value if the browser supports __lookupGetter__ or getOwnPropertyDescriptor 17 | removeMaskOnSubmit: false, // remove the mask before submitting the form. 18 | clearMaskOnLostFocus: true, 19 | insertMode: true, // insert the input or overwrite the input 20 | insertModeVisual: true, // show selected caret when insertmode = false 21 | clearIncomplete: false, // clear the incomplete input on blur 22 | alias: null, 23 | onKeyDown: () => {}, // callback to implement autocomplete on certain keys for example. args => event, buffer, caretPos, opts 24 | onBeforeMask: null, // executes before masking the initial value to allow preprocessing of the initial value. args => initialValue, opts => return processedValue 25 | onBeforePaste: function (pastedValue, opts) { 26 | return typeof opts.onBeforeMask === "function" 27 | ? opts.onBeforeMask.call(this, pastedValue, opts) 28 | : pastedValue; 29 | }, // executes before masking the pasted value to allow preprocessing of the pasted value. args => pastedValue, opts => return processedValue 30 | onBeforeWrite: null, // executes before writing to the masked element. args => event, opts 31 | onUnMask: null, // executes after unmasking to allow postprocessing of the unmaskedvalue. args => maskedValue, unmaskedValue, opts 32 | outputMask: null, // mask to apply when unmasking 33 | showMaskOnFocus: true, // show the mask-placeholder when the input has focus 34 | showMaskOnHover: true, // show the mask-placeholder when hovering the empty input 35 | onKeyValidation: () => {}, // executes on every key-press with the result of isValid. Params: key, result, opts 36 | skipOptionalPartCharacter: " ", // a character which can be used to skip an optional part of a mask 37 | numericInput: false, // numericInput input direction style (input shifts to the left while holding the caret position) 38 | rightAlign: false, // align to the right 39 | undoOnEscape: true, // pressing escape reverts the value to the value before focus 40 | // numeric basic properties 41 | radixPoint: "", // ".", // | "," 42 | _radixDance: false, // dance around the radixPoint 43 | groupSeparator: "", // ",", // | "." 44 | // numeric basic properties 45 | keepStatic: null, // try to keep the mask static while typing. Decisions to alter the mask will be posponed if possible 46 | positionCaretOnTab: true, // when enabled the caret position is set after the latest valid position on TAB 47 | tabThrough: false, // allows for tabbing through the different parts of the masked field 48 | supportsInputType: ["text", "tel", "url", "password", "search"], // list with the supported input types 49 | isComplete: null, // override for isComplete - args => buffer, opts - return true || false 50 | preValidation: null, // hook to preValidate the input. Usefull for validating regardless the definition. args => buffer, pos, char, isSelection, opts, maskset, caretPos, strict => return true/false/command object 51 | postValidation: null, // hook to postValidate the result from isValid. Usefull for validating the entry as a whole. args => buffer, pos, c, currentResult, opts, maskset, strict, fromCheckval, fromAlternate => return true/false/json 52 | staticDefinitionSymbol: undefined, // specify a definitionSymbol for static content, used to make matches for alternators 53 | jitMasking: false, // just in time masking ~ only mask while typing, can n (number), true or false 54 | nullable: true, // return nothing instead of the buffertemplate when the user hasn't entered anything. 55 | inputEventOnly: false, // dev option - testing inputfallback behavior 56 | noValuePatching: false, // disable value property patching 57 | positionCaretOnClick: "lvp", // none, lvp (based on the last valid position (default), radixFocus (position caret to radixpoint on initial click), select (select the whole input), ignore (ignore the click and continue the mask) 58 | casing: null, // mask-level casing. Options: null, "upper", "lower" or "title" or callback args => elem, test, pos, validPositions return charValue 59 | inputmode: "text", // specify the inputmode 60 | importDataAttributes: true, // import data-inputmask attributes 61 | shiftPositions: true, // shift position of the mask entries on entry and deletion. 62 | usePrototypeDefinitions: true, // use the default defined definitions from the prototype 63 | validationEventTimeOut: 3000, // Time to show validation error on form submit 64 | substitutes: {} // define character substitutes 65 | }; 66 | -------------------------------------------------------------------------------- /lib/definitions.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 9: { 3 | validator: "\\p{N}", 4 | definitionSymbol: "*" 5 | }, 6 | a: { 7 | validator: "\\p{L}", 8 | definitionSymbol: "*" 9 | }, 10 | "*": { 11 | validator: "[\\p{L}\\p{N}]" 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /lib/dependencyLibs/data.js: -------------------------------------------------------------------------------- 1 | export default function (owner, key, value) { 2 | if (value === undefined) { 3 | return owner.__data ? owner.__data[key] : null; 4 | } else { 5 | owner.__data = owner.__data || {}; 6 | owner.__data[key] = value; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /lib/dependencyLibs/events.js: -------------------------------------------------------------------------------- 1 | import window from "../global/window"; 2 | 3 | import data from "./data"; 4 | import extend from "./extend"; 5 | import DependencyLib from "./inputmask.dependencyLib"; 6 | 7 | export { on, off, trigger, Evnt as Event }; 8 | 9 | const document = window.document; 10 | 11 | function isValidElement(elem) { 12 | return elem instanceof Element && data(elem, "events"); 13 | } 14 | 15 | let Evnt; 16 | if (typeof window.CustomEvent === "function") { 17 | Evnt = window.CustomEvent; 18 | } else if (window.Event && document && document.createEvent) { 19 | Evnt = function (event, params) { 20 | params = params || { 21 | bubbles: false, 22 | cancelable: false, 23 | composed: true, 24 | detail: undefined 25 | }; 26 | const evt = document.createEvent("CustomEvent"); 27 | evt.initCustomEvent( 28 | event, 29 | params.bubbles, 30 | params.cancelable, 31 | params.detail 32 | ); 33 | return evt; 34 | }; 35 | Evnt.prototype = window.Event.prototype; 36 | } else if (typeof Event !== "undefined") { 37 | // nodejs 38 | Evnt = Event; 39 | } 40 | 41 | function on(events, handler) { 42 | if (!this[0] || !isValidElement(this[0])) { 43 | return this; // Early return if no valid element 44 | } 45 | 46 | const elem = this[0], 47 | eventRegistry = data(elem, "events"), 48 | addEvent = (ev, namespace) => { 49 | // register domevent 50 | if (elem.addEventListener) { 51 | // all browsers except IE before version 9 52 | elem.addEventListener(ev, handler, false); 53 | } else if (elem.attachEvent) { 54 | // IE before version 9 55 | elem.attachEvent(`on${ev}`, handler); 56 | } 57 | eventRegistry[ev] = eventRegistry[ev] || {}; 58 | eventRegistry[ev][namespace] = eventRegistry[ev][namespace] || []; 59 | eventRegistry[ev][namespace].push(handler); 60 | }; 61 | 62 | events.split(" ").forEach((event) => { 63 | const [ev, namespace = "global"] = event.split("."); 64 | addEvent(ev, namespace); 65 | }); 66 | 67 | return this; 68 | } 69 | 70 | function off(events, handler) { 71 | let eventRegistry, elem; 72 | 73 | function removeEvent(ev, namespace, handler) { 74 | if (ev in eventRegistry === true) { 75 | // unbind to dom events 76 | if (elem.removeEventListener) { 77 | // all browsers except IE before version 9 78 | elem.removeEventListener(ev, handler, false); 79 | } else if (elem.detachEvent) { 80 | // IE before version 9 81 | elem.detachEvent(`on${ev}`, handler); 82 | } 83 | // when the namespace is not defined (global namespace), we need to clean up all events in all namespaces 84 | if (namespace === "global") { 85 | for (const nmsp in eventRegistry[ev]) { 86 | eventRegistry[ev][nmsp].splice( 87 | eventRegistry[ev][nmsp].indexOf(handler), 88 | 1 89 | ); 90 | } 91 | } else { 92 | eventRegistry[ev][namespace].splice( 93 | eventRegistry[ev][namespace].indexOf(handler), 94 | 1 95 | ); 96 | } 97 | } 98 | } 99 | 100 | function resolveNamespace(ev, namespace) { 101 | const evts = []; 102 | let hndx, hndL; 103 | if (ev.length > 0) { 104 | const namespaces = namespace 105 | ? [namespace] 106 | : Object.keys(eventRegistry[ev]); 107 | for (let nsi = 0; nsi < namespaces.length; nsi++) { 108 | namespace = namespaces[nsi]; 109 | if (handler === undefined) { 110 | for ( 111 | hndx = 0, hndL = eventRegistry[ev][namespace]?.length || 0; 112 | hndx < hndL; 113 | hndx++ 114 | ) { 115 | evts.push({ 116 | ev, 117 | namespace, 118 | handler: eventRegistry[ev][namespace][hndx] 119 | }); 120 | } 121 | } else { 122 | evts.push({ 123 | ev, 124 | namespace, 125 | handler 126 | }); 127 | } 128 | } 129 | } else if (namespace.length > 0) { 130 | for (const evNdx in eventRegistry) { 131 | if (eventRegistry[evNdx][namespace]) { 132 | if (handler === undefined) { 133 | for ( 134 | hndx = 0, hndL = eventRegistry[evNdx][namespace].length; 135 | hndx < hndL; 136 | hndx++ 137 | ) { 138 | evts.push({ 139 | ev: evNdx, 140 | namespace, 141 | handler: eventRegistry[evNdx][namespace][hndx] 142 | }); 143 | } 144 | } else { 145 | evts.push({ 146 | ev: evNdx, 147 | namespace, 148 | handler 149 | }); 150 | } 151 | } 152 | } 153 | } 154 | 155 | return evts; 156 | } 157 | 158 | if (isValidElement(this[0])) { 159 | eventRegistry = data(this[0], "events"); 160 | elem = this[0]; 161 | // if no events defined, remove all events 162 | events = events || Object.keys(eventRegistry).join(" "); 163 | 164 | if (events !== "") { 165 | events.split(" ").forEach((event) => { 166 | const [ev, namespace] = event.split("."); 167 | resolveNamespace(ev, namespace).forEach( 168 | ({ ev: ev1, handler: handler1, namespace: namespace1 }) => { 169 | removeEvent(ev1, namespace1, handler1); 170 | } 171 | ); 172 | }); 173 | } 174 | } 175 | return this; 176 | } 177 | 178 | function trigger(events /* , args... */) { 179 | if (isValidElement(this[0])) { 180 | const eventRegistry = data(this[0], "events"), 181 | elem = this[0], 182 | _events = typeof events === "string" ? events.split(" ") : [events.type]; 183 | for (let endx = 0; endx < _events.length; endx++) { 184 | const nsEvent = _events[endx].split("."), 185 | ev = nsEvent[0], 186 | namespace = nsEvent[1] || "global"; 187 | if (document !== undefined) { 188 | // trigger domevent 189 | let evnt; 190 | const params = { 191 | bubbles: true, 192 | cancelable: true, 193 | composed: true, 194 | detail: arguments[1] 195 | }; 196 | // The custom event that will be created 197 | if (document.createEvent) { 198 | try { 199 | switch (ev) { 200 | case "input": 201 | params.inputType = "insertText"; 202 | evnt = new InputEvent(ev, params); 203 | break; 204 | default: 205 | evnt = new CustomEvent(ev, params); 206 | } 207 | } catch (e) { 208 | evnt = document.createEvent("CustomEvent"); 209 | evnt.initCustomEvent( 210 | ev, 211 | params.bubbles, 212 | params.cancelable, 213 | params.detail 214 | ); 215 | } 216 | if (events.type) extend(evnt, events); 217 | elem.dispatchEvent(evnt); 218 | } else { 219 | evnt = document.createEventObject(); 220 | evnt.eventType = ev; 221 | evnt.detail = arguments[1]; 222 | if (events.type) extend(evnt, events); 223 | elem.fireEvent("on" + evnt.eventType, evnt); 224 | } 225 | } else if (eventRegistry[ev] !== undefined) { 226 | arguments[0] = arguments[0].type 227 | ? arguments[0] 228 | : DependencyLib.Event(arguments[0]); 229 | arguments[0].detail = arguments.slice(1); 230 | 231 | const registry = eventRegistry[ev], 232 | handlers = 233 | namespace === "global" 234 | ? Object.values(registry).flat() 235 | : registry[namespace]; 236 | handlers.forEach((handler) => handler.apply(elem, arguments)); 237 | } 238 | } 239 | } 240 | return this; 241 | } 242 | -------------------------------------------------------------------------------- /lib/dependencyLibs/extend.js: -------------------------------------------------------------------------------- 1 | export default function extend() { 2 | let options, 3 | name, 4 | src, 5 | copy, 6 | copyIsArray, 7 | clone, 8 | target = arguments[0] || {}, 9 | i = 1, 10 | length = arguments.length, 11 | deep = false; 12 | 13 | // Handle a deep copy situation 14 | if (typeof target === "boolean") { 15 | deep = target; 16 | 17 | // Skip the boolean and the target 18 | target = arguments[i] || {}; 19 | i++; 20 | } 21 | 22 | // Handle case when target is a string or something (possible in deep copy) 23 | if (typeof target !== "object" && typeof target !== "function") { 24 | target = {}; 25 | } 26 | 27 | for (; i < length; i++) { 28 | // Only deal with non-null/undefined values 29 | if ((options = arguments[i]) != null) { 30 | // Extend the base object 31 | for (name in options) { 32 | src = target[name]; 33 | copy = options[name]; 34 | 35 | // Prevent never-ending loop 36 | if (target === copy) { 37 | continue; 38 | } 39 | 40 | // Recurse if we're merging plain objects or arrays 41 | if ( 42 | deep && 43 | copy && 44 | (Object.prototype.toString.call(copy) === "[object Object]" || 45 | (copyIsArray = Array.isArray(copy))) 46 | ) { 47 | if (copyIsArray) { 48 | copyIsArray = false; 49 | clone = src && Array.isArray(src) ? src : []; 50 | } else { 51 | clone = 52 | src && Object.prototype.toString.call(src) === "[object Object]" 53 | ? src 54 | : {}; 55 | } 56 | 57 | // Never move original objects, clone them 58 | target[name] = extend(deep, clone, copy); 59 | 60 | // Don't bring in undefined values 61 | } else if (copy !== undefined) { 62 | target[name] = copy; 63 | } 64 | } 65 | } 66 | } 67 | 68 | // Return the modified object 69 | return target; 70 | } 71 | -------------------------------------------------------------------------------- /lib/dependencyLibs/inputmask.dependencyLib.jquery.js: -------------------------------------------------------------------------------- 1 | /* 2 | Input Mask plugin dependencyLib 3 | http://github.com/RobinHerbots/jquery.inputmask 4 | Copyright (c) Robin Herbots 5 | Licensed under the MIT license 6 | */ 7 | 8 | import jQuery from "jquery"; 9 | 10 | if (jQuery === undefined) { 11 | throw new Error("jQuery not loaded!"); 12 | } 13 | export default jQuery; 14 | -------------------------------------------------------------------------------- /lib/dependencyLibs/inputmask.dependencyLib.js: -------------------------------------------------------------------------------- 1 | /* 2 | Input Mask plugin dependencyLib 3 | http://github.com/RobinHerbots/jquery.inputmask 4 | Copyright (c) Robin Herbots 5 | Licensed under the MIT license 6 | */ 7 | 8 | import window from "../global/window"; 9 | 10 | import data from "./data"; 11 | import { on, off, trigger, Event } from "./events"; 12 | import extend from "./extend"; 13 | 14 | const document = window.document; 15 | 16 | function DependencyLib(elem) { 17 | if (elem instanceof DependencyLib) { 18 | return elem; 19 | } 20 | if (!(this instanceof DependencyLib)) { 21 | return new DependencyLib(elem); 22 | } 23 | if (elem !== undefined && elem !== null && elem !== window) { 24 | this[0] = elem.nodeName 25 | ? elem 26 | : elem[0] !== undefined && elem[0].nodeName 27 | ? elem[0] 28 | : document.querySelector(elem); 29 | if (this[0] !== undefined && this[0] !== null) { 30 | data(this[0], "events", data(this[0], "events") || {}); 31 | } 32 | } 33 | } 34 | 35 | DependencyLib.prototype = { 36 | on, 37 | off, 38 | trigger 39 | }; 40 | 41 | // static 42 | DependencyLib.extend = extend; 43 | DependencyLib.data = data; 44 | DependencyLib.Event = Event; 45 | 46 | export default DependencyLib; 47 | -------------------------------------------------------------------------------- /lib/environment.js: -------------------------------------------------------------------------------- 1 | import window from "./global/window"; 2 | 3 | const ua = (window.navigator && window.navigator.userAgent) || "", 4 | ie = ua.indexOf("MSIE ") > 0 || ua.indexOf("Trident/") > 0, 5 | mobile = 6 | (window.navigator && 7 | window.navigator.userAgentData && 8 | window.navigator.userAgentData.mobile) || 9 | (window.navigator && window.navigator.maxTouchPoints) || 10 | "ontouchstart" in window, // not entirely correct but will currently do 11 | iphone = /iphone/i.test(ua); 12 | 13 | export { ie, mobile, iphone }; 14 | -------------------------------------------------------------------------------- /lib/escapeRegex.js: -------------------------------------------------------------------------------- 1 | const escapeRegexRegex = new RegExp( 2 | "(\\" + 3 | [ 4 | "/", 5 | ".", 6 | "*", 7 | "+", 8 | "?", 9 | "|", 10 | "(", 11 | ")", 12 | "[", 13 | "]", 14 | "{", 15 | "}", 16 | "\\", 17 | "quot;, 18 | "^" 19 | ].join("|\\") + 20 | ")", 21 | "gim" 22 | ); 23 | export function escapeRegex(str) { 24 | return str.replace(escapeRegexRegex, "\\$1"); 25 | } -------------------------------------------------------------------------------- /lib/eventruler.js: -------------------------------------------------------------------------------- 1 | import { HandleNativePlaceholder } from "./inputHandling"; 2 | import Inputmask from "./inputmask"; 3 | import { keys } from "./keycode.js"; 4 | import { getBufferTemplate } from "./positioning"; 5 | 6 | export { EventRuler }; 7 | 8 | const EventRuler = { 9 | on: function (input, eventName, eventHandler) { 10 | const $ = input.inputmask.dependencyLib; 11 | 12 | let ev = function (e) { 13 | if (e.originalEvent) { 14 | e = e.originalEvent || e; // get original event from jquery event 15 | arguments[0] = e; 16 | } 17 | // console.log(e.type); 18 | const that = this, 19 | inputmask = that.inputmask, 20 | opts = inputmask ? inputmask.opts : undefined; 21 | let args; 22 | if (inputmask === undefined && this.nodeName !== "FORM") { 23 | // happens when cloning an object with jquery.clone 24 | const imOpts = $.data(that, "_inputmask_opts"); 25 | $(that).off(); // unbind all events 26 | if (imOpts) { 27 | new Inputmask(imOpts).mask(that); 28 | } 29 | } else if ( 30 | !["submit", "reset", "setvalue"].includes(e.type) && 31 | this.nodeName !== "FORM" && 32 | (that.disabled || 33 | (that.readOnly && 34 | !( 35 | (e.type === "keydown" && e.ctrlKey && e.key === keys.c) || 36 | (opts.tabThrough === false && e.key === keys.Tab) 37 | ))) 38 | ) { 39 | e.preventDefault(); 40 | } else { 41 | switch (e.type) { 42 | case "input": 43 | if (inputmask.skipInputEvent === true) { 44 | inputmask.skipInputEvent = false; 45 | return e.preventDefault(); 46 | } 47 | 48 | // if (mobile) { //this causes problem see #2220 49 | // args = arguments; 50 | // setTimeout(function () { //needed for caret selection when entering a char on Android 8 - #1818 51 | // eventHandler.apply(that, args); 52 | // caret(that, that.inputmask.caretPos, undefined, true); 53 | // }, 0); 54 | // return false; 55 | // } 56 | break; 57 | case "click": 58 | case "focus": 59 | if (inputmask.validationEvent) { 60 | // #841 61 | inputmask.validationEvent = false; 62 | input.blur(); 63 | HandleNativePlaceholder( 64 | input, 65 | (inputmask.isRTL 66 | ? getBufferTemplate.call(inputmask).slice().reverse() 67 | : getBufferTemplate.call(inputmask) 68 | ).join("") 69 | ); 70 | setTimeout(function () { 71 | input.focus(); 72 | }, opts.validationEventTimeOut); 73 | return false; 74 | } 75 | args = arguments; 76 | setTimeout(function () { 77 | // needed for Chrome ~ initial selection clears after the clickevent 78 | if (!input.inputmask) { 79 | // `inputmask.remove()` was called before this callback 80 | return; 81 | } 82 | eventHandler.apply(that, args); 83 | }, 0); 84 | return /* false */; // #2423 85 | } 86 | const returnVal = eventHandler.apply(that, arguments); 87 | if (returnVal === false) { 88 | e.preventDefault(); 89 | e.stopPropagation(); 90 | } 91 | return returnVal; 92 | } 93 | }; 94 | // add inputmask namespace to event 95 | eventName = `${eventName}.inputmask`; 96 | if (["submit.inputmask", "reset.inputmask"].includes(eventName)) { 97 | ev = ev.bind(input); // bind creates a new eventhandler (wrap) 98 | if (input.form !== null) $(input.form).on(eventName, ev); 99 | } else { 100 | $(input).on(eventName, ev); 101 | } 102 | }, 103 | off: function (input, event) { 104 | if (input.inputmask) { 105 | const $ = input.inputmask.dependencyLib; 106 | $(input).off(event || ".inputmask"); 107 | } 108 | } 109 | }; 110 | -------------------------------------------------------------------------------- /lib/extensions/colormask.css: -------------------------------------------------------------------------------- 1 | mark.im-caret { 2 | animation: 1s blink step-end infinite !important; 3 | } 4 | 5 | mark.im-caret-select { 6 | background-color: rgba(0, 0, 0, 0.25); 7 | } 8 | 9 | @keyframes blink { 10 | from, to { 11 | border-right-color: black; 12 | } 13 | 50% { 14 | /*border-right-color: transparent;*/ 15 | border-right-color: white; 16 | } 17 | } 18 | 19 | span.im-static { 20 | color: grey; 21 | } 22 | 23 | div.im-colormask { 24 | display: inline-block; 25 | border-style: groove; 26 | border-width: 1px; 27 | appearance: textfield; 28 | cursor: text; 29 | } 30 | 31 | div.im-colormask > input, div.im-colormask > input:-webkit-autofill { 32 | position: absolute !important; 33 | display: inline-block; 34 | background-color: transparent; 35 | color: transparent; 36 | -webkit-text-fill-color: transparent; 37 | transition: background-color 5000s ease-in-out 0s; 38 | caret-color: transparent; 39 | text-shadow: none; 40 | appearance: textfield; 41 | border-style: none; 42 | left: 0; /*calculated*/ 43 | } 44 | 45 | div.im-colormask > input:focus { 46 | outline: none; 47 | } 48 | 49 | div.im-colormask > input::selection { 50 | background: none; 51 | } 52 | 53 | div.im-colormask > input::-moz-selection { 54 | background: none; 55 | } 56 | 57 | div.im-colormask > input:-webkit-autofill ~ div { 58 | background-color: rgb(255, 255, 255); 59 | } 60 | 61 | div.im-colormask > div { 62 | color: black; 63 | display: inline-block; 64 | width: 100px; /*calculated*/ 65 | } -------------------------------------------------------------------------------- /lib/extensions/colormask.js: -------------------------------------------------------------------------------- 1 | /* 2 | Input Mask colormask extension 3 | http://github.com/RobinHerbots/inputmask 4 | Copyright (c) Robin Herbots 5 | Licensed under the MIT license 6 | */ 7 | import { EventHandlers } from "../eventhandlers"; 8 | import Inputmask from "../inputmask"; 9 | import { keys } from "../keycode.js"; 10 | import { 11 | caret, 12 | getBuffer, 13 | getLastValidPosition, 14 | translatePosition 15 | } from "../positioning"; 16 | import { getPlaceholder, getTestTemplate } from "../validation-tests"; 17 | 18 | const $ = Inputmask.dependencyLib; 19 | 20 | function Colormask(alias, options, internal) { 21 | // allow instanciating without new 22 | if (!(this instanceof Inputmask)) { 23 | return new Inputmask(alias, options, internal); 24 | } 25 | this.colorMask = undefined; 26 | Object.getOwnPropertyNames(Inputmask).forEach(function (key) { 27 | if (!Object.prototype.hasOwnProperty.call(this, key)) { 28 | this[key] = Inputmask[key]; 29 | } 30 | }, this); 31 | } 32 | 33 | Colormask.prototype = Inputmask.prototype; 34 | Colormask.prototype.writeBufferHook = function (caretPos) { 35 | renderColorMask.call(this, this.el, caretPos, false); 36 | }; 37 | Colormask.prototype.caretHook = function (caretPos) { 38 | renderColorMask.call(this, this.el, caretPos, false); 39 | }; 40 | Colormask.prototype.applyMaskHook = function () { 41 | initializeColorMask.call(this, this.el); 42 | }; 43 | Colormask.prototype.keyEventHook = function (e) { 44 | if (e.key === keys.ArrowRight || e.key === keys.ArrowLeft) { 45 | const inputmask = this; 46 | setTimeout(function () { 47 | const caretPos = caret.call( 48 | inputmask, 49 | inputmask.el, 50 | undefined, 51 | undefined, 52 | true 53 | ); 54 | renderColorMask.call(inputmask, inputmask.el, caretPos); 55 | }, 0); 56 | } 57 | }; 58 | 59 | function initializeColorMask(input) { 60 | const computedStyle = ( 61 | input.ownerDocument.defaultView || window 62 | ).getComputedStyle(input, null); 63 | 64 | function findCaretPos(clientx) { 65 | // calculate text width 66 | let e = document.createElement("span"), 67 | caretPos = 0; 68 | for (const style in computedStyle) { 69 | // clone styles 70 | if (isNaN(style) && style.indexOf("font") !== -1) { 71 | e.style[style] = computedStyle[style]; 72 | } 73 | } 74 | e.style.textTransform = computedStyle.textTransform; 75 | e.style.letterSpacing = computedStyle.letterSpacing; 76 | e.style.position = "absolute"; 77 | e.style.height = "auto"; 78 | e.style.width = "auto"; 79 | e.style.visibility = "hidden"; 80 | e.style.whiteSpace = "nowrap"; 81 | 82 | document.body.appendChild(e); 83 | let inputText = input.inputmask.__valueGet.call(input), 84 | previousWidth = 0; 85 | 86 | while (e.offsetWidth < clientx) { 87 | const ichar = inputText.charAt(caretPos); 88 | e.innerHTML += ichar === " " || ichar === "" ? "_" : ichar; 89 | if (e.offsetWidth >= clientx) { 90 | let offset1 = clientx - previousWidth, 91 | offset2 = e.offsetWidth - clientx; 92 | e.innerHTML = inputText.charAt(caretPos); 93 | offset1 += Math.round(e.offsetWidth / 2); 94 | caretPos = (offset1 < offset2 ? caretPos - 1 : caretPos) - 1; 95 | break; 96 | } 97 | previousWidth = e.offsetWidth; 98 | caretPos++; 99 | } 100 | 101 | if (input.style.textAlign === "right") { 102 | e.innerHTML = "_"; 103 | const maxChars = Math.ceil(input.offsetWidth / e.offsetWidth) - 1; 104 | caretPos = inputText.length - (maxChars - caretPos) + 1; 105 | } 106 | 107 | document.body.removeChild(e); 108 | return caretPos; 109 | } 110 | 111 | const template = document.createElement("div"); 112 | template.style.width = computedStyle.width; 113 | template.style.textAlign = computedStyle.textAlign; 114 | const colorMask = document.createElement("div"); 115 | input.inputmask.colorMask = colorMask; 116 | colorMask.className = "im-colormask"; 117 | input.parentNode.insertBefore(colorMask, input); 118 | input.parentNode.removeChild(input); 119 | colorMask.appendChild(input); 120 | colorMask.appendChild(template); 121 | input.style.left = template.offsetLeft + "px"; 122 | 123 | $(colorMask).on("mouseleave", function (e) { 124 | return EventHandlers.mouseleaveEvent.call(input, [e]); 125 | }); 126 | $(colorMask).on("mouseenter", function (e) { 127 | return EventHandlers.mouseenterEvent.call(input, [e]); 128 | }); 129 | $(colorMask).on("click", function (e) { 130 | caret.call( 131 | input.inputmask, 132 | input, 133 | findCaretPos(e.clientX), 134 | undefined, 135 | true 136 | ); 137 | return EventHandlers.clickEvent.call(input, [e]); 138 | }); 139 | } 140 | 141 | function positionColorMask(input, template) { 142 | input.style.left = template.offsetLeft + "px"; 143 | } 144 | 145 | export function renderColorMask(input, caretPos, clear) { 146 | let inputmask = this, 147 | { isRTL, maskset, opts, maxLength } = inputmask, 148 | maskTemplate = [], 149 | isStatic = false, 150 | test, 151 | testPos, 152 | ndxIntlzr, 153 | pos = 0, 154 | templates = { 155 | static: { 156 | start: isRTL ? "</span>" : "<span class='im-static'>", 157 | end: isRTL ? "<span class='im-static'>" : "</span>" 158 | }, 159 | caret: { 160 | start: 161 | '<mark class="im-caret" style="border-right-width: 1px;border-right-style: solid;">', 162 | start_select: '<mark class="im-caret-select">', 163 | end: "</mark>" 164 | } 165 | }; 166 | 167 | function setEntry(entry) { 168 | if (entry === undefined) entry = ""; 169 | if (!isStatic && (test.static === true || testPos.input === undefined)) { 170 | isStatic = true; 171 | maskTemplate.push(templates.static.start + entry); 172 | } else if ( 173 | isStatic && 174 | ((test.static !== true && testPos.input !== undefined) || test.def === "") 175 | ) { 176 | isStatic = false; 177 | maskTemplate.push(templates.static.end + entry); 178 | } else { 179 | maskTemplate.push(entry); 180 | } 181 | } 182 | 183 | function setCaret(begin, end, length) { 184 | if (document.activeElement === input) { 185 | maskTemplate.splice( 186 | begin, 187 | 0, 188 | begin === end || length > maskset.maskLength 189 | ? templates.caret.start 190 | : templates.caret.start_select 191 | ); 192 | maskTemplate.splice(end + (isRTL ? 0 : 1), 0, templates.caret.end); 193 | } 194 | } 195 | 196 | if (input.inputmask.colorMask !== undefined) { 197 | const buffer = getBuffer.call(inputmask); 198 | if (caretPos === undefined) { 199 | caretPos = caret.call(inputmask, input); 200 | } else if (caretPos.begin === undefined) { 201 | caretPos = { 202 | begin: caretPos, 203 | end: caretPos 204 | }; 205 | } 206 | 207 | if (isRTL) { 208 | // translate caretPos 209 | caretPos.begin = translatePosition.call(inputmask, caretPos.begin); 210 | caretPos.end = translatePosition.call(inputmask, caretPos.end); 211 | } 212 | 213 | if (clear !== true) { 214 | const lvp = getLastValidPosition.call(inputmask); 215 | do { 216 | if (maskset.validPositions[pos]) { 217 | testPos = maskset.validPositions[pos]; 218 | test = testPos.match; 219 | ndxIntlzr = testPos.locator.slice(); 220 | setEntry(buffer[pos]); 221 | } else { 222 | testPos = getTestTemplate.call(inputmask, pos, ndxIntlzr, pos - 1); 223 | test = testPos.match; 224 | ndxIntlzr = testPos.locator.slice(); 225 | 226 | const jitMasking = 227 | opts.jitMasking !== false ? opts.jitMasking : test.jit; 228 | if ( 229 | jitMasking === false || 230 | jitMasking === undefined /* || pos < lvp */ || 231 | (typeof jitMasking === "number" && 232 | isFinite(jitMasking) && 233 | jitMasking > pos) 234 | ) { 235 | setEntry(getPlaceholder.call(inputmask, pos, test)); 236 | // } else { 237 | // isStatic = false; 238 | } // break infinite loop 239 | } 240 | pos++; 241 | } while ( 242 | ((maxLength === undefined || pos < maxLength) && 243 | (test.static !== true || test.def !== "")) || 244 | lvp > pos || 245 | isStatic 246 | ); 247 | if (isStatic) setEntry(); 248 | setCaret( 249 | isRTL ? caretPos.end : caretPos.begin, 250 | isRTL ? caretPos.begin : caretPos.end, 251 | caretPos.end 252 | ); 253 | } 254 | 255 | const template = input.inputmask.colorMask.getElementsByTagName("div")[0]; 256 | template.innerHTML = (isRTL ? maskTemplate.reverse() : maskTemplate).join( 257 | "" 258 | ); 259 | positionColorMask(input, template); 260 | // console.log(template.innerHTML) 261 | // console.log(JSON.stringify(caretPos)); 262 | } 263 | } 264 | 265 | // make inputmask available 266 | window.Colormask = Colormask; 267 | export default Colormask; 268 | -------------------------------------------------------------------------------- /lib/extensions/inputmask.date.i18n.js: -------------------------------------------------------------------------------- 1 | /* 2 | Input Mask plugin extensions 3 | http://github.com/RobinHerbots/inputmask 4 | Copyright (c) Robin Herbots 5 | Licensed under the MIT license 6 | */ 7 | import Inputmask from "../inputmask"; 8 | 9 | const $ = Inputmask.dependencyLib; 10 | 11 | $.extend(true, Inputmask.prototype.i18n, { 12 | dayNames: [ 13 | "Mon", 14 | "Tue", 15 | "Wed", 16 | "Thu", 17 | "Fri", 18 | "Sat", 19 | "Sun", 20 | "Monday", 21 | "Tuesday", 22 | "Wednesday", 23 | "Thursday", 24 | "Friday", 25 | "Saturday", 26 | "Sunday" 27 | ], 28 | monthNames: [ 29 | "Jan", 30 | "Feb", 31 | "Mar", 32 | "Apr", 33 | "May", 34 | "Jun", 35 | "Jul", 36 | "Aug", 37 | "Sep", 38 | "Oct", 39 | "Nov", 40 | "Dec", 41 | "January", 42 | "February", 43 | "March", 44 | "April", 45 | "May", 46 | "June", 47 | "July", 48 | "August", 49 | "September", 50 | "October", 51 | "November", 52 | "December" 53 | ], 54 | ordinalSuffix: ["st", "nd", "rd", "th"] 55 | }); 56 | -------------------------------------------------------------------------------- /lib/extensions/inputmask.extensions.js: -------------------------------------------------------------------------------- 1 | /* 2 | Input Mask plugin extensions 3 | http://github.com/RobinHerbots/inputmask 4 | Copyright (c) Robin Herbots 5 | Licensed under the MIT license 6 | */ 7 | import Inputmask from "../inputmask"; 8 | import { getLastValidPosition } from "../positioning"; 9 | import { getMaskTemplate } from "../validation-tests"; 10 | // extra definitions 11 | Inputmask.extendDefinitions({ 12 | A: { 13 | validator: "[A-Za-z\u0410-\u044F\u0401\u0451\u00C0-\u00FF\u00B5]", 14 | casing: "upper" // auto uppercasing 15 | }, 16 | "&": { 17 | // alfanumeric uppercasing 18 | validator: "[0-9A-Za-z\u0410-\u044F\u0401\u0451\u00C0-\u00FF\u00B5]", 19 | casing: "upper" 20 | }, 21 | "#": { 22 | // hexadecimal 23 | validator: "[0-9A-Fa-f]", 24 | casing: "upper" 25 | } 26 | }); 27 | 28 | const ipValidatorRegex = /25[0-5]|2[0-4][0-9]|[01][0-9][0-9]/; 29 | 30 | function ipValidator(chrs, maskset, pos, strict, opts) { 31 | if (pos - 1 > -1 && maskset.buffer[pos - 1] !== ".") { 32 | chrs = maskset.buffer[pos - 1] + chrs; 33 | if (pos - 2 > -1 && maskset.buffer[pos - 2] !== ".") { 34 | chrs = maskset.buffer[pos - 2] + chrs; 35 | } else chrs = "0" + chrs; 36 | } else chrs = "00" + chrs; 37 | if ( 38 | opts.greedy && 39 | parseInt(chrs) > 255 && 40 | ipValidatorRegex.test("00" + chrs.charAt(2)) 41 | ) { 42 | const buffer = [...maskset.buffer.slice(0, pos), ".", chrs.charAt(2)]; 43 | if (buffer.join("").match(/\./g).length < 4) { 44 | return { 45 | refreshFromBuffer: true, 46 | buffer, 47 | caret: pos + 2 48 | }; 49 | } 50 | } 51 | return ipValidatorRegex.test(chrs); 52 | } 53 | 54 | Inputmask.extendAliases({ 55 | cssunit: { 56 | regex: "[+-]?[0-9]+\\.?([0-9]+)?(px|em|rem|ex|%|in|cm|mm|pt|pc)" 57 | }, 58 | url: { 59 | // needs update => https://en.wikipedia.org/wiki/URL 60 | regex: "(https?|ftp)://.*", 61 | autoUnmask: false, 62 | keepStatic: false, 63 | tabThrough: true 64 | }, 65 | ip: { 66 | // ip-address mask 67 | mask: "i{1,3}.j{1,3}.k{1,3}.l{1,3}", 68 | definitions: { 69 | i: { 70 | validator: ipValidator 71 | }, 72 | j: { 73 | validator: ipValidator 74 | }, 75 | k: { 76 | validator: ipValidator 77 | }, 78 | l: { 79 | validator: ipValidator 80 | } 81 | }, 82 | onUnMask: function (maskedValue, unmaskedValue, opts) { 83 | return maskedValue; 84 | }, 85 | inputmode: "decimal", 86 | substitutes: { ",": "." } 87 | }, 88 | email: { 89 | // https://en.wikipedia.org/wiki/Domain_name#Domain_name_space 90 | // https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names 91 | // should be extended with the toplevel domains at the end 92 | mask: function ({ separator, quantifier }) { 93 | let emailMask = 94 | "*{1,64}[.*{1,64}][.*{1,64}][.*{1,63}]@-{1,63}.-{1,63}[.-{1,63}][.-{1,63}]", 95 | mask = emailMask; 96 | if (separator) { 97 | for (let i = 0; i < quantifier; i++) { 98 | mask += `[${separator}${emailMask}]`; 99 | } 100 | } 101 | return mask; 102 | }, 103 | greedy: false, 104 | casing: "lower", 105 | separator: null, 106 | quantifier: 5, 107 | skipOptionalPartCharacter: "", 108 | onBeforePaste: function (pastedValue, opts) { 109 | pastedValue = pastedValue.toLowerCase(); 110 | return pastedValue.replace("mailto:", ""); 111 | }, 112 | definitions: { 113 | "*": { 114 | validator: 115 | "[0-9\uFF11-\uFF19A-Za-z\u0410-\u044F\u0401\u0451\u00C0-\u00FF\u00B5!#$%&'*+/=?^_`{|}~-]" 116 | }, 117 | "-": { 118 | validator: "[0-9A-Za-z-]" 119 | } 120 | }, 121 | onUnMask: function (maskedValue, unmaskedValue, opts) { 122 | return maskedValue; 123 | }, 124 | inputmode: "email" 125 | }, 126 | mac: { 127 | mask: "##:##:##:##:##:##" 128 | }, // https://en.wikipedia.org/wiki/Vehicle_identification_number 129 | // see issue #1199 130 | vin: { 131 | mask: "V{13}9{4}", 132 | definitions: { 133 | V: { 134 | validator: "[A-HJ-NPR-Za-hj-npr-z\\d]", 135 | casing: "upper" 136 | } 137 | }, 138 | clearIncomplete: true, 139 | autoUnmask: true 140 | }, // http://rion.io/2013/09/10/validating-social-security-numbers-through-regular-expressions-2/ 141 | // https://en.wikipedia.org/wiki/Social_Security_number 142 | ssn: { 143 | mask: "999-99-9999", 144 | postValidation: function ( 145 | buffer, 146 | pos, 147 | c, 148 | currentResult, 149 | opts, 150 | maskset, 151 | strict 152 | ) { 153 | const bffr = getMaskTemplate.call( 154 | this, 155 | true, 156 | getLastValidPosition.call(this), 157 | true, 158 | true 159 | ); 160 | return /^(?!219-09-9999|078-05-1120)(?!666|000|9.{2}).{3}-(?!00).{2}-(?!0{4}).{4}$/.test( 161 | bffr.join("") 162 | ); 163 | } 164 | } 165 | }); 166 | -------------------------------------------------------------------------------- /lib/global/FormData.js: -------------------------------------------------------------------------------- 1 | if (FormData.Inputmask === undefined) { 2 | class FormDataPatch extends FormData { 3 | constructor(form, submitter) { 4 | super(form, submitter); 5 | 6 | const entries = this.entries(); 7 | let entry; 8 | while ((entry = entries.next()).done === false) { 9 | const fieldName = entry.value[0], 10 | originalValue = entry.value[1], // Get the original value from FormData 11 | element = document.getElementById(fieldName); 12 | 13 | if ( 14 | element && 15 | element.inputmask !== undefined && 16 | !(originalValue instanceof File) 17 | ) { 18 | // Apply masking only if it's not a File and the element has inputmask 19 | this.set(fieldName, element.value); 20 | } 21 | } 22 | 23 | return this; 24 | } 25 | } 26 | FormDataPatch.Inputmask = true; 27 | // eslint-disable-next-line no-global-assign 28 | FormData = FormDataPatch; 29 | } 30 | -------------------------------------------------------------------------------- /lib/global/window.js: -------------------------------------------------------------------------------- 1 | const canUseDOM = !!( 2 | typeof window !== "undefined" && 3 | window.document && 4 | window.document.createElement 5 | ); 6 | 7 | export default canUseDOM ? window : {}; 8 | -------------------------------------------------------------------------------- /lib/inputmaskElement.js: -------------------------------------------------------------------------------- 1 | import window from "./global/window"; 2 | import Inputmask from "./inputmask"; 3 | 4 | const document = window.document; 5 | 6 | // add check if it is supported by the browser 7 | // integrate shadowroot into maskcope 8 | if ( 9 | document && 10 | document.head && 11 | document.head.attachShadow && 12 | window.customElements && 13 | window.customElements.get("input-mask") === undefined 14 | ) { 15 | class InputmaskElement extends HTMLElement { 16 | constructor() { 17 | super(); 18 | const attributeNames = this.getAttributeNames(), 19 | shadow = this.attachShadow({ mode: "closed" }); 20 | this.input = document.createElement("input"); 21 | this.input.type = "text"; 22 | shadow.appendChild(this.input); 23 | 24 | for (const attr in attributeNames) { 25 | if (Object.prototype.hasOwnProperty.call(attributeNames, attr)) { 26 | this.input.setAttribute( 27 | attributeNames[attr], 28 | this.getAttribute(attributeNames[attr]) 29 | ); 30 | } 31 | } 32 | 33 | const im = new Inputmask(); 34 | im.dataAttribute = ""; 35 | im.mask(this.input); 36 | } 37 | 38 | attributeChangedCallback(attrName, oldVal, newVal) { 39 | this.input.setAttribute(attrName, newVal); 40 | } 41 | 42 | // bind value 43 | get value() { 44 | return this.input.value; 45 | } 46 | 47 | set value(value) { 48 | this.input.value = value; 49 | } 50 | } 51 | 52 | window.customElements.define("input-mask", InputmaskElement); 53 | } 54 | -------------------------------------------------------------------------------- /lib/jquery.inputmask.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Input Mask plugin for jquery 3 | * http://github.com/RobinHerbots/jquery.inputmask 4 | * Copyright (c) Robin Herbots 5 | * Licensed under the MIT license 6 | */ 7 | import $ from "jquery"; 8 | 9 | import Inputmask from "./inputmask"; 10 | 11 | if ($.fn.inputmask === undefined) { 12 | // jquery plugin 13 | $.fn.inputmask = function (fn, options) { 14 | let nptmask, 15 | input = this[0]; 16 | if (options === undefined) options = {}; 17 | if (typeof fn === "string") { 18 | switch (fn) { 19 | case "unmaskedvalue": 20 | return input && input.inputmask 21 | ? input.inputmask.unmaskedvalue() 22 | : $(input).val(); 23 | case "remove": 24 | return this.each(function () { 25 | if (this.inputmask) this.inputmask.remove(); 26 | }); 27 | case "getemptymask": 28 | return input && input.inputmask ? input.inputmask.getemptymask() : ""; 29 | case "hasMaskedValue": // check whether the returned value is masked or not; currently only works reliable when using jquery.val fn to retrieve the value 30 | return input && input.inputmask 31 | ? input.inputmask.hasMaskedValue() 32 | : false; 33 | case "isComplete": 34 | return input && input.inputmask ? input.inputmask.isComplete() : true; 35 | case "getmetadata": // return mask metadata if exists 36 | return input && input.inputmask 37 | ? input.inputmask.getmetadata() 38 | : undefined; 39 | case "setvalue": 40 | Inputmask.setValue(input, options); 41 | break; 42 | case "option": 43 | if (typeof options === "string") { 44 | if (input && input.inputmask !== undefined) { 45 | return input.inputmask.option(options); 46 | } 47 | } else { 48 | return this.each(function () { 49 | if (this.inputmask !== undefined) { 50 | return this.inputmask.option(options); 51 | } 52 | }); 53 | } 54 | break; 55 | default: 56 | options.alias = fn; 57 | nptmask = new Inputmask(options); 58 | return this.each(function () { 59 | nptmask.mask(this); 60 | }); 61 | } 62 | } else if (Array.isArray(fn)) { 63 | options.alias = fn; 64 | nptmask = new Inputmask(options); 65 | return this.each(function () { 66 | nptmask.mask(this); 67 | }); 68 | } else if (typeof fn === "object") { 69 | nptmask = new Inputmask(fn); 70 | if (fn.mask === undefined && fn.alias === undefined) { 71 | return this.each(function () { 72 | if (this.inputmask !== undefined) { 73 | return this.inputmask.option(fn); 74 | } else nptmask.mask(this); 75 | }); 76 | } else { 77 | return this.each(function () { 78 | nptmask.mask(this); 79 | }); 80 | } 81 | } else if (fn === undefined) { 82 | // look for data-inputmask atributes 83 | return this.each(function () { 84 | nptmask = new Inputmask(options); 85 | nptmask.mask(this); 86 | }); 87 | } 88 | }; 89 | } 90 | -------------------------------------------------------------------------------- /lib/keycode.js: -------------------------------------------------------------------------------- 1 | export { keyCode, toKey, toKeyCode, keys }; 2 | 3 | const ignorables = { 4 | Alt: 18, 5 | AltGraph: 18, 6 | ArrowDown: 40, 7 | ArrowLeft: 37, 8 | ArrowRight: 39, 9 | ArrowUp: 38, 10 | Backspace: 8, 11 | CapsLock: 20, 12 | Control: 17, 13 | ContextMenu: 93, 14 | Dead: 221, 15 | Delete: 46, 16 | End: 35, 17 | Escape: 27, 18 | F1: 112, 19 | F2: 113, 20 | F3: 114, 21 | F4: 115, 22 | F5: 116, 23 | F6: 117, 24 | F7: 118, 25 | F8: 119, 26 | F9: 120, 27 | F10: 121, 28 | F11: 122, 29 | F12: 123, 30 | Home: 36, 31 | Insert: 45, 32 | NumLock: 144, 33 | PageDown: 34, 34 | PageUp: 33, 35 | Pause: 19, 36 | PrintScreen: 44, 37 | Process: 229, 38 | Shift: 16, 39 | ScrollLock: 145, 40 | Tab: 9, 41 | Unidentified: 229 42 | }, 43 | keyCode = { 44 | c: 67, 45 | x: 88, 46 | z: 90, 47 | BACKSPACE_SAFARI: 127, 48 | Enter: 13, 49 | Meta_LEFT: 91, 50 | Meta_RIGHT: 92, 51 | Space: 32, 52 | ...ignorables 53 | }, 54 | keyCodeRev = Object.entries(keyCode).reduce( 55 | (acc, [key, value]) => 56 | ( 57 | // eslint-disable-next-line no-sequences 58 | (acc[value] = acc[value] === undefined ? key : acc[value]), acc 59 | ), 60 | {} 61 | ), 62 | keys = Object.entries(keyCode).reduce( 63 | // eslint-disable-next-line no-sequences 64 | (acc, [key, value]) => ((acc[key] = key === "Space" ? " " : key), acc), 65 | {} 66 | ); 67 | 68 | function toKey(keyCode, shiftKey) { 69 | return ( 70 | keyCodeRev[keyCode] || 71 | (shiftKey 72 | ? String.fromCharCode(keyCode) 73 | : String.fromCharCode(keyCode).toLowerCase()) 74 | ); 75 | } 76 | 77 | function toKeyCode(key) { 78 | return keyCode[key]; 79 | } 80 | -------------------------------------------------------------------------------- /lib/masktoken.js: -------------------------------------------------------------------------------- 1 | export default function (isGroup, isOptional, isQuantifier, isAlternator) { 2 | this.matches = []; 3 | this.openGroup = isGroup || false; 4 | this.alternatorGroup = false; 5 | this.isGroup = isGroup || false; 6 | this.isOptional = isOptional || false; 7 | this.isQuantifier = isQuantifier || false; 8 | this.isAlternator = isAlternator || false; 9 | this.quantifier = { 10 | min: 1, 11 | max: 1 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /lib/polyfills/Array.includes.js: -------------------------------------------------------------------------------- 1 | // https://tc39.github.io/ecma262/#sec-array.prototype.includes 2 | if (!Array.prototype.includes) { 3 | // eslint-disable-next-line no-extend-native 4 | Object.defineProperty(Array.prototype, "includes", { 5 | value: function (searchElement, fromIndex) { 6 | // 1. Let O be ? ToObject(this value). 7 | if (this == null) { 8 | throw new TypeError('"this" is null or not defined'); 9 | } 10 | 11 | const o = Object(this), 12 | // 2. Let len be ? ToLength(? Get(O, "length")). 13 | len = o.length >>> 0; 14 | 15 | // 3. If len is 0, return false. 16 | if (len === 0) { 17 | return false; 18 | } 19 | 20 | // 4. Let n be ? ToInteger(fromIndex). 21 | // (If fromIndex is undefined, this step produces the value 0.) 22 | let n = fromIndex | 0, 23 | // 5. If n ≥ 0, then 24 | // a. Let k be n. 25 | // 6. Else n < 0, 26 | // a. Let k be len + n. 27 | // b. If k < 0, let k be 0. 28 | k = Math.max(n >= 0 ? n : len - Math.abs(n), 0); 29 | 30 | // 7. Repeat, while k < len 31 | while (k < len) { 32 | // a. Let elementK be the result of ? Get(O, ! ToString(k)). 33 | // b. If SameValueZero(searchElement, elementK) is true, return true. 34 | // c. Increase k by 1. 35 | // NOTE: === provides the correct "SameValueZero" comparison needed here. 36 | if (o[k] === searchElement) { 37 | return true; 38 | } 39 | k++; 40 | } 41 | 42 | // 8. Return false 43 | return false; 44 | } 45 | }); 46 | } 47 | -------------------------------------------------------------------------------- /lib/polyfills/Object.entries.js: -------------------------------------------------------------------------------- 1 | const reduce = Function.bind.call(Function.call, Array.prototype.reduce), 2 | isEnumerable = Function.bind.call( 3 | Function.call, 4 | Object.prototype.propertyIsEnumerable 5 | ), 6 | concat = Function.bind.call(Function.call, Array.prototype.concat), 7 | keys = Object.keys; 8 | 9 | if (!Object.entries) { 10 | Object.entries = function entries(O) { 11 | return reduce( 12 | keys(O), 13 | (e, k) => 14 | concat( 15 | e, 16 | typeof k === "string" && isEnumerable(O, k) ? [[k, O[k]]] : [] 17 | ), 18 | [] 19 | ); 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /lib/polyfills/Object.getPrototypeOf.js: -------------------------------------------------------------------------------- 1 | if (typeof Object.getPrototypeOf !== "function") { 2 | Object.getPrototypeOf = 3 | typeof "test".__proto__ === "object" 4 | ? function (object) { 5 | return object.__proto__; 6 | } 7 | : function (object) { 8 | return object.constructor.prototype; 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /lib/polyfills/String.includes.js: -------------------------------------------------------------------------------- 1 | if (!String.prototype.includes) { 2 | // eslint-disable-next-line no-extend-native 3 | String.prototype.includes = function (search, start) { 4 | if (typeof start !== "number") { 5 | start = 0; 6 | } 7 | 8 | if (start + search.length > this.length) { 9 | return false; 10 | } else { 11 | return this.indexOf(search, start) !== -1; 12 | } 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /micromasks/mm.js: -------------------------------------------------------------------------------- 1 | (() => { 2 | window.mm = (i, mask) => { 3 | const d = { 9: "[0-9]", a: "[a-z]" }, 4 | msk = mask.split(""); 5 | i.addEventListener("input", handler); 6 | i.addEventListener("focus", handler); 7 | 8 | function handler(e) { 9 | if (e.type == "focus" && i.value !== "") return; 10 | const mskd = []; 11 | let s = i.selectionStart - 1; 12 | msk.forEach((el, n) => { 13 | if (d[el]) { 14 | const t = new RegExp(d[el], "i").test(i.value.charAt(n)); 15 | mskd.push(t ? i.value.charAt(n) : "_"); 16 | if (t && s === n && i.value.charAt(n) !== "_") { 17 | s++; 18 | } 19 | } else { 20 | mskd.push(el); 21 | if (s === n) s++; 22 | } 23 | }); 24 | i.value = mskd.join(""); 25 | i.selectionStart = i.selectionEnd = s < 0 ? 0 : s; 26 | setTimeout(function () { 27 | i.selectionStart = i.selectionEnd = s < 0 ? 0 : s; 28 | }, 0); 29 | } 30 | }; 31 | })(); 32 | -------------------------------------------------------------------------------- /nodetest.js: -------------------------------------------------------------------------------- 1 | const Inputmask = require("./dist/inputmask").default, 2 | im = Inputmask.format("abcdef", { mask: "aa-aa-aa" }); 3 | console.log(im); 4 | -------------------------------------------------------------------------------- /nuspecs/Inputmask.nuspec: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="utf-8"?> 2 | <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> 3 | <metadata> 4 | <id>inputmask</id> 5 | <version>0.0.0</version> 6 | <title>Inputmask</title> 7 | <authors>Robin Herbots</authors> 8 | <owners>Robin Herbots</owners> 9 | <license type="expression">MIT</license> 10 | <projectUrl>https://github.com/RobinHerbots/Inputmask</projectUrl> 11 | <requireLicenseAcceptance>true</requireLicenseAcceptance> 12 | <description>Inputmask is a javascript library which creates an input mask. Inputmask can run against vanilla javascript, jQuery and jqlite.</description> 13 | <summary>Inputmask is a javascript library which creates an input mask. Inputmask can run against vanilla javascript, jQuery and jqlite.</summary> 14 | <tags>jQuery, plugins, input, form, inputmask, mask</tags> 15 | </metadata> 16 | <files> 17 | <file src="..\dist\**\*" target="content\Scripts\inputmask" /> 18 | <file src="Readme.txt" target="Readme.txt" /> 19 | </files> 20 | </package> -------------------------------------------------------------------------------- /nuspecs/Readme.txt: -------------------------------------------------------------------------------- 1 | ## .NET Nuget Package Install 2 | 3 | PM> Install-Package InputMask 4 | 5 | In App_Start, BundleConfig.cs 6 | 7 | bundles.Add(new ScriptBundle("~/bundles/inputmask").Include( 8 | "~/Scripts/inputmask/jquery.inputmask.js")); 9 | 10 | In Layout 11 | 12 | @Scripts.Render("~/bundles/inputmask") 13 | -------------------------------------------------------------------------------- /nuspecs/jquery.inputmask.nuspec: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="utf-8"?> 2 | <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> 3 | <metadata> 4 | <id>jQuery.InputMask</id> 5 | <version>0.0.0</version> 6 | <title>Inputmask</title> 7 | <authors>Robin Herbots</authors> 8 | <owners>Robin Herbots</owners> 9 | <license type="expression">MIT</license> 10 | <projectUrl>https://github.com/RobinHerbots/Inputmask</projectUrl> 11 | <requireLicenseAcceptance>true</requireLicenseAcceptance> 12 | <description>Inputmask is a javascript library which creates an input mask. Inputmask can run against vanilla javascript, jQuery and jqlite.</description> 13 | <summary>Inputmask is a javascript library which creates an input mask. Inputmask can run against vanilla javascript, jQuery and jqlite.</summary> 14 | <tags>jQuery, plugins, input, form, inputmask, mask</tags> 15 | </metadata> 16 | <files> 17 | <file src="..\dist\**\*" target="content\Scripts\inputmask" /> 18 | <file src="Readme.txt" target="Readme.txt" /> 19 | </files> 20 | </package> -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "inputmask", 3 | "version": "5.0.10-beta.48", 4 | "description": "Inputmask is a javascript library which creates an input mask. Inputmask can run against vanilla javascript, jQuery and jqlite.", 5 | "main": "dist/inputmask.js", 6 | "exports": { 7 | ".": "./dist/inputmask.js", 8 | "./dist/*": "./dist/*", 9 | "./lib/*": "./lib/*", 10 | "./micromasks/*": "./micromasks/*" 11 | }, 12 | "files": [ 13 | "bundle.js", 14 | "Changelog.md", 15 | "dist/", 16 | "lib/", 17 | "micromasks/" 18 | ], 19 | "publishConfig": { 20 | "registry": "https://registry.npmjs.org" 21 | }, 22 | "scripts": { 23 | "start": "webpack --progress --watch --config-name main --config webpack.config.js", 24 | "jquery": "webpack --progress --watch --config-name jquery --config webpack.config.js", 25 | "colormask": "webpack --progress --watch --config-name colormask --config webpack.config.js", 26 | "test": "grunt validate" 27 | }, 28 | "repository": { 29 | "type": "git", 30 | "url": "https://github.com/RobinHerbots/Inputmask.git" 31 | }, 32 | "keywords": [ 33 | "form", 34 | "input", 35 | "inputmask", 36 | "jquery", 37 | "jquery-plugin", 38 | "mask", 39 | "plugins" 40 | ], 41 | "author": { 42 | "name": "Robin Herbots", 43 | "url": "https://github.com/RobinHerbots" 44 | }, 45 | "license": "MIT", 46 | "bugs": { 47 | "url": "https://github.com/RobinHerbots/Inputmask/issues" 48 | }, 49 | "homepage": "https://github.com/RobinHerbots/Inputmask", 50 | "devDependencies": { 51 | "@babel/core": "^7.27.1", 52 | "@babel/eslint-parser": "^7.27.1", 53 | "@babel/preset-env": "^7.27.2", 54 | "@babel/preset-typescript": "^7.27.1", 55 | "@robinherbots/grunt-available-tasks": "^0.6.4", 56 | "@robinherbots/grunt-nuget": "^0.3.3", 57 | "babel-loader": "^10.0.0", 58 | "eslint": "^8.57.1", 59 | "eslint-config-prettier": "^10.1.5", 60 | "eslint-config-standard": "^17.1.0", 61 | "eslint-plugin-header": "^3.1.1", 62 | "eslint-plugin-import": "^2.31.0", 63 | "eslint-plugin-n": "^16.6.2", 64 | "eslint-plugin-prettier": "^5.4.0", 65 | "eslint-plugin-promise": "^6.6.0", 66 | "grunt": "^1.6.1", 67 | "grunt-bump": "^0.8.0", 68 | "grunt-contrib-clean": "^2.0.1", 69 | "grunt-contrib-copy": "^1.0.0", 70 | "grunt-eslint": "^25.0.0", 71 | "grunt-karma": "^4.0.2", 72 | "grunt-release": "^0.14.0", 73 | "grunt-webpack": "^7.0.0", 74 | "jquery": "^3.7.1", 75 | "karma": "^6.4.4", 76 | "karma-browserstack-launcher": "^1.6.0", 77 | "karma-chrome-launcher": "^3.2.0", 78 | "karma-qunit": "^4.2.1", 79 | "load-grunt-tasks": "^5.1.0", 80 | "lodash": "^4.17.21", 81 | "prettier": "3.5.3", 82 | "qunit": "^2.24.1", 83 | "webpack": "^5.99.8", 84 | "webpack-cli": "^6.0.1" 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /qunit/index.js: -------------------------------------------------------------------------------- 1 | import jQuery from "jquery"; 2 | import qunit from "qunit"; 3 | 4 | import Inputmask from "../bundle"; 5 | 6 | import "./prototypeExtensions.js"; 7 | import simulator from "./simulator.js"; // inject globally for the simulator to detect inputeventonly 8 | import testsAlternations from "./tests_alternations"; 9 | import testsAttributes from "./tests_attributes"; 10 | import testsBase from "./tests_base"; 11 | import testsDate from "./tests_date"; 12 | import testsDynamic from "./tests_dynamic"; 13 | import testsEscape from "./tests_escape"; 14 | import testsFormatvalidate from "./tests_formatvalidate"; 15 | import testsInitialvalue from "./tests_initialvalue"; 16 | import testsInputeventonly from "./tests_inputeventonly"; 17 | import testsIp from "./tests_ip"; 18 | import testsJitmasking from "./tests_jitmasking"; 19 | import testsJqueryInputmask from "./tests_jquery_inputmask"; 20 | import testsKeepStatic from "./tests_keepStatic"; 21 | import testsMulti from "./tests_multi"; 22 | import testsNumeric from "./tests_numeric"; 23 | import testsNumericinput from "./tests_numericinput"; 24 | import testsOption from "./tests_option"; 25 | import testsOptional from "./tests_optional"; 26 | import testsPaste from "./tests_paste"; 27 | import testsRegex from "./tests_regex"; 28 | import testsSetvalue from "./tests_setvalue"; 29 | 30 | if (Inputmask.dependencyLib === jQuery) window.jQuery = Inputmask.dependencyLib; 31 | 32 | // android testing 33 | Inputmask.extendDefaults({ 34 | inputEventOnly: false 35 | }); 36 | 37 | window.Inputmask = Inputmask; 38 | 39 | // inject simulater code in the dependencies 40 | simulator(Inputmask.dependencyLib, Inputmask); 41 | simulator(jQuery, Inputmask); 42 | 43 | // load tests 44 | if (qunit) { 45 | testsAlternations(qunit, Inputmask); 46 | testsAttributes(qunit, Inputmask); 47 | testsBase(qunit, Inputmask); 48 | testsDate(qunit, Inputmask); 49 | testsDynamic(qunit, Inputmask); 50 | testsEscape(qunit, Inputmask); 51 | testsFormatvalidate(qunit, Inputmask); 52 | testsInitialvalue(qunit, Inputmask); 53 | testsInputeventonly(qunit, Inputmask); 54 | testsIp(qunit, Inputmask); 55 | testsJitmasking(qunit, Inputmask); 56 | testsJqueryInputmask(qunit, jQuery, Inputmask); 57 | testsKeepStatic(qunit, Inputmask); 58 | testsMulti(qunit, Inputmask); 59 | testsNumeric(qunit, Inputmask); 60 | testsNumericinput(qunit, Inputmask); 61 | testsOption(qunit, Inputmask); 62 | testsOptional(qunit, Inputmask); 63 | testsPaste(qunit, Inputmask); 64 | testsRegex(qunit, Inputmask); 65 | testsSetvalue(qunit, Inputmask); 66 | 67 | qunit.load(); 68 | // qunit.start(); 69 | } 70 | -------------------------------------------------------------------------------- /qunit/prototypeExtensions.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-extend-native */ 2 | /* 3 | 4 | These are dummy prototype extensions to test that the inputmask code can deal with an extension 5 | 6 | */ 7 | 8 | Array.prototype.dummy = function () { 9 | return false; 10 | }; 11 | 12 | String.prototype.dummy = function () { 13 | return false; 14 | }; 15 | -------------------------------------------------------------------------------- /qunit/qunit.html: -------------------------------------------------------------------------------- 1 | <!DOCTYPE html> 2 | <html> 3 | 4 | <head> 5 | <meta charset="utf-8"> 6 | <title>Inputmask - QUnit</title> 7 | <link rel="stylesheet" href="../node_modules/qunit/qunit/qunit.css"> 8 | </head> 9 | 10 | <body> 11 | <div id="qunit"></div> 12 | <div id="qunit-fixture"></div> 13 | 14 | <script src="../node_modules/jquery/dist/jquery.js"></script> 15 | <script src="../node_modules/qunit/qunit/qunit.js"></script> 16 | <script src="../qunit/qunit.js" charset="utf-8"></script> 17 | </body> 18 | 19 | </html> -------------------------------------------------------------------------------- /qunit/simulator.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-fallthrough */ 2 | import { keys } from "../lib/keycode"; 3 | 4 | export default function ($, Inputmask) { 5 | $.caret = function (input, begin, end) { 6 | input = input.nodeName ? input : input[0]; 7 | input.focus(); 8 | let range; 9 | if (typeof begin === "number") { 10 | end = typeof end === "number" ? end : begin; 11 | // if (!$(input).is(":visible")) { 12 | // return; 13 | // } 14 | 15 | if (input.setSelectionRange) { 16 | input.setSelectionRange(begin, end); 17 | } else if (window.getSelection) { 18 | range = document.createRange(); 19 | if (input.firstChild === undefined) { 20 | const textNode = document.createTextNode(""); 21 | input.appendChild(textNode); 22 | } 23 | range.setStart( 24 | input.firstChild, 25 | begin < input.value.length ? begin : input.value.length 26 | ); 27 | range.setEnd( 28 | input.firstChild, 29 | end < input.value.length ? end : input.value.length 30 | ); 31 | range.collapse(true); 32 | const sel = window.getSelection(); 33 | sel.removeAllRanges(); 34 | sel.addRange(range); 35 | // input.focus(); 36 | } else if (input.createTextRange) { 37 | range = input.createTextRange(); 38 | range.collapse(true); 39 | range.moveEnd("character", end); 40 | range.moveStart("character", begin); 41 | range.select(); 42 | } 43 | } else { 44 | if ("selectionStart" in input && "selectionEnd" in input) { 45 | begin = input.selectionStart; 46 | end = input.selectionEnd; 47 | } else if (window.getSelection) { 48 | range = window.getSelection().getRangeAt(0); 49 | if ( 50 | range.commonAncestorContainer.parentNode === input || 51 | range.commonAncestorContainer === input 52 | ) { 53 | begin = range.startOffset; 54 | end = range.endOffset; 55 | } 56 | } else if (document.selection && document.selection.createRange) { 57 | range = document.selection.createRange(); 58 | begin = 0 - range.duplicate().moveStart("character", -100000); 59 | end = begin + range.text.length; 60 | } 61 | /* eslint-disable consistent-return */ 62 | return { 63 | begin, 64 | end 65 | }; 66 | /* eslint-enable consistent-return */ 67 | } 68 | }; 69 | $.fn = $.fn || $.prototype; 70 | $.fn.SendKey = function (key, modifier) { 71 | const elem = this.nodeName ? this : this[0], 72 | origCode = key; 73 | elem.type = "text"; // force textinput to support caret fn 74 | 75 | function trigger(elem, evnt) { 76 | elem.focus(); 77 | if ($ === window.jQuery) { 78 | $(elem).trigger(evnt); 79 | } else { 80 | if (document.createEvent) { 81 | elem.dispatchEvent(evnt); 82 | } else { 83 | elem.fireEvent("on" + evnt.eventType, evnt); 84 | } 85 | } 86 | } 87 | 88 | switch (key) { 89 | case keys.Home: 90 | if (modifier == undefined) { 91 | $.caret(this, 0); 92 | break; 93 | } 94 | case keys.End: 95 | if (modifier == undefined) { 96 | $.caret(this, elem.value.length); 97 | break; 98 | } 99 | case keys.ArrowLeft: 100 | if (modifier == undefined) { 101 | var pos = $.caret(this); 102 | $.caret(this, pos.begin - 1); 103 | break; 104 | } 105 | case keys.ArrowRight: 106 | if (modifier == undefined) { 107 | var pos2 = $.caret(this); 108 | $.caret(this, pos2.end + 1); 109 | break; 110 | } 111 | default: 112 | if ( 113 | (window.Inputmask && 114 | window.Inputmask.prototype.defaults.inputEventOnly === true) || 115 | (elem.inputmask && elem.inputmask.opts.inputEventOnly === true) 116 | ) { 117 | let input = new $.Event("input"), 118 | currentValue = 119 | elem.inputmask && elem.inputmask.__valueGet 120 | ? elem.inputmask.__valueGet.call(elem) 121 | : elem.value, 122 | caretPos = $.caret(elem), 123 | // caretOffset = 0, 124 | // console.log("initial " + currentValue); 125 | // console.log(caretPos); 126 | 127 | front = currentValue.substring(0, caretPos.begin), 128 | back = currentValue.substring(caretPos.end), 129 | newValue = currentValue; 130 | 131 | switch (key) { 132 | case keys.Backspace: 133 | if (caretPos.begin === caretPos.end) { 134 | front = front.substr(0, front.length - 1); 135 | } 136 | newValue = front + back; 137 | // console.log("backspace " + newValue); 138 | break; 139 | case keys.Delete: 140 | if (origCode !== ".") { 141 | if (caretPos.begin === caretPos.end) { 142 | back = back.slice(1); 143 | } 144 | newValue = front + back; 145 | break; 146 | } 147 | default: 148 | newValue = front + key[0] + back; 149 | // caretOffset = front.length > 0 ? 1 : 0; 150 | break; 151 | } 152 | 153 | if (elem.inputmask && elem.inputmask.__valueSet) { 154 | elem.inputmask.__valueSet.call(elem, newValue); 155 | } else { 156 | elem.value = newValue; 157 | } 158 | $.caret(elem, newValue.length - back.length); 159 | trigger(elem, input); 160 | } else { 161 | const keydown = new $.Event("keydown"), 162 | keypress = new $.Event("keypress"), 163 | keyup = new $.Event("keyup"); 164 | 165 | keydown.key = key; 166 | if (modifier == keys.Control) { 167 | keydown.ctrlKey = true; 168 | } 169 | trigger(elem, keydown); 170 | if (!keydown.defaultPrevented) { 171 | keypress.key = key; 172 | if (modifier == keys.Control) { 173 | keypress.ctrlKey = true; 174 | } 175 | trigger(elem, keypress); 176 | if (!keypress.defaultPrevented) { 177 | keyup.key = key; 178 | if (modifier == keys.Control) { 179 | keyup.ctrlKey = true; 180 | } 181 | trigger(elem, keyup); 182 | } 183 | } 184 | } 185 | } 186 | }; 187 | if (!("append" in $.fn)) { 188 | $.fn.append = function (child) { 189 | const input = this.nodeName ? this : this[0]; 190 | input.insertAdjacentHTML("beforeend", child); 191 | }; 192 | } 193 | if (!("remove" in $.fn)) { 194 | $.fn.remove = function () { 195 | let input = this.nodeName ? this : this[0]; 196 | if (input !== undefined && input !== null) { 197 | input.parentElement.removeChild(input); 198 | input = undefined; 199 | } 200 | }; 201 | } 202 | if (!("val" in $.fn)) { 203 | $.fn.val = function (value) { 204 | const input = this.nodeName ? this : this[0]; 205 | if (value !== undefined) { 206 | if (input.inputmask) { 207 | input.inputmask._valueSet(value, true); 208 | $(input).trigger("setvalue"); 209 | } else { 210 | input.value = value; 211 | } 212 | } 213 | 214 | return input.value; 215 | }; 216 | } 217 | 218 | $.fn.Type = function (inputStr) { 219 | const input = this.nodeName ? this : this[0], 220 | $input = $(input); 221 | inputStr.split("").forEach(function (lmnt, ndx) { 222 | $input.SendKey(lmnt); 223 | }); 224 | }; 225 | 226 | $.fn.paste = function (inputStr) { 227 | const input = this.nodeName ? this : this[0], 228 | $input = $(input); 229 | if (window.clipboardData) { 230 | window.clipboardData.setData("Text", inputStr); 231 | } else { 232 | $.data($input, "clipboard", inputStr); 233 | window.clipboardData = { 234 | getData: function () { 235 | window.clipboardData = undefined; 236 | return $.data($input, "clipboard"); 237 | } 238 | }; 239 | } 240 | 241 | $input.trigger("paste"); 242 | }; 243 | 244 | $.fn.input = function (inputStr, caretBegin, caretEnd) { 245 | const input = this.nodeName ? this : this[0]; 246 | input.inputmask.__valueSet.call(input, inputStr); 247 | if (caretBegin !== undefined) { 248 | $.caret(input, caretBegin, caretEnd); 249 | } 250 | $(input).trigger("input"); 251 | }; 252 | } 253 | -------------------------------------------------------------------------------- /qunit/tests_attributes.js: -------------------------------------------------------------------------------- 1 | export default function (qunit, Inputmask) { 2 | var $ = Inputmask.dependencyLib; 3 | qunit.module("Attribute options"); 4 | 5 | qunit.test( 6 | "data-inputmask=\"'alias':'integer', 'allowMinus': false, 'allowPlus': false\" - StennikovDmitriy", 7 | function (assert) { 8 | var $fixture = $("#qunit-fixture"); 9 | $fixture.append( 10 | "<input type=\"text\" id=\"testmask\" data-inputmask=\"'alias':'integer', 'allowMinus': false, 'allowPlus': false\" />" 11 | ); 12 | var testmask = document.getElementById("testmask"); 13 | Inputmask().mask(testmask); 14 | 15 | $("#testmask").Type("1234,56"); 16 | assert.equal(testmask.value, "123456", "Result " + testmask.value); 17 | } 18 | ); 19 | 20 | qunit.test( 21 | "data-inputmask=\"'mask':'[9-]AAA-999'\" - airomero", 22 | function (assert) { 23 | var $fixture = $("#qunit-fixture"); 24 | $fixture.append( 25 | '<input type="text" id="testmask" data-inputmask="\'mask\':\'[9-]AAA-999\'" />' 26 | ); 27 | var testmask = document.getElementById("testmask"); 28 | Inputmask().mask(testmask); 29 | 30 | $("#testmask").Type("abc123"); 31 | assert.equal(testmask.value, "ABC-123", "Result " + testmask.value); 32 | } 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /qunit/tests_escape.js: -------------------------------------------------------------------------------- 1 | export default function (qunit, Inputmask) { 2 | var $ = Inputmask.dependencyLib; 3 | qunit.module("Escape character"); 4 | 5 | qunit.test('inputmask("9\\|9")', function (assert) { 6 | var $fixture = $("#qunit-fixture"); 7 | $fixture.append('<input type="text" id="testmask" />'); 8 | var testmask = document.getElementById("testmask"); 9 | Inputmask("9\\|9").mask(testmask); 10 | 11 | testmask.focus(); 12 | 13 | $("#testmask").Type("23"); 14 | assert.equal(testmask.value, "2|3", "Result " + testmask.value); 15 | }); 16 | 17 | qunit.test('inputmask("9\\[9\\]")', function (assert) { 18 | var $fixture = $("#qunit-fixture"); 19 | $fixture.append('<input type="text" id="testmask" />'); 20 | var testmask = document.getElementById("testmask"); 21 | Inputmask("9\\[9\\]").mask(testmask); 22 | 23 | testmask.focus(); 24 | 25 | $("#testmask").Type("23"); 26 | assert.equal(testmask.value, "2[3]", "Result " + testmask.value); 27 | }); 28 | 29 | qunit.test('inputmask("9\\\\9")', function (assert) { 30 | var $fixture = $("#qunit-fixture"); 31 | $fixture.append('<input type="text" id="testmask" />'); 32 | var testmask = document.getElementById("testmask"); 33 | Inputmask("9\\\\9").mask(testmask); 34 | 35 | testmask.focus(); 36 | 37 | $("#testmask").Type("23"); 38 | assert.equal(testmask.value, "2\\3", "Result " + testmask.value); 39 | }); 40 | 41 | qunit.test('inputmask("9\\{9\\}")', function (assert) { 42 | var $fixture = $("#qunit-fixture"); 43 | $fixture.append('<input type="text" id="testmask" />'); 44 | var testmask = document.getElementById("testmask"); 45 | Inputmask("9\\{9\\}").mask(testmask); 46 | 47 | testmask.focus(); 48 | 49 | $("#testmask").Type("23"); 50 | assert.equal(testmask.value, "2{3}", "Result " + testmask.value); 51 | }); 52 | 53 | qunit.test('inputmask("9\\(9\\)")', function (assert) { 54 | var $fixture = $("#qunit-fixture"); 55 | $fixture.append('<input type="text" id="testmask" />'); 56 | var testmask = document.getElementById("testmask"); 57 | Inputmask("9\\(9\\)").mask(testmask); 58 | 59 | testmask.focus(); 60 | 61 | $("#testmask").Type("23"); 62 | assert.equal(testmask.value, "2(3)", "Result " + testmask.value); 63 | }); 64 | 65 | qunit.test('inputmask("9\\?9")', function (assert) { 66 | var $fixture = $("#qunit-fixture"); 67 | $fixture.append('<input type="text" id="testmask" />'); 68 | var testmask = document.getElementById("testmask"); 69 | Inputmask("9\\?9").mask(testmask); 70 | 71 | testmask.focus(); 72 | 73 | $("#testmask").Type("23"); 74 | assert.equal(testmask.value, "2?3", "Result " + testmask.value); 75 | }); 76 | 77 | qunit.test('inputmask("\\9999") value not mask', function (assert) { 78 | var $fixture = $("#qunit-fixture"); 79 | $fixture.append('<input type="text" value="999" id="testmask" />'); 80 | var testmask = document.getElementById("testmask"); 81 | Inputmask("\\9999", { 82 | autoUnmask: true 83 | }).mask(testmask); 84 | 85 | testmask.focus(); 86 | 87 | assert.equal( 88 | testmask.inputmask._valueGet(), 89 | "9999", 90 | "Result " + testmask.inputmask._valueGet() 91 | ); 92 | }); 93 | } 94 | -------------------------------------------------------------------------------- /qunit/tests_inputeventonly.js: -------------------------------------------------------------------------------- 1 | import { keys } from "../lib/keycode"; 2 | 3 | export default function (qunit, Inputmask) { 4 | const $ = Inputmask.dependencyLib; 5 | qunit.module("inputEventOnly: true"); 6 | 7 | qunit.test("XXX-9999-9999-XXX-XXX - gersteba", function (assert) { 8 | const $fixture = $("#qunit-fixture"); 9 | $fixture.append('<input type="text" id="testmask" />'); 10 | const testmask = document.getElementById("testmask"); 11 | Inputmask({ 12 | inputEventOnly: true, 13 | mask: "XXX-9999-9999-XXX-XXX", 14 | definitions: { 15 | X: { 16 | validator: "[A-Ha-hJ-Nj-nPpR-Zr-z2-9]", 17 | cardinality: 1, 18 | casing: "upper" 19 | } 20 | } 21 | }).mask(testmask); 22 | 23 | testmask.focus(); 24 | // simulate input 25 | $(testmask).input("abc12341234abcabc"); 26 | 27 | assert.equal( 28 | testmask.value, 29 | "ABC-1234-1234-ABC-ABC", 30 | "Result " + testmask.value 31 | ); 32 | }); 33 | 34 | qunit.test("(999) 999-9999", function (assert) { 35 | const $fixture = $("#qunit-fixture"); 36 | $fixture.append('<input type="text" id="testmask" />'); 37 | const testmask = document.getElementById("testmask"); 38 | Inputmask("(999) 999-9999", { inputEventOnly: true }).mask(testmask); 39 | 40 | testmask.focus(); 41 | // simulate input 42 | $(testmask).input("1231231234"); 43 | 44 | assert.equal(testmask.value, "(123) 123-1234", "Result " + testmask.value); 45 | }); 46 | 47 | qunit.test("(999) 999-9999 - type 123 + backspace", function (assert) { 48 | const $fixture = $("#qunit-fixture"); 49 | $fixture.append('<input type="text" id="testmask" />'); 50 | const testmask = document.getElementById("testmask"); 51 | Inputmask("(999) 999-9999", { inputEventOnly: true }).mask(testmask); 52 | 53 | testmask.focus(); 54 | // simulate input 55 | $(testmask).input("123"); 56 | // simulate backspace 57 | $(testmask).input("(12) ___-____", 3); 58 | assert.ok($.caret(testmask).begin == 3, "Caret " + $.caret(testmask).begin); 59 | }); 60 | 61 | qunit.test( 62 | "9999\\9\\9 - type 1234 + backspace - NightsDream", 63 | function (assert) { 64 | const $fixture = $("#qunit-fixture"); 65 | $fixture.append('<input type="text" id="testmask" />'); 66 | const testmask = document.getElementById("testmask"); 67 | Inputmask({ 68 | mask: "9999\\9\\9", 69 | clearMaskOnLostFocus: false, 70 | placeholder: "X", 71 | inputEventOnly: true 72 | }).mask(testmask); 73 | 74 | testmask.focus(); 75 | // simulate input 76 | $(testmask).input("123499"); 77 | // simulate backspace 78 | $(testmask).input("12399", 3); 79 | assert.ok( 80 | $.caret(testmask).begin == 3, 81 | "Caret " + $.caret(testmask).begin + " : " + testmask.value 82 | ); 83 | assert.ok(testmask.value == "123X99", testmask.value); 84 | } 85 | ); 86 | 87 | qunit.test("numeric placeholder 0 - alexey-m-ukolov", function (assert) { 88 | const done = assert.async(), 89 | $fixture = $("#qunit-fixture"); 90 | $fixture.append('<input type="text" id="testmask" />'); 91 | const testmask = document.getElementById("testmask"); 92 | Inputmask( 93 | { 94 | alias: "numeric", 95 | placeholder: "0", 96 | inputEventOnly: true 97 | }, 98 | { inputEventOnly: true } 99 | ).mask(testmask); 100 | 101 | testmask.focus(); 102 | setTimeout(function () { 103 | $(testmask).Type("10"); 104 | assert.equal(testmask.value, "10", "Result " + testmask.value); 105 | done(); 106 | }, 0); 107 | }); 108 | 109 | qunit.test("numeric 1 - #1617", function (assert) { 110 | const done = assert.async(), 111 | $fixture = $("#qunit-fixture"); 112 | $fixture.append('<input type="text" id="testmask" />'); 113 | const testmask = document.getElementById("testmask"); 114 | Inputmask("numeric", { 115 | groupSeparator: ".", 116 | radixPoint: ",", 117 | placeholder: "0", 118 | digits: 2, 119 | digitsOptional: false, 120 | clearMaskOnLostFocus: false, 121 | inputEventOnly: true 122 | }).mask(testmask); 123 | 124 | testmask.focus(); 125 | $("#testmask").trigger("click"); 126 | setTimeout(function () { 127 | $("#testmask").Type("56,03"); 128 | $("#testmask").SendKey(keys.Backspace); 129 | $("#testmask").SendKey(keys.Backspace); 130 | $("#testmask").SendKey(keys.Backspace); 131 | $("#testmask").SendKey(keys.Backspace); 132 | $("#testmask").Type("0,03"); 133 | assert.equal(testmask.value, "50,03", "Result " + testmask.value); 134 | done(); 135 | }, 0); 136 | }); 137 | 138 | qunit.test("integer autofill 50", function (assert) { 139 | const $fixture = $("#qunit-fixture"); 140 | $fixture.append('<input type="text" id="testmask"/>'); 141 | const testmask = document.getElementById("testmask"); 142 | Inputmask("integer", { 143 | inputEventOnly: true 144 | }).mask(testmask); 145 | $(testmask).input("50"); 146 | assert.equal(testmask.value, "50", "Result " + testmask.value); 147 | }); 148 | 149 | qunit.test("currency type 123", function (assert) { 150 | const done = assert.async(), 151 | $fixture = $("#qunit-fixture"); 152 | $fixture.append('<input type="text" id="testmask"/>'); 153 | const testmask = document.getElementById("testmask"); 154 | Inputmask("currency", { 155 | prefix: "$ ", 156 | inputEventOnly: true 157 | }).mask(testmask); 158 | testmask.focus(); 159 | $.caret(testmask, 3); 160 | setTimeout(function () { 161 | $(testmask).Type("123"); 162 | assert.equal(testmask.value, "$ 123.00", "Result " + testmask.value); 163 | done(); 164 | }, 0); 165 | }); 166 | 167 | qunit.test("currency type 1234.56 + backspace x4", function (assert) { 168 | const done = assert.async(), 169 | $fixture = $("#qunit-fixture"); 170 | $fixture.append('<input type="text" id="testmask"/>'); 171 | const testmask = document.getElementById("testmask"); 172 | Inputmask("currency", { 173 | prefix: "$ ", 174 | inputEventOnly: true 175 | }).mask(testmask); 176 | testmask.focus(); 177 | $.caret(testmask, 3); 178 | setTimeout(function () { 179 | $(testmask).Type("1234.56"); 180 | $("#testmask").SendKey(keys.Backspace); 181 | $("#testmask").SendKey(keys.Backspace); 182 | $("#testmask").SendKey(keys.Backspace); 183 | $("#testmask").SendKey(keys.Backspace); 184 | assert.equal(testmask.value, "$ 123.00", "Result " + testmask.value); 185 | done(); 186 | }, 0); 187 | }); 188 | 189 | qunit.test("datetime", function (assert) { 190 | const done = assert.async(), 191 | $fixture = $("#qunit-fixture"); 192 | $fixture.append('<input type="text" id="testmask" />'); 193 | const testmask = document.getElementById("testmask"); 194 | Inputmask({ 195 | alias: "datetime", 196 | inputFormat: "dd/mm/yyyy", 197 | inputEventOnly: true 198 | }).mask(testmask); 199 | 200 | testmask.focus(); 201 | setTimeout(function () { 202 | $(testmask).Type("1"); 203 | assert.equal(testmask.value, "1d/mm/yyyy", "Result " + testmask.value); 204 | done(); 205 | }, 0); 206 | }); 207 | } 208 | -------------------------------------------------------------------------------- /qunit/tests_ip.js: -------------------------------------------------------------------------------- 1 | import { keys } from "../lib/keycode"; 2 | 3 | export default function (qunit, Inputmask) { 4 | var $ = Inputmask.dependencyLib; 5 | 6 | qunit.module("IP - masks"); 7 | qunit.test('inputmask("ip" - 10.10.10.10', function (assert) { 8 | var done = assert.async(), 9 | $fixture = $("#qunit-fixture"); 10 | $fixture.append('<input type="text" id="testmask" />'); 11 | var testmask = document.getElementById("testmask"); 12 | $fixture.append('<input type="text" id="testmask2" />'); 13 | var testmask2 = document.getElementById("testmask2"); 14 | Inputmask("ip").mask(testmask); 15 | 16 | testmask.focus(); 17 | $("#testmask").Type("10.10.10.10"); 18 | testmask2.focus(); 19 | setTimeout(function () { 20 | assert.equal(testmask.value, "10.10.10.10", "Result " + testmask.value); 21 | done(); 22 | }, 0); 23 | }); 24 | 25 | qunit.test('inputmask("ip" - 1.1.1.1', function (assert) { 26 | var done = assert.async(), 27 | $fixture = $("#qunit-fixture"); 28 | $fixture.append('<input type="text" id="testmask" />'); 29 | var testmask = document.getElementById("testmask"); 30 | $fixture.append('<input type="text" id="testmask2" />'); 31 | var testmask2 = document.getElementById("testmask2"); 32 | Inputmask("ip").mask(testmask); 33 | 34 | testmask.focus(); 35 | $("#testmask").Type("1.1.1.1"); 36 | testmask2.focus(); 37 | setTimeout(function () { 38 | assert.equal(testmask.value, "1.1.1.1", "Result " + testmask.value); 39 | done(); 40 | }, 0); 41 | }); 42 | 43 | qunit.test('inputmask("ip" - 255.255.255.255', function (assert) { 44 | var done = assert.async(), 45 | $fixture = $("#qunit-fixture"); 46 | $fixture.append('<input type="text" id="testmask" />'); 47 | var testmask = document.getElementById("testmask"); 48 | $fixture.append('<input type="text" id="testmask2" />'); 49 | var testmask2 = document.getElementById("testmask2"); 50 | Inputmask("ip").mask(testmask); 51 | 52 | testmask.focus(); 53 | $("#testmask").Type("255.255.255.255"); 54 | setTimeout(function () { 55 | testmask2.focus(); 56 | assert.equal( 57 | testmask.value, 58 | "255.255.255.255", 59 | "Result " + testmask.value 60 | ); 61 | done(); 62 | }, 0); 63 | }); 64 | 65 | qunit.test('inputmask("ip" - 192.168.1.100', function (assert) { 66 | var done = assert.async(), 67 | $fixture = $("#qunit-fixture"); 68 | $fixture.append('<input type="text" id="testmask" />'); 69 | var testmask = document.getElementById("testmask"); 70 | $fixture.append('<input type="text" id="testmask2" />'); 71 | var testmask2 = document.getElementById("testmask2"); 72 | Inputmask("ip").mask(testmask); 73 | 74 | testmask.focus(); 75 | $("#testmask").Type("192.168.1.100"); 76 | testmask2.focus(); 77 | setTimeout(function () { 78 | assert.equal(testmask.value, "192.168.1.100", "Result " + testmask.value); 79 | done(); 80 | }, 0); 81 | }); 82 | 83 | qunit.test( 84 | 'inputmask("ip" - 123123123123 - delete 2nd 1 - ', 85 | function (assert) { 86 | var done = assert.async(), 87 | $fixture = $("#qunit-fixture"); 88 | $fixture.append('<input type="text" id="testmask" />'); 89 | var testmask = document.getElementById("testmask"); 90 | $fixture.append('<input type="text" id="testmask2" />'); 91 | var testmask2 = document.getElementById("testmask2"); 92 | Inputmask("ip").mask(testmask); 93 | 94 | testmask.focus(); 95 | $("#testmask").Type("123123123123"); 96 | testmask2.focus(); 97 | $.caret(testmask, 4); 98 | $("#testmask").SendKey(keys.Delete); 99 | setTimeout(function () { 100 | assert.equal( 101 | testmask.value, 102 | "123.23.123.123", 103 | "Result " + testmask.value 104 | ); 105 | done(); 106 | }, 0); 107 | } 108 | ); 109 | 110 | qunit.test("ip - greedy: true", function (assert) { 111 | var done = assert.async(), 112 | $fixture = $("#qunit-fixture"); 113 | $fixture.append('<input type="text" id="testmask" />'); 114 | var testmask = document.getElementById("testmask"); 115 | Inputmask("ip", { 116 | greedy: true 117 | }).mask(testmask); 118 | 119 | testmask.focus(); 120 | setTimeout(function () { 121 | assert.equal( 122 | testmask.inputmask._valueGet(), 123 | "___.___.___.___", 124 | "Result " + testmask.inputmask._valueGet() 125 | ); 126 | done(); 127 | }, 0); 128 | }); 129 | 130 | qunit.test("ip - greedy: true 192.168.1.1", function (assert) { 131 | var done = assert.async(), 132 | $fixture = $("#qunit-fixture"); 133 | $fixture.append('<input type="text" id="testmask" />'); 134 | var testmask = document.getElementById("testmask"); 135 | Inputmask("ip", { 136 | greedy: true 137 | }).mask(testmask); 138 | 139 | testmask.focus(); 140 | $("#testmask").Type("192.168.1.1"); 141 | setTimeout(function () { 142 | assert.equal( 143 | testmask.inputmask._valueGet(), 144 | "192.168.1.1__", 145 | "Result " + testmask.inputmask._valueGet() 146 | ); 147 | done(); 148 | }, 0); 149 | }); 150 | 151 | qunit.test("ip - greedy: true 192.168.1.1", function (assert) { 152 | var done = assert.async(), 153 | $fixture = $("#qunit-fixture"); 154 | $fixture.append('<input type="text" id="testmask" />'); 155 | var testmask = document.getElementById("testmask"); 156 | Inputmask("ip", { 157 | greedy: true 158 | }).mask(testmask); 159 | 160 | testmask.focus(); 161 | $("#testmask").Type("192.168.1.1"); 162 | setTimeout(function () { 163 | assert.equal(testmask.value, "192.168.1.1", "Result " + testmask.value); 164 | done(); 165 | }, 0); 166 | }); 167 | 168 | qunit.test("ip - greedy: true 99999999", function (assert) { 169 | var done = assert.async(), 170 | $fixture = $("#qunit-fixture"); 171 | $fixture.append('<input type="text" id="testmask" />'); 172 | var testmask = document.getElementById("testmask"); 173 | Inputmask("ip", { 174 | greedy: true 175 | }).mask(testmask); 176 | 177 | testmask.focus(); 178 | $("#testmask").Type("99999999"); 179 | setTimeout(function () { 180 | assert.equal(testmask.value, "99.99.99.99", "Result " + testmask.value); 181 | done(); 182 | }, 0); 183 | }); 184 | } 185 | -------------------------------------------------------------------------------- /qunit/tests_jitmasking.js: -------------------------------------------------------------------------------- 1 | export default function (qunit, Inputmask) { 2 | const $ = Inputmask.dependencyLib; 3 | qunit.module("JIT Masking"); 4 | 5 | qunit.test( 6 | "'(.999){*}', { jitMasking: true, numericInput: true }", 7 | function (assert) { 8 | const $fixture = $("#qunit-fixture"); 9 | $fixture.append('<input type="text" id="testmask" />'); 10 | const testmask = document.getElementById("testmask"); 11 | 12 | Inputmask("(.999){*}", { 13 | jitMasking: true, 14 | numericInput: true, 15 | groupSeparator: "." // hack see numerics ~otherwise the extra . in front is expected 16 | }).mask(testmask); 17 | $("#testmask").Type("123456"); 18 | assert.equal($(testmask).val(), "123.456", "Result " + $(testmask).val()); 19 | } 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /qunit/tests_jquery_inputmask.js: -------------------------------------------------------------------------------- 1 | require("../lib/jquery.inputmask"); 2 | 3 | export default function (qunit, $, Inputmask) { 4 | qunit.module("jquery.inputmask plugin"); 5 | qunit.test("", function (assert) { 6 | var done = assert.async(), 7 | $fixture = $("#qunit-fixture"); 8 | $fixture.append('<input type="text" id="testmask" />'); 9 | 10 | $("#testmask").inputmask({ mask: "99-9999-99" }); 11 | $("#testmask").focus(); 12 | setTimeout(function () { 13 | assert.equal( 14 | $("#testmask")[0].inputmask._valueGet(), 15 | "__-____-__", 16 | "Result " + $("#testmask")[0].inputmask._valueGet() 17 | ); 18 | done(); 19 | }, 0); 20 | }); 21 | } 22 | -------------------------------------------------------------------------------- /qunit/tests_option.js: -------------------------------------------------------------------------------- 1 | export default function (qunit, Inputmask) { 2 | var $ = Inputmask.dependencyLib; 3 | qunit.module("Extra options after masking"); 4 | 5 | qunit.test("decimal alias add suffix later - gkostov", function (assert) { 6 | var $fixture = $("#qunit-fixture"); 7 | $fixture.append('<input type="text" id="testmask" />'); 8 | var testmask = document.getElementById("testmask"); 9 | Inputmask({ alias: "decimal", suffix: "" }).mask("testmask"); 10 | testmask.inputmask.option({ suffix: "%" }); 11 | 12 | $("#testmask").val("123.45"); 13 | assert.equal(testmask.value, "123.45%", "Result " + testmask.value); 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /qunit/tests_setvalue.js: -------------------------------------------------------------------------------- 1 | export default function (qunit, Inputmask) { 2 | var $ = Inputmask.dependencyLib; 3 | qunit.module("Set value with fn.val"); 4 | qunit.test('inputmask("decimal") ~ value="123.45"', function (assert) { 5 | var $fixture = $("#qunit-fixture"); 6 | $fixture.append('<input type="text" id="testmask" />'); 7 | var testmask = document.getElementById("testmask"); 8 | Inputmask("decimal").mask(testmask); 9 | $("#testmask").val("123.45"); 10 | assert.equal(testmask.value, "123.45", "Result " + testmask.value); 11 | }); 12 | 13 | qunit.test('inputmask("9") ~ value="1" ', function (assert) { 14 | var $fixture = $("#qunit-fixture"); 15 | $fixture.append('<input type="text" id="testmask" />'); 16 | var testmask = document.getElementById("testmask"); 17 | Inputmask("9").mask(testmask); 18 | $("#testmask").val("1"); 19 | assert.equal(testmask.value, "1", "Result " + testmask.value); 20 | }); 21 | 22 | qunit.test( 23 | 'inputmask("decimal") ~ .val("123.45") - disabled input', 24 | function (assert) { 25 | var $fixture = $("#qunit-fixture"); 26 | $fixture.append( 27 | '<input type="text" id="testmask" disabled="disabled" />' 28 | ); 29 | var testmask = document.getElementById("testmask"); 30 | Inputmask("decimal").mask(testmask); 31 | $("#testmask").val("123.45"); 32 | assert.equal(testmask.value, "123.45", "Result " + testmask.value); 33 | } 34 | ); 35 | 36 | qunit.test( 37 | 'inputmask("mm/yyyy") ~ .val("031973") - disabled input', 38 | function (assert) { 39 | var $fixture = $("#qunit-fixture"); 40 | $fixture.append( 41 | '<input type="text" id="testmask" disabled="disabled" />' 42 | ); 43 | var testmask = document.getElementById("testmask"); 44 | Inputmask("datetime", { inputFormat: "mm/yyyy", min: "01/1900" }).mask( 45 | testmask 46 | ); 47 | $("#testmask").val("031973"); 48 | assert.equal(testmask.value, "03/1973", "Result " + testmask.value); 49 | } 50 | ); 51 | 52 | qunit.test( 53 | 'inputmask({ "mask": "(999) 999-9999" }) ~ .val("8144419449") - type="tel" - bodrick', 54 | function (assert) { 55 | var $fixture = $("#qunit-fixture"); 56 | $fixture.append('<input type="tel" id="testmask" disabled="disabled" />'); 57 | var testmask = document.getElementById("testmask"); 58 | Inputmask({ 59 | mask: "(999) 999-9999" 60 | }).mask(testmask); 61 | $("#testmask").val("8144419449"); 62 | assert.equal( 63 | testmask.value, 64 | "(814) 441-9449", 65 | "Result " + testmask.value 66 | ); 67 | } 68 | ); 69 | 70 | qunit.test( 71 | ".inputmask('decimal',{ alias:\"decimal\",integerDigits:9,digits:3,digitsOptional: false,placeholder: '0' }); - '2000.000' - vijjj", 72 | function (assert) { 73 | var $fixture = $("#qunit-fixture"); 74 | $fixture.append('<input type="text" id="testmask" />'); 75 | var testmask = document.getElementById("testmask"); 76 | Inputmask("decimal", { 77 | alias: "decimal", 78 | integerDigits: 9, 79 | digits: 3, 80 | digitsOptional: false, 81 | placeholder: "0" 82 | }).mask(testmask); 83 | $("#testmask").val("2000.000"); 84 | assert.equal(testmask.value, "2000.000", "Result " + testmask.value); 85 | } 86 | ); 87 | 88 | qunit.test( 89 | ".inputmask('decimal',{ alias:\"decimal\",integerDigits:9,digits:3,digitsOptional: false,placeholder: '0' }); - 3000.000 - vijjj", 90 | function (assert) { 91 | var $fixture = $("#qunit-fixture"); 92 | $fixture.append('<input type="text" id="testmask" />'); 93 | var testmask = document.getElementById("testmask"); 94 | Inputmask("decimal", { 95 | alias: "decimal", 96 | integerDigits: 9, 97 | digits: 3, 98 | digitsOptional: false, 99 | placeholder: "0" 100 | }).mask(testmask); 101 | $("#testmask").val(3000.0); 102 | assert.equal(testmask.value, "3000.000", "Result " + testmask.value); 103 | } 104 | ); 105 | 106 | qunit.test( 107 | ".inputmask('decimal',{ alias:\"decimal\",integerDigits:9,digits:3,digitsOptional: false,placeholder: '0' }); - '4000.00' - vijjj", 108 | function (assert) { 109 | var $fixture = $("#qunit-fixture"); 110 | $fixture.append('<input type="text" id="testmask" />'); 111 | var testmask = document.getElementById("testmask"); 112 | Inputmask("decimal", { 113 | alias: "decimal", 114 | integerDigits: 9, 115 | digits: 3, 116 | digitsOptional: false, 117 | placeholder: "0" 118 | }).mask(testmask); 119 | $("#testmask").val("4000.00"); 120 | assert.equal(testmask.value, "4000.000", "Result " + testmask.value); 121 | } 122 | ); 123 | 124 | qunit.test( 125 | ".inputmask('decimal',{ alias:\"decimal\",integerDigits:9,digits:3,digitsOptional: false,placeholder: '0' }); - '5000.000' - vijjj", 126 | function (assert) { 127 | var $fixture = $("#qunit-fixture"); 128 | $fixture.append('<input type="text" id="testmask" />'); 129 | var testmask = document.getElementById("testmask"); 130 | Inputmask("decimal", { 131 | alias: "decimal", 132 | integerDigits: 9, 133 | digits: 3, 134 | digitsOptional: false, 135 | placeholder: "0" 136 | }).mask(testmask); 137 | document.getElementById("testmask").value = "5000.000"; 138 | assert.equal(testmask.value, "5000.000", "Result " + testmask.value); 139 | } 140 | ); 141 | 142 | qunit.test( 143 | '.inputmask("mask", {"mask": "+7 (999) 999-99-99"}); - "+7 (705) 123-45-67" - serious-andy', 144 | function (assert) { 145 | var $fixture = $("#qunit-fixture"); 146 | $fixture.append('<input type="text" id="testmask" />'); 147 | var testmask = document.getElementById("testmask"); 148 | Inputmask("mask", { 149 | mask: "+7 (999) 999-99-99" 150 | }).mask(testmask); 151 | $("#testmask").val("+7 (705) 123-45-67"); 152 | assert.equal( 153 | testmask.value, 154 | "+7 (705) 123-45-67", 155 | "Result " + testmask.value 156 | ); 157 | } 158 | ); 159 | 160 | qunit.test( 161 | '.inputmask("mask", {"mask": "+375 (99) 999-99-99"}); - "+375 (37) 999-99-99" - PavelTyk', 162 | function (assert) { 163 | var $fixture = $("#qunit-fixture"); 164 | $fixture.append('<input type="text" id="testmask" />'); 165 | var testmask = document.getElementById("testmask"); 166 | Inputmask("mask", { 167 | mask: "+375 (99) 999-99-99" 168 | }).mask(testmask); 169 | $("#testmask").val("+375 (37) 999-99-99"); 170 | assert.equal( 171 | testmask.value, 172 | "+375 (37) 999-99-99", 173 | "Result " + testmask.value 174 | ); 175 | } 176 | ); 177 | 178 | qunit.test( 179 | '.inputmask("mask", {"mask": "+7(999)999-99-99"}); - \'7771231234\' + \'\' - moongrate', 180 | function (assert) { 181 | var $fixture = $("#qunit-fixture"), 182 | done = assert.async(); 183 | $fixture.append('<input type="text" id="testmask" />'); 184 | var testmask = document.getElementById("testmask"); 185 | Inputmask("mask", { 186 | mask: "+7(999)999-99-99" 187 | }).mask(testmask); 188 | testmask.focus(); 189 | setTimeout(function () { 190 | $("#testmask").Type("7771231234"); 191 | $("#testmask").val(testmask.value); 192 | assert.equal( 193 | testmask.value, 194 | "+7(777)123-12-34", 195 | "Result " + testmask.value 196 | ); 197 | done(); 198 | }, 0); 199 | } 200 | ); 201 | } 202 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"), 2 | _ = require("lodash"), 3 | terserPlugin = require("terser-webpack-plugin"), 4 | webpack = require("webpack"); 5 | 6 | function createBanner() { 7 | const pkg = JSON.parse(fs.readFileSync("./package.json")); 8 | return ( 9 | "[name]\n" + 10 | `${pkg.homepage}\n` + 11 | `Copyright (c) 2010 - ${new Date().getFullYear()} ${pkg.author.name}\n` + 12 | `Licensed under the ${pkg.license} license\n` + 13 | `Version: ${pkg.version}` 14 | ); 15 | } 16 | 17 | const rules = { 18 | js: { 19 | test: /\.js$/, 20 | loader: "babel-loader", 21 | exclude: /(node_modules)/, 22 | options: { 23 | presets: ["@babel/preset-env", "@babel/preset-typescript"], 24 | plugins: ["@babel/plugin-transform-modules-commonjs"], 25 | passPerPreset: true 26 | } 27 | }, 28 | ts: { 29 | test: /\.tsx?$/, 30 | loader: "babel-loader", 31 | exclude: /(node_modules)/, 32 | options: { 33 | presets: ["@babel/preset-typescript"], 34 | passPerPreset: true 35 | } 36 | } 37 | }; 38 | 39 | module.exports = function (env, argv) { 40 | const config = { 41 | name: "main", 42 | entry: { 43 | "dist/inputmask": "./bundle.js", 44 | "dist/inputmask.min": "./bundle.js", 45 | "qunit/qunit": "./qunit/index.js" 46 | }, 47 | // experiments: { 48 | // outputModule: true, 49 | // }, 50 | output: { 51 | path: __dirname, 52 | filename: "[name].js", 53 | library: { 54 | type: "umd2" 55 | }, 56 | globalObject: "typeof self !== 'undefined' ? self : this" 57 | }, 58 | externals: { 59 | jquery: { 60 | commonjs: "jquery", 61 | commonjs2: "jquery", 62 | amd: "jquery", 63 | root: "jQuery" 64 | }, 65 | jqlite: "jqlite", 66 | qunit: "QUnit", 67 | window: "window" 68 | }, 69 | optimization: { 70 | minimize: env === "production", 71 | minimizer: [ 72 | new terserPlugin({ 73 | include: /\.min\.js$/, 74 | terserOptions: { 75 | sourceMap: env !== "production", 76 | format: { 77 | ascii_only: true, 78 | beautify: false, 79 | comments: /^!/ 80 | }, 81 | compress: { 82 | drop_console: env === "production" 83 | } 84 | }, 85 | extractComments: false 86 | }), 87 | new terserPlugin({ 88 | exclude: /\.min\.js$/, 89 | terserOptions: { 90 | sourceMap: env !== "production", 91 | format: { 92 | ascii_only: true, 93 | beautify: true, 94 | comments: /^!/ 95 | }, 96 | compress: { 97 | drop_console: env === "production" 98 | } 99 | }, 100 | extractComments: false 101 | }) 102 | ] 103 | }, 104 | module: { 105 | rules: [rules.js, rules.ts] 106 | }, 107 | resolve: { 108 | extensions: [".wasm", ".mjs", ".js", ".ts", ".json"], 109 | alias: { 110 | // "./dependencyLibs/inputmask.dependencyLib": "./dependencyLibs/inputmask.dependencyLib.jquery" 111 | } 112 | }, 113 | devtool: env === "production" ? undefined : "source-map", 114 | plugins: [ 115 | new webpack.BannerPlugin({ 116 | banner: createBanner, 117 | entryOnly: true 118 | }) 119 | ], 120 | bail: true, 121 | mode: env === "production" ? "production" : "none", 122 | target: ["web", "es5"] 123 | }, 124 | jqueryConfig = _.defaultsDeep({}, config); 125 | jqueryConfig.entry = {}; 126 | _.assignIn(jqueryConfig, { 127 | name: "jquery", 128 | resolve: { 129 | extensions: [".wasm", ".mjs", ".js", ".ts", ".json"], 130 | alias: { 131 | "./dependencyLibs/inputmask.dependencyLib": 132 | "./dependencyLibs/inputmask.dependencyLib.jquery" 133 | } 134 | }, 135 | entry: { 136 | "dist/jquery.inputmask": "./bundle.jquery.js", 137 | "dist/jquery.inputmask.min": "./bundle.jquery.js", 138 | "qunit/qunit": "./qunit/index.js" 139 | } 140 | }); 141 | 142 | const colorMaskConfig = _.defaultsDeep({}, config); 143 | colorMaskConfig.entry = {}; 144 | _.assignIn(colorMaskConfig, { 145 | name: "colormask", 146 | entry: { 147 | "dist/colormask": "./bundle.colormask.js", 148 | "dist/colormask.min": "./bundle.colormask.js" 149 | } 150 | }); 151 | return [config, jqueryConfig, colorMaskConfig]; 152 | }; 153 | --------------------------------------------------------------------------------