Overview

JavaScript can be used to add a mask to an input field in a Dynaform. A mask is a pattern of characters, such as a phone number like (999) 999-9999 or a product code like aa-99a9, that ensures that the user only inputs characters which conform to the pattern. Unlike the validate property, which checks whether the entered text conforms to the pattern after the focus leaves the field, masks work while the user is typing and are better at guiding the user to enter the proper input in the field.

Adding the Masked Input Code

Josh Bush's Masked Input plugin can be used to add masks to Dynaform fields. This code has an MIT license, which allows it to be incorporated into ProcessMaker without problems.

The Masked Input can be incorporated into the Dynaform in three ways:

  • Download the .js file by going to the Josh Bush's page, right-clicking and saving the Minified file.

    A file named jquery.maskedinput.min.js will be downloaded. Place it in the public_html directory in the ProcessMaker server:

    Linux:

    /opt/processmaker/workflow/public_html/jquery.maskedinput.min.js

    Windows:

    <install-directory>\processmaker\workflow\public_html\jquery.maskedinput.min.js

    Then, add the file name jquery.maskedinput.min.js to the Dynaform's external libs property, as shown in the image below:

  • Copy and paste the following code (jquery.maskedinput.min.js's code) into the Dynaform's JavaScript property.

    /*
        jQuery Masked Input Plugin
        Copyright (c) 2007 - 2015 Josh Bush (digitalbush.com)
        Licensed under the MIT license (http://digitalbush.com/projects/masked-input-plugin/#license)
        Version: 1.4.1
    */

    !function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports?require("jquery"):jQuery)}(function(a){var b,c=navigator.userAgent,d=/iphone/i.test(c),e=/chrome/i.test(c),f=/android/i.test(c);a.mask={definitions:{9:"[0-9]",a:"[A-Za-z]","*":"[A-Za-z0-9]"},autoclear:!0,dataName:"rawMaskFn",placeholder:"_"},a.fn.extend({caret:function(a,b){var c;if(0!==this.length&&!this.is(":hidden"))return"number"==typeof a?(b="number"==typeof b?b:a,this.each(function(){this.setSelectionRange?this.setSelectionRange(a,b):this.createTextRange&&(c=this.createTextRange(),c.collapse(!0),c.moveEnd("character",b),c.moveStart("character",a),c.select())})):(this[0].setSelectionRange?(a=this[0].selectionStart,b=this[0].selectionEnd):document.selection&&document.selection.createRange&&(c=document.selection.createRange(),a=0-c.duplicate().moveStart("character",-1e5),b=a+c.text.length),{begin:a,end:b})},unmask:function(){return this.trigger("unmask")},mask:function(c,g){var h,i,j,k,l,m,n,o;if(!c&&this.length>0){h=a(this[0]);var p=h.data(a.mask.dataName);return p?p():void 0}return g=a.extend({autoclear:a.mask.autoclear,placeholder:a.mask.placeholder,completed:null},g),i=a.mask.definitions,j=[],k=n=c.length,l=null,a.each(c.split(""),function(a,b){"?"==b?(n--,k=a):i[b]?(j.push(new RegExp(i[b])),null===l&&(l=j.length-1),k>a&&(m=j.length-1)):j.push(null)}),this.trigger("unmask").each(function(){function h(){if(g.completed){for(var a=l;m>=a;a++)if(j[a]&&C[a]===p(a))return;g.completed.call(B)}}function p(a){return g.placeholder.charAt(a<g.placeholder.length?a:0)}function q(a){for(;++a<n&&!j[a];);return a}function r(a){for(;--a>=0&&!j[a];);return a}function s(a,b){var c,d;if(!(0>a)){for(c=a,d=q(b);n>c;c++)if(j[c]){if(!(n>d&&j[c].test(C[d])))break;C[c]=C[d],C[d]=p(d),d=q(d)}z(),B.caret(Math.max(l,a))}}function t(a){var b,c,d,e;for(b=a,c=p(a);n>b;b++)if(j[b]){if(d=q(b),e=C[b],C[b]=c,!(n>d&&j[d].test(e)))break;c=e}}function u(){var a=B.val(),b=B.caret();if(o&&o.length&&o.length>a.length){for(A(!0);b.begin>0&&!j[b.begin-1];)b.begin--;if(0===b.begin)for(;b.begin<l&&!j[b.begin];)b.begin++;B.caret(b.begin,b.begin)}else{for(A(!0);b.begin<n&&!j[b.begin];)b.begin++;B.caret(b.begin,b.begin)}h()}function v(){A(),B.val()!=E&&B.change()}function w(a){if(!B.prop("readonly")){var b,c,e,f=a.which||a.keyCode;o=B.val(),8===f||46===f||d&&127===f?(b=B.caret(),c=b.begin,e=b.end,e-c===0&&(c=46!==f?r(c):e=q(c-1),e=46===f?q(e):e),y(c,e),s(c,e-1),a.preventDefault()):13===f?v.call(this,a):27===f&&(B.val(E),B.caret(0,A()),a.preventDefault())}}function x(b){if(!B.prop("readonly")){var c,d,e,g=b.which||b.keyCode,i=B.caret();if(!(b.ctrlKey||b.altKey||b.metaKey||32>g)&&g&&13!==g){if(i.end-i.begin!==0&&(y(i.begin,i.end),s(i.begin,i.end-1)),c=q(i.begin-1),n>c&&(d=String.fromCharCode(g),j[c].test(d))){if(t(c),C[c]=d,z(),e=q(c),f){var k=function(){a.proxy(a.fn.caret,B,e)()};setTimeout(k,0)}else B.caret(e);i.begin<=m&&h()}b.preventDefault()}}}function y(a,b){var c;for(c=a;b>c&&n>c;c++)j[c]&&(C[c]=p(c))}function z(){B.val(C.join(""))}function A(a){var b,c,d,e=B.val(),f=-1;for(b=0,d=0;n>b;b++)if(j[b]){for(C[b]=p(b);d++<e.length;)if(c=e.charAt(d-1),j[b].test(c)){C[b]=c,f=b;break}if(d>e.length){y(b+1,n);break}}else C[b]===e.charAt(d)&&d++,k>b&&(f=b);return a?z():k>f+1?g.autoclear||C.join("")===D?(B.val()&&B.val(""),y(0,n)):z():(z(),B.val(B.val().substring(0,f+1))),k?b:l}var B=a(this),C=a.map(c.split(""),function(a,b){return"?"!=a?i[a]?p(b):a:void 0}),D=C.join(""),E=B.val();B.data(a.mask.dataName,function(){return a.map(C,function(a,b){return j[b]&&a!=p(b)?a:null}).join("")}),B.one("unmask",function(){B.off(".mask").removeData(a.mask.dataName)}).on("focus.mask",function(){if(!B.prop("readonly")){clearTimeout(b);var a;E=B.val(),a=A(),b=setTimeout(function(){B.get(0)===document.activeElement&&(z(),a==c.replace("?","").length?B.caret(0,a):B.caret(a))},10)}}).on("blur.mask",v).on("keydown.mask",w).on("keypress.mask",x).on("input.mask paste.mask",function(){B.prop("readonly")||setTimeout(function(){var a=A(!0);B.caret(a),h()},0)}),e&&f&&B.off("input.mask").on("input.mask",u),A()})}})});

    As shown in the image:

  • Add the following URL to the Dynaform's external libs property:
    https://raw.githubusercontent.com/digitalBush/jquery.maskedinput/1.4.1/dist/jquery.maskedinput.min.js

    The code may load more slowly when downloading from an external site.

  • Defining the Fields

    Add JavaScript code to the textbox or textarea field to call the mask() method.

    $("#id").getControl().mask("mask-parameters", {placeholder: "placeholder", completed: function})

    Parameters:

    • id: Unique ID of the control.
    • mask-parameters: The template of the mask, where:
      Parameter Represents Example
      9 Any number (0-9). A US phone number: $("#id").getControl().mask("1(999) 999-9999")
      a Any letter (A-Z,a-z) IATA 3-letter code: $("#id").getControl().mask("aaa")
      * Any letter or number (A-Z,a-z,0-9)
      ? Any characters after ? are optional. An optional extension to a phone number:
      $("#id").getControl().mask("(999) 999-9999? x9999")
      Any other characters are automatically inserted into the field.
      Ex: $("id").getControl().mask("Good evening, aa?aaaaaaaaaaaaaa")
    • Placeholder: (Optional) Object that defines the mask's properties, and has the following format:
      {placeholder: "placeholder"}

      By default, characters to be entered by the user are displayed as "_" (an underscore) when the field has the focus. To use different character(s), define the placeholder. For example, to use a space instead of an underscore:
      $("#id").getControl().mask("IM-99a9", {placeholder: " "})

    • Completed: Defines a custom function that will be executed after the focus leaves the field. For example, to display a message if the text entered in the "productCode" field starts with "C":
      $("#productCode").getControl().mask("a***", {completed: function() {
         if (this.val().substr(0,1) == "C") {
            alert("Remember to only use Acme Co. product codes");
         }
      }});

    It is also possible to define new wildcard characters or redefine existing ones to use in a mask. For example, the following code defines a new wildcard ~, which represents either + (plus sign) or - (minus sign). Then, it uses that wildcard in a mask in the "amount" field:

    $.mask.definitions['~'] = '[+-]';
    $("#amount").getControl().mask("~9.99");

    The mask() function can also be used with text fields inside grids. For example, the following code applies the mask "99-H99" to a grid field with the ID "itemCode", inside a grid whose ID is "orderList":

    var gridId = "itemCode"; //set to ID of grid
    var fieldId = "amount"; //set to ID of text field inside grid

    //set the mask in all existing rows when the Dynaform loads:
    var nRows = $("#"+gridId).getNumberRows()
    for (var i = 1; i <= nRows; i++) {
        $("[id='form["+gridId+"]["+i+"]["+fieldId+"]']").mask("99-H99");
    }

    //set the mask in newly added rows:
    $("#"+gridId).onAddRow(function(aNewRow, oGrid, rowIndex) {
        $("[id='form["+gridId+"]["+rowIndex+"]["+fieldId+"]']").mask("99-H99");
    });

    Numbers with Thousands Separators

    Normandes Junior provides a jQuery mask for numbers with two decimal digits and integers that need to automatically insert a thousands separator.

    To use this mask in a Dynaform, first download the file by clicking here. Then, save the file in the public_html folder of your ProcessMaker server:

    Linux:

    /opt/processmaker/workflow/public_html/jquery.maskedinput.min.js

    Windows:

    <install-directory>\processmaker\workflow\public_html\jquery.maskedinput.min.js

    Place the file name in the Dynaform's External Libs property, as shown in the image below:

    Then, add JavaScript code to the Javascript property of the Dynaform to configure the textbox or textarea that will use the imported number mask library. Some examples can be found in the table below:

    Examples
    Description Code
    For an English-style decimal number such as 1.99, 12,288.07 or 182,837,627,897.54, which uses a , (comma) as the thousands separator and a . (dot) as the decimal point: $("#id").getControl().maskNumber()
    $("#invoiceAmount").getControl().maskNumber();
    For an English-style integer such as 13, 12,288 or 182,837,627,897, which uses a , (comma) as the thousands separator: $("#id").getControl().maskNumber({integer: true})
    $("#invoiceAmount").getControl().maskNumber({integer: true});
    For an European-style number such as 1,99, 12.288,07 or 182.837.627.897,54, which uses a . (dot) as the thousands separator and a , (comma) as the decimal point, use the code: $("#id").getControl().maskNumber({decimal: ',', thousands: '.'})
    $("#invoiceAmount").getControl().maskNumber({decimal: ',', thousands: '.'});
    For an European-style integer such as 13, 12.288 or 182.837.627.897, which uses a . (dot) as the thousands separator, use the code: $("#id").getControl().maskNumber({integer: true, thousands: '.'})
    $("#invoiceAmount").getControl().maskNumber({integer: true, thousands: '.'});

    The maskNumber() function can also be used with text fields inside grids. For example, the following code applies a European style number mask to a grid field with the ID "amount" inside a grid whose ID is "orderList":

    var gridId = "orderList"; //set to ID of grid
    var fieldId = "amount"; //set to ID of text field inside grid

    //set the thousands separator in all existing rows when the Dynaform loads:
    var nRows = $("#"+gridId).getNumberRows()
    for (var i = 1; i <= nRows; i++) {
        $("[id='form["+gridId+"]["+i+"]["+fieldId+"]']").maskNumber({decimal: ',', thousands: '.'});
    }

    //set the thousands separator in newly added rows:
    $("#"+gridId).onAddRow(function(aNewRow, oGrid, rowIndex) {
        $("[id='form["+gridId+"]["+rowIndex+"]["+fieldId+"]']").maskNumber({decimal: ',', thousands: '.'});
    });