I had some difficulties implementing masks at my work (XSS protection seemed to be enabled), so I developed a new workaround, which detects validation patterns and automatically applies masks to the corresponding <input> elements.
First of all, I created a new template and added the following line before closing the <head> element at startpage.pstpl:
Code:
function() { // Easy creation of masks according to the validation regular expression
// New validation function
var validate = function(qid, input, length) {
var v = function(l) {
if (input.value.length == l) {
$('#vmsg_'+qid+'_regex_validation').removeClass('error').addClass('good');
$("#"+input.id).removeClass('error').addClass('good');
return true;
}
else {
$('#vmsg_'+qid+'_regex_validation').removeClass('good').addClass('error');
$("#"+input.id).removeClass('good').addClass('error');
return false;
}
}
if (!isNaN(length)) { // We got a numeric length
v(length);
} else { // We got an array of allowed lengths
for (var i = 0; i<length.length; i++) {
if (v(length[i])) { break; }
}
}
}
// telefone and telefoneOptions come from https://igorescobar.github.io/jQuery-Mask-Plugin/
var telefone = function (val) {
return val.replace(/\D/g, '').length === 11 ? '(00) 00000-0000' : '(00) 0000-00009';
}
var telefoneOptions = {
onKeyPress: function(val, e, field, options) {
field.mask(telefone.apply({}, arguments), options);
}
}
// Our mask-options-regex-length correpondences
var masks = [
["00.000.000/0000-00", {}, "/^[0-9]{2}\\\\.[0-9]{3}\\\\.[0-9]{3}\\\\/[0-9]{4}-[0-9]{2}$/", 18], // CNPJ
["00000-000", {}, "/^[0-9]{5}-[0-9]{3}$/", 9], // CEP
["000.000.000-00", {}, "/^[0-9]{3}.[0-9]{3}.[0-9]{3}-[0-9]{2}$/", 14], // CPF
[telefone, telefoneOptions, "/^\\\\([0-9]{2}\\\\) [0-9]{4,5}-[0-9]{4}$/", [14, 15]], // 8 or 9-digit Brazilian telephone numbers
];
// Form pairs of [qid, regex] for later search
var scripts = $("script")
var regexes = []
for (var i=0; i<scripts.length; i++) {
// We first try to get qid from the line "function LEMval????(sgqa){"
var script = scripts[i].innerHTML;
var currIndex = scripts[i].innerHTML.indexOf("function LEMval");
while (currIndex >= 0) {
script = script.substring(currIndex+15); // Get rid of "function LEMval"
if (!isNaN(script.substring(0,1))) { // We found a qid after "function LEMval"
var valqid = script.substring(0,script.indexOf("("));
// Now we try to get the validation regex, which is delimited by double
// quotes as in LEMregexMatch("/^[0-9]{2}-[0-9]{8,9}$/"
var regex = script.substring(script.indexOf("LEMregexMatch(\"")+15);
regex = regex.substring(0, regex.indexOf("\""));
// If we find it, appendo to regexes list as a pair of [qid, regex]
regexes.push([valqid, regex]);
}
currIndex = script.indexOf("function LEMval"); // Next...
}
}
// Iterate through found questions and create masks
for (var i=0; i<regexes.length; i++) {
var qid = regexes[i][0];
var input = $("#question"+qid+" input")[0];
for (var ii=0; ii<masks.length; ii++) {
if (masks[ii][2] == regexes[i][1]) {
var length = masks[ii][3];
$("#"+ input.id).mask(masks[ii][0], masks[ii][1], masks[ii][2]);
// We now have to manipulate validation functions. We may have a delay on mask update
window["LEMval"+qid] = function (a, b, c) {
return function(sgqa) {
setTimeout(validate(a, b, c), 500);
}
}(qid, input, length); // We must separate from the outer scope
$("#"+ input.id).focusout(window["LEMval"+qid]);
}
}
}
}
This script is ready for some Brazilian masks (ZIP code, phone numbers etc.), but may easily adapted to other masks.
The downside of this solution is that it is very dependent on LimeSurvey code, and version changes might brake it. Works with 2.05+ Build 141229.