From d170438dac7f81aebdc3f176da7d534ba16efbf5 Mon Sep 17 00:00:00 2001 From: Ferry Date: Wed, 20 Feb 2019 20:23:21 +0100 Subject: [PATCH] publishing version 1.6.0 --- README.md | 272 ++++++------- css/bootstrap-pincode-input.css | 9 +- js/bootstrap-pincode-input.js | 662 ++++++++++++++++---------------- package-lock.json | 5 + package.json | 53 +-- 5 files changed, 507 insertions(+), 494 deletions(-) create mode 100644 package-lock.json diff --git a/README.md b/README.md index 3100b02..82175f6 100644 --- a/README.md +++ b/README.md @@ -1,136 +1,136 @@ -# Bootstrap pincode-input -Bootstrap jQuery widget for x-digit pincode input - -You only need a <input type="text"> and Bootstrap. - -After entering a pincode the value will be updated in the original textbox. -It supports a callback after all digits are entered and backspace is allowed. -See Usage below this page to find out all parameters - -For touch devices there will be only one input tag created. With the supplied CSS it will look like the user is inputting a code in multiple input boxes. - - -# Demo - -A demo can be found at [fkranenburg.github.io/bootstrap-pincode-input][site] - -[site]: http://fkranenburg.github.io/bootstrap-pincode-input - - -![screenshot](https://raw.github.com/fkranenburg/bootstrap-pincode-input/master/example.jpg) - -# Installation - -You can install bootstrap-pincode-input by using [Bower](http://bower.io/). - -```bash -bower install bootstrap-pincode-input -``` -Or you can install it through [npm](https://www.npmjs.com/): - -``` -npm install --save bootstrap-pincode-input -``` - -## Usage - -### inputs -Number. Default: `0` - -Length of to be entered code. For every digit a input box will be created and visibile for the user. - -```html - -``` -This function will create, for example, an input box with 4 digits. -```javascript -$('#pincode-input1').pincodeInput({inputs:4}); -``` - - - -### placeholders -String. Default: ```null``` - -Place placeholders in every input. Make sure you define a placeholder for each input seperated with a ```space```. -For example an input with 3 digits, placeholders are defined like ```1 2 3```. - -```html - -``` - -```javascript -$('#pincode-input1').pincodeInput({inputs:2,placeholders:"0 0 0"}); -``` - -### hidedigits -Boolean. Default: ```true``` - -By default entered digits are hidden visually (like a password input) for the user. -This can be overriden by setting this to ```false```. - -```html - -``` - -```javascript -$('#pincode-input1').pincodeInput({inputs:4,hidedigits:false}); -``` - - -### keydown -@deprecated since 1.3.0 -> will be removed in a later release. Use change event instead. - -Callback function for keydown event for each input box. The ```keydown``` event is passed to the callback. - - -```javascript -$('#pincode-input1').pincodeInput({keydown:function(e){ - console.log("keydown event fired!",e); -}); -``` - - -### change -Callback function for each input box after user enters or removes a digit. -The following parameters are passed to the given function. - -* ```input``` Element. the DOM input element where user changed a digit. -* ```value``` String. the value entered -* ```inputnumber``` Number. returns the 'position' of the current input. - - -```javascript - $('#pincode-input1').pincodeInput({inputs:4,change: function(input,value,inputnumber){ - console.log("onchange from input number "+inputnumber+", current value: " + value, input); - }}); -``` - - -### complete -Callback function when all input boxes have a value (user has entered the full code). -The following parameters are passed to the given function. - -* ```value``` String. complete given code as a string. -* ```event``` Event. the last 'keydown' event from last inputbox. -* ```errorElement``` Element. returns the error element where you can put a custom error message for the user, for example the code is invalid. - - -```javascript - $('#pincode-input1').pincodeInput({inputs:6,complete:function(value, e, errorElement){ - console.log("code entered: " + value); - - /*do some code checking here*/ - - $(errorElement).html("I'm sorry, but the code not correct"); - }}); -``` - - - -# License - -This plugin is available under the [Apache 2.0 license][siteapache] -[siteapache]: https://www.apache.org/licenses/LICENSE-2.0 - -Created by Ferry Kranenburg +# Bootstrap pincode-input +Bootstrap jQuery widget for x-digit pincode input + +You only need a <input type="text"> and Bootstrap. + +After entering a pincode the value will be updated in the original textbox. +It supports a callback after all digits are entered and backspace is allowed. +See Usage below this page to find out all parameters + +For touch devices there will be only one input tag created. With the supplied CSS it will look like the user is inputting a code in multiple input boxes. + + +# Demo + +A demo can be found at [fkranenburg.github.io/bootstrap-pincode-input][site] + +[site]: http://fkranenburg.github.io/bootstrap-pincode-input + + +![screenshot](https://raw.github.com/fkranenburg/bootstrap-pincode-input/master/example.jpg) + +# Installation + +You can install bootstrap-pincode-input by using [Bower](http://bower.io/). + +```bash +bower install bootstrap-pincode-input +``` +Or you can install it through [npm](https://www.npmjs.com/): + +``` +npm install --save bootstrap-pincode-input +``` + +## Usage + +### inputs +Number. Default: `0` + +Length of to be entered code. For every digit a input box will be created and visibile for the user. + +```html + +``` +This function will create, for example, an input box with 4 digits. +```javascript +$('#pincode-input1').pincodeInput({inputs:4}); +``` + + + +### placeholders +String. Default: ```null``` + +Place placeholders in every input. Make sure you define a placeholder for each input seperated with a ```space```. +For example an input with 3 digits, placeholders are defined like ```1 2 3```. + +```html + +``` + +```javascript +$('#pincode-input1').pincodeInput({inputs:2,placeholders:"0 0 0"}); +``` + +### hidedigits +Boolean. Default: ```true``` + +By default entered digits are hidden visually (like a password input) for the user. +This can be overriden by setting this to ```false```. + +```html + +``` + +```javascript +$('#pincode-input1').pincodeInput({inputs:4,hidedigits:false}); +``` + + +### keydown +@deprecated since 1.3.0 -> will be removed in a later release. Use change event instead. + +Callback function for keydown event for each input box. The ```keydown``` event is passed to the callback. + + +```javascript +$('#pincode-input1').pincodeInput({keydown:function(e){ + console.log("keydown event fired!",e); +}); +``` + + +### change +Callback function for each input box after user enters or removes a digit. +The following parameters are passed to the given function. + +* ```input``` Element. the DOM input element where user changed a digit. +* ```value``` String. the value entered +* ```inputnumber``` Number. returns the 'position' of the current input. + + +```javascript + $('#pincode-input1').pincodeInput({inputs:4,change: function(input,value,inputnumber){ + console.log("onchange from input number "+inputnumber+", current value: " + value, input); + }}); +``` + + +### complete +Callback function when all input boxes have a value (user has entered the full code). +The following parameters are passed to the given function. + +* ```value``` String. complete given code as a string. +* ```event``` Event. the last 'keydown' event from last inputbox. +* ```errorElement``` Element. returns the error element where you can put a custom error message for the user, for example the code is invalid. + + +```javascript + $('#pincode-input1').pincodeInput({inputs:6,complete:function(value, e, errorElement){ + console.log("code entered: " + value); + + /*do some code checking here*/ + + $(errorElement).html("I'm sorry, but the code not correct"); + }}); +``` + + + +# License + +This plugin is available under the [Apache 2.0 license]: + https://www.apache.org/licenses/LICENSE-2.0 + +Created by Ferry Kranenburg diff --git a/css/bootstrap-pincode-input.css b/css/bootstrap-pincode-input.css index 48a92e3..fd306e1 100644 --- a/css/bootstrap-pincode-input.css +++ b/css/bootstrap-pincode-input.css @@ -1,3 +1,10 @@ +@font-face { + font-family: "pincode-input-mask"; + src: url(data:font/woff;charset:utf-8;base64,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) format("woff"); +} +.pincode-input-text-masked { + font-family: pincode-input-mask; +} .pincode-input-container { display:inline-block; } @@ -37,7 +44,7 @@ display: block; background-color:transparent; background:transparent; - letter-spacing:20px; + letter-spacing:24px; } /* On every digit we use the letter-spacing of the above textbox to determine the table background diff --git a/js/bootstrap-pincode-input.js b/js/bootstrap-pincode-input.js index 0d76b89..fd84fdf 100644 --- a/js/bootstrap-pincode-input.js +++ b/js/bootstrap-pincode-input.js @@ -1,331 +1,331 @@ -/* ========================================================= - * bootstrap-pincode-input.js - * - * ========================================================= - * Created by Ferry Kranenburg - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ========================================================= */ - -;(function ($, window, document, undefined) { - - "use strict"; - - - // Create the defaults once - var pluginName = "pincodeInput"; - var defaults = { - placeholders: undefined, // seperate with a " "(space) to set an placeholder for each input box - inputs: 4, // 4 input boxes = code of 4 digits long - hidedigits: true, // hide digits - patern: '[0-9]*', - inputtype: 'number', - inputmode: 'numeric', - keydown: function (e) { - }, - change: function (input, value, inputnumber) { // callback on every input on change (keyup event) - //input = the input textbox DOM element - //value = the value entered by user (or removed) - //inputnumber = the position of the input box (in touch mode we only have 1 big input box, so always 1 is returned here) - }, - complete: function (value, e, errorElement) { // callback when all inputs are filled in (keyup event) - //value = the entered code - //e = last keyup event - //errorElement = error span next to to this, fill with html e.g. : $(errorElement).html("Code not correct"); - } - - }; - - // The actual plugin constructor - function Plugin(element, options) { - this.element = element; - this.settings = $.extend({}, defaults, options); - this._defaults = defaults; - this._name = pluginName; - this.init(); - } - - // Avoid Plugin.prototype conflicts - $.extend(Plugin.prototype, { - init: function () { - this.buildInputBoxes(); - - }, - updateOriginalInput: function () { - var newValue = ""; - $('.pincode-input-text', this._container).each(function (index, value) { - newValue += $(value).val().toString(); - }); - $(this.element).val(newValue); - }, - check: function () { - var isComplete = true; - var code = ""; - $('.pincode-input-text', this._container).each(function (index, value) { - code += $(value).val().toString(); - if (!$(value).val()) { - isComplete = false; - } - }); - - if (this._isTouchDevice()) { - // check if single input has it all - if (code.length == this.settings.inputs) { - return true; - } - } else { - return isComplete; - } - - - }, - buildInputBoxes: function () { - this._container = $('
').addClass('pincode-input-container'); - - - var currentValue = []; - var placeholders = []; - var touchplaceholders = ""; //in touch mode we have just 1 big input box, and there is only 1 placeholder in this case - - if (this.settings.placeholders) { - placeholders = this.settings.placeholders.split(" "); - touchplaceholders = this.settings.placeholders.replace(/ /g, ""); - } - - // If we do not hide digits, we need to include the current value of the input box - // This will only work if the current value is not longer than the number of input boxes. - if (this.settings.hidedigits == false && $(this.element).val() != "") { - currentValue = $(this.element).val().split(""); - } - - // make sure this is the first password field here - if (this.settings.hidedigits) { - this._pwcontainer = $('
').css("display", "none").appendTo(this._container); - this._pwfield = $('').attr({ - 'type': 'password', - 'pattern': this.settings.pattern, - 'inputmode': this.settings.inputmode, - 'id': 'preventautofill', - 'autocomplete': 'off' - }).appendTo(this._pwcontainer); - } - - if (this._isTouchDevice()) { - // set main class - $(this._container).addClass("touch"); - - // For touch devices we build a html table directly under the pincode textbox. The textbox will become transparent - // This table is used for styling only, it will display how many 'digits' the user should fill in. - // With CSS letter-spacing we try to put every digit visually insize each table cell. - - var wrapper = $('
').addClass('touchwrapper touch' + this.settings.inputs).appendTo(this._container); - var input = $('').attr({ - 'type': this.settings.inputtype, - 'pattern': this.settings.pattern, - 'inputmode': this.settings.inputmode, - 'placeholder': touchplaceholders, - 'maxlength': this.settings.inputs, - 'autocomplete': 'off' - }).addClass('form-control pincode-input-text').appendTo(wrapper); - - var touchtable = $('').addClass('touchtable').appendTo(wrapper); - var row = $('').appendTo(touchtable); - // create touch background elements (for showing user how many digits must be entered) - for (var i = 0; i < this.settings.inputs; i++) { - if (i == (this.settings.inputs - 1)) { - $('
').addClass('last').appendTo(row); - } else { - $('').appendTo(row); - } - } - if (this.settings.hidedigits) { - // hide digits - input.attr('type', 'password'); - } else { - // show digits, also include default value - input.val(currentValue[i]); - } - - // add events - this._addEventsToInput(input, 1); - - } else { - // for desktop mode we build one input for each digit - for (var i = 0; i < this.settings.inputs; i++) { - - var input = $('').attr({ - 'type': 'text', - 'maxlength': "1", - 'autocomplete': 'off', - 'placeholder': (placeholders[i] ? placeholders[i] : undefined) - }).addClass('form-control pincode-input-text').appendTo(this._container); - if (this.settings.hidedigits) { - // hide digits - input.attr('type', 'password'); - } else { - // show digits, also include default value - input.val(currentValue[i]); - } - - if (i == 0) { - input.addClass('first'); - } else if (i == (this.settings.inputs - 1)) { - input.addClass('last'); - } else { - input.addClass('mid'); - } - - // add events - this._addEventsToInput(input, (i + 1)); - } - } - - - // error box - this._error = $('
').addClass('text-danger pincode-input-error').appendTo(this._container); - - //hide original element and place this before it - $(this.element).css("display", "none"); - this._container.insertBefore(this.element); - }, - enable: function () { - $('.pincode-input-text', this._container).each(function (index, value) { - $(value).prop('disabled', false); - }); - }, - disable: function () { - $('.pincode-input-text', this._container).each(function (index, value) { - $(value).prop('disabled', true); - }); - }, - focus: function () { - $('.pincode-input-text', this._container).first().select().focus(); - }, - clear: function () { - $('.pincode-input-text', this._container).each(function (index, value) { - $(value).val(""); - }); - this.updateOriginalInput(); - }, - _isTouchDevice: function () { - // I know, sniffing is a really bad idea, but it works 99% of the times - if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) { - return true; - } - }, - _addEventsToInput: function (input, inputnumber) { - - input.on('focus', function (e) { - this.select(); //automatically select current value - }); - - input.on('keydown', $.proxy(function (e) { - if (this._pwfield) { - // Because we need to prevent password saving by browser - // remove the value here and change the type! - // we do this every time the user types - $(this._pwfield).attr({'type': 'text'}); - $(this._pwfield).val(""); - } - - // prevent more input for touch device (we can't limit it) - if (this._isTouchDevice()) { - if (e.keyCode == 8 || e.keyCode == 46) { - // do nothing on backspace and delete - - } else { - if ($(this.element).val().length == this.settings.inputs) { - e.preventDefault(); - e.stopPropagation(); - } - } - - } else { - // in desktop mode, check if an number was entered - - if (!(e.keyCode == 8 // backspace key - || e.keyCode == 9 // tab key - || e.keyCode == 46 // delete key - || (e.keyCode >= 48 && e.keyCode <= 57) // numbers on keyboard - || (e.keyCode >= 96 && e.keyCode <= 105) // number on keypad - || (this.settings.inputtype != 'number' && e.keyCode >= 65 && e.keyCode <= 90)) // alfabet - ) { - e.preventDefault(); // Prevent character input - e.stopPropagation(); - - } - - } - - this.settings.keydown(e); - }, this)); - - input.on('keyup', $.proxy(function (e) { - // after every keystroke we check if all inputs have a value, if yes we call complete callback - if (!this._isTouchDevice()) { - // on backspace or delete go to previous input box - if (e.keyCode == 8 || e.keyCode == 46) { - // goto previous - $(e.currentTarget).prev().select(); - $(e.currentTarget).prev().focus(); - } else { - if ($(e.currentTarget).val() != "") { - $(e.currentTarget).next().select(); - $(e.currentTarget).next().focus(); - } - } - } - - // update original input box - this.updateOriginalInput(); - - // oncomplete check - if (this.check()) { - this.settings.complete($(this.element).val(), e, this._error); - } - - //onchange event for each input - if (this.settings.change) { - this.settings.change(e.currentTarget, $(e.currentTarget).val(), inputnumber); - } - - - // prevent more input for touch device (we can't limit it) - if (this._isTouchDevice()) { - if (e.keyCode == 8 || e.keyCode == 46) { - // do nothing on backspace and delete - } else { - if ($(this.element).val().length == this.settings.inputs) { - $(e.currentTarget).blur(); - } - } - - } - - }, this)); - } - - - }); - - // A really lightweight plugin wrapper around the constructor, - // preventing against multiple instantiations - $.fn[pluginName] = function (options) { - return this.each(function () { - if (!$.data(this, "plugin_" + pluginName)) { - $.data(this, "plugin_" + pluginName, new Plugin(this, options)); - } - }); - }; - -})(jQuery, window, document); +/* ========================================================= + * bootstrap-pincode-input.js + * + * ========================================================= + * Created by Ferry Kranenburg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================= */ + +;(function ($, window, document, undefined) { + + "use strict"; + + + // Create the defaults once + var pluginName = "pincodeInput"; + var defaults = { + placeholders: undefined, // seperate with a " "(space) to set an placeholder for each input box + inputs: 4, // 4 input boxes = code of 4 digits long + hidedigits: true, // hide digits + patern: '[0-9]*', + inputtype: 'number', + inputmode: 'numeric', + keydown: function (e) { + }, + change: function (input, value, inputnumber) { // callback on every input on change (keyup event) + //input = the input textbox DOM element + //value = the value entered by user (or removed) + //inputnumber = the position of the input box (in touch mode we only have 1 big input box, so always 1 is returned here) + }, + complete: function (value, e, errorElement) { // callback when all inputs are filled in (keyup event) + //value = the entered code + //e = last keyup event + //errorElement = error span next to to this, fill with html e.g. : $(errorElement).html("Code not correct"); + } + + }; + + // The actual plugin constructor + function Plugin(element, options) { + this.element = element; + this.settings = $.extend({}, defaults, options); + this._defaults = defaults; + this._name = pluginName; + this.init(); + } + + // Avoid Plugin.prototype conflicts + $.extend(Plugin.prototype, { + init: function () { + this.buildInputBoxes(); + + }, + updateOriginalInput: function () { + var newValue = ""; + $('.pincode-input-text', this._container).each(function (index, value) { + newValue += $(value).val().toString(); + }); + $(this.element).val(newValue); + }, + check: function () { + var isComplete = true; + var code = ""; + $('.pincode-input-text', this._container).each(function (index, value) { + code += $(value).val().toString(); + if (!$(value).val()) { + isComplete = false; + } + }); + + if (this._isTouchDevice()) { + // check if single input has it all + if (code.length == this.settings.inputs) { + return true; + } + } else { + return isComplete; + } + + + }, + buildInputBoxes: function () { + this._container = $('
').addClass('pincode-input-container'); + + + var currentValue = []; + var placeholders = []; + var touchplaceholders = ""; //in touch mode we have just 1 big input box, and there is only 1 placeholder in this case + + if (this.settings.placeholders) { + placeholders = this.settings.placeholders.split(" "); + touchplaceholders = this.settings.placeholders.replace(/ /g, ""); + } + + // If we do not hide digits, we need to include the current value of the input box + // This will only work if the current value is not longer than the number of input boxes. + if (this.settings.hidedigits == false && $(this.element).val() != "") { + currentValue = $(this.element).val().split(""); + } + + // make sure this is the first password field here + if (this.settings.hidedigits) { + this._pwcontainer = $('
').css("display", "none").appendTo(this._container); + this._pwfield = $('').attr({ + 'type': this.settings.inputtype, + 'pattern': this.settings.pattern, + 'inputmode': this.settings.inputmode, + 'id': 'preventautofill', + 'autocomplete': 'off' + }).addClass('pincode-input-text-masked').appendTo(this._pwcontainer); + } + + if (this._isTouchDevice()) { + // set main class + $(this._container).addClass("touch"); + + // For touch devices we build a html table directly under the pincode textbox. The textbox will become transparent + // This table is used for styling only, it will display how many 'digits' the user should fill in. + // With CSS letter-spacing we try to put every digit visually insize each table cell. + + var wrapper = $('
').addClass('touchwrapper touch' + this.settings.inputs).appendTo(this._container); + var input = $('').attr({ + 'type': this.settings.inputtype, + 'pattern': this.settings.pattern, + 'inputmode': this.settings.inputmode, + 'placeholder': touchplaceholders, + 'maxlength': this.settings.inputs, + 'autocomplete': 'off' + }).addClass('form-control pincode-input-text').appendTo(wrapper); + + var touchtable = $('').addClass('touchtable').appendTo(wrapper); + var row = $('').appendTo(touchtable); + // create touch background elements (for showing user how many digits must be entered) + for (var i = 0; i < this.settings.inputs; i++) { + if (i == (this.settings.inputs - 1)) { + $('
').addClass('last').appendTo(row); + } else { + $('').appendTo(row); + } + } + if (this.settings.hidedigits) { + // hide digits + input.addClass('pincode-input-text-masked'); + } else { + // show digits, also include default value + input.val(currentValue[i]); + } + + // add events + this._addEventsToInput(input, 1); + + } else { + // for desktop mode we build one input for each digit + for (var i = 0; i < this.settings.inputs; i++) { + + var input = $('').attr({ + 'type': 'text', + 'maxlength': "1", + 'autocomplete': 'off', + 'placeholder': (placeholders[i] ? placeholders[i] : undefined) + }).addClass('form-control pincode-input-text').appendTo(this._container); + if (this.settings.hidedigits) { + // hide digits + input.addClass('pincode-input-text-masked'); + } else { + // show digits, also include default value + input.val(currentValue[i]); + } + + if (i == 0) { + input.addClass('first'); + } else if (i == (this.settings.inputs - 1)) { + input.addClass('last'); + } else { + input.addClass('mid'); + } + + // add events + this._addEventsToInput(input, (i + 1)); + } + } + + + // error box + this._error = $('
').addClass('text-danger pincode-input-error').appendTo(this._container); + + //hide original element and place this before it + $(this.element).css("display", "none"); + this._container.insertBefore(this.element); + }, + enable: function () { + $('.pincode-input-text', this._container).each(function (index, value) { + $(value).prop('disabled', false); + }); + }, + disable: function () { + $('.pincode-input-text', this._container).each(function (index, value) { + $(value).prop('disabled', true); + }); + }, + focus: function () { + $('.pincode-input-text', this._container).first().select().focus(); + }, + clear: function () { + $('.pincode-input-text', this._container).each(function (index, value) { + $(value).val(""); + }); + this.updateOriginalInput(); + }, + _isTouchDevice: function () { + // I know, sniffing is a really bad idea, but it works 99% of the times + if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) { + return true; + } + }, + _addEventsToInput: function (input, inputnumber) { + + input.on('focus', function (e) { + this.select(); //automatically select current value + }); + + input.on('keydown', $.proxy(function (e) { + if (this._pwfield) { + // Because we need to prevent password saving by browser + // remove the value here and change the type! + // we do this every time the user types + $(this._pwfield).attr({'type': 'text'}); + $(this._pwfield).val(""); + } + + // prevent more input for touch device (we can't limit it) + if (this._isTouchDevice()) { + if (e.keyCode == 8 || e.keyCode == 46) { + // do nothing on backspace and delete + + } else { + if ($(this.element).val().length == this.settings.inputs) { + e.preventDefault(); + e.stopPropagation(); + } + } + + } else { + // in desktop mode, check if an number was entered + + if (!(e.keyCode == 8 // backspace key + || e.keyCode == 9 // tab key + || e.keyCode == 46 // delete key + || (e.keyCode >= 48 && e.keyCode <= 57) // numbers on keyboard + || (e.keyCode >= 96 && e.keyCode <= 105) // number on keypad + || (this.settings.inputtype != 'number' && e.keyCode >= 65 && e.keyCode <= 90)) // alfabet + ) { + e.preventDefault(); // Prevent character input + e.stopPropagation(); + + } + + } + + this.settings.keydown(e); + }, this)); + + input.on('keyup', $.proxy(function (e) { + // after every keystroke we check if all inputs have a value, if yes we call complete callback + if (!this._isTouchDevice()) { + // on backspace or delete go to previous input box + if (e.keyCode == 8 || e.keyCode == 46) { + // goto previous + $(e.currentTarget).prev().select(); + $(e.currentTarget).prev().focus(); + } else { + if ($(e.currentTarget).val() != "") { + $(e.currentTarget).next().select(); + $(e.currentTarget).next().focus(); + } + } + } + + // update original input box + this.updateOriginalInput(); + + // oncomplete check + if (this.check()) { + this.settings.complete($(this.element).val(), e, this._error); + } + + //onchange event for each input + if (this.settings.change) { + this.settings.change(e.currentTarget, $(e.currentTarget).val(), inputnumber); + } + + + // prevent more input for touch device (we can't limit it) + if (this._isTouchDevice()) { + if (e.keyCode == 8 || e.keyCode == 46) { + // do nothing on backspace and delete + } else { + if ($(this.element).val().length == this.settings.inputs) { + $(e.currentTarget).blur(); + } + } + + } + + }, this)); + } + + + }); + + // A really lightweight plugin wrapper around the constructor, + // preventing against multiple instantiations + $.fn[pluginName] = function (options) { + return this.each(function () { + if (!$.data(this, "plugin_" + pluginName)) { + $.data(this, "plugin_" + pluginName, new Plugin(this, options)); + } + }); + }; + +})(jQuery, window, document); diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..66c1720 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "bootstrap-pincode-input", + "version": "1.6.0", + "lockfileVersion": 1 +} diff --git a/package.json b/package.json index 64eb80b..cc51195 100644 --- a/package.json +++ b/package.json @@ -1,26 +1,27 @@ -{ - "name": "bootstrap-pincode-input", - "version": "1.4.1", - "description": "Bootstrap jQuery widget for x-digit pincode input", - "main": "js/bootstrap-pincode-input.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "repository": { - "type": "git", - "url": "https://github.com/fkranenburg/bootstrap-pincode-input.git" - }, - "keywords": [ - "pincode", - "bootstrap pincode", - "bootstrap pincode input", - "jQuery", - "jquery-plugin" - ], - "author": "Ferry Kranenburg", - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/fkranenburg/bootstrap-pincode-input/issues" - }, - "homepage": "https://github.com/fkranenburg/bootstrap-pincode-input" -} +{ + "name": "bootstrap-pincode-input", + "version": "1.6.0", + "description": "Bootstrap jQuery widget for x-digit pincode input", + "main": "js/bootstrap-pincode-input.js", + "scripts": { + "test": "", + "prebuild": "npm install" + }, + "repository": { + "type": "git", + "url": "https://github.com/fkranenburg/bootstrap-pincode-input.git" + }, + "keywords": [ + "pincode", + "bootstrap pincode", + "bootstrap pincode input", + "jQuery", + "jquery-plugin" + ], + "author": "Ferry Kranenburg", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/fkranenburg/bootstrap-pincode-input/issues" + }, + "homepage": "https://github.com/fkranenburg/bootstrap-pincode-input" +}