/* Modernizr 2.7.1 (Custom Build) | MIT & BSD
* Build: http://modernizr.com/download/#-shiv-teststyles-prefixes-load
*
* Included here to avoid multiple loads.
* Tests for: touch
*/
;window.Modernizr=function(a,b,c){function w(a){j.cssText=a}function x(a,b){return w(m.join(a+";")+(b||""))}function y(a,b){return typeof a===b}function z(a,b){return!!~(""+a).indexOf(b)}function A(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:y(f,"function")?f.bind(d||b):f}return!1}var d="2.7.1",e={},f=!0,g=b.documentElement,h="modernizr",i=b.createElement(h),j=i.style,k,l={}.toString,m=" -webkit- -moz- -o- -ms- ".split(" "),n={},o={},p={},q=[],r=q.slice,s,t=function(a,c,d,e){var f,i,j,k,l=b.createElement("div"),m=b.body,n=m||b.createElement("body");if(parseInt(d,10))while(d--)j=b.createElement("div"),j.id=e?e[d]:h+(d+1),l.appendChild(j);return f=["",'"].join(""),l.id=h,(m?l:n).innerHTML+=f,n.appendChild(l),m||(n.style.background="",n.style.overflow="hidden",k=g.style.overflow,g.style.overflow="hidden",g.appendChild(n)),i=c(l,a),m?l.parentNode.removeChild(l):(n.parentNode.removeChild(n),g.style.overflow=k),!!i},u={}.hasOwnProperty,v;!y(u,"undefined")&&!y(u.call,"undefined")?v=function(a,b){return u.call(a,b)}:v=function(a,b){return b in a&&y(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=r.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(r.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(r.call(arguments)))};return e}),n.touch=function(){var c;return"ontouchstart"in a||a.DocumentTouch&&b instanceof DocumentTouch?c=!0:t(["@media (",m.join("touch-enabled),("),h,")","{#modernizr{top:9px;position:absolute}}"].join(""),function(a){c=a.offsetTop===9}),c};for(var B in n)v(n,B)&&(s=B.toLowerCase(),e[s]=n[B](),q.push((e[s]?"":"no-")+s));return e.addTest=function(a,b){if(typeof a=="object")for(var d in a)v(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,typeof f!="undefined"&&f&&(g.className+=" "+(b?"":"no-")+a),e[a]=b}return e},w(""),i=k=null,function(a,b){function l(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function m(){var a=s.elements;return typeof a=="string"?a.split(" "):a}function n(a){var b=j[a[h]];return b||(b={},i++,a[h]=i,j[i]=b),b}function o(a,c,d){c||(c=b);if(k)return c.createElement(a);d||(d=n(c));var g;return d.cache[a]?g=d.cache[a].cloneNode():f.test(a)?g=(d.cache[a]=d.createElem(a)).cloneNode():g=d.createElem(a),g.canHaveChildren&&!e.test(a)&&!g.tagUrn?d.frag.appendChild(g):g}function p(a,c){a||(a=b);if(k)return a.createDocumentFragment();c=c||n(a);var d=c.frag.cloneNode(),e=0,f=m(),g=f.length;for(;e",g="hidden"in a,k=a.childNodes.length==1||function(){b.createElement("a");var a=b.createDocumentFragment();return typeof a.cloneNode=="undefined"||typeof a.createDocumentFragment=="undefined"||typeof a.createElement=="undefined"}()}catch(c){g=!0,k=!0}})();var s={elements:d.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output progress section summary template time video",version:c,shivCSS:d.shivCSS!==!1,supportsUnknownElements:k,shivMethods:d.shivMethods!==!1,type:"default",shivDocument:r,createElement:o,createDocumentFragment:p};a.html5=s,r(b)}(this,b),e._version=d,e._prefixes=m,e.testStyles=t,g.className=g.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(f?" js "+q.join(" "):""),e}(this,this.document),function(a,b,c){function d(a){return"[object Function]"==o.call(a)}function e(a){return"string"==typeof a}function f(){}function g(a){return!a||"loaded"==a||"complete"==a||"uninitialized"==a}function h(){var a=p.shift();q=1,a?a.t?m(function(){("c"==a.t?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){"img"!=a&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l=b.createElement(a),o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};1===y[c]&&(r=1,y[c]=[]),"object"==a?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),"img"!=a&&(r||2===y[c]?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i("c"==b?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),1==p.length&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&"[object Opera]"==o.call(a.opera),l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return"[object Array]"==o.call(a)},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f 0) ? window.innerWidth : screen.width;
var scrHeight = (window.innerHeight > 0) ? window.innerHeight : screen.height;
window.onunload = function(){
// Firefox workaround
$.ObjectPlanet.alreadySubmitted = false;
};
function initJQuery() {
//if the jQuery object isn't available
if (typeof(jQuery) == 'undefined') {
if (typeof $ == "undefined") {
//only output the script once..
addScript("include/jquery/js/jquery-3.5.1.min.js");
//$.ObjectPlanet.jQueryScriptOutputted = true;
}
setTimeout("initJQuery()", 50);
} else {
// JQuery ready function, executed at HTML-ready
$(function() {
setDeviceProperties()
var styleMobile = $.ObjectPlanet.device.handheld && paramOrFieldEmpty("action");
if (styleMobile) {
// adapt to mobile if device has touch support and not in preview mode
adaptToMobile();
} else {
adaptToDeskTop();
}
if (!styleMobile || document.URL.indexOf("action") != -1) $("#viewport").remove();
$("#op_loading").hide();
$("#op_all").css("opacity","1.0");
// position buttons in case content has pushed then to the right.
if (styleMobile) {
var $btns = $(".buttons");
var bPad = $btns.outerWidth() - scrWidth; bPad = bPad < 0 ? 0 : bPad;
if (0 < bPad) $btns.css("padding-right",bPad + "");
}
// scroll down to first validation error
var $validationErr = $(".validationError:first");
if (0 < $validationErr.length) {
$('html, body').animate({
scrollTop: $validationErr.offset().top
}, 1000);
}
// for each question
$(".questionInput").each(function() {
///////////////////////////////////////////////
// Find matrix questions, and rotate cell
// groups (those that are marked for rotation)
///////////////////////////////////////////////
// create a clone of the matrix question
var $matrix = $(".matrix", this);
if ($matrix.length == 0) {
return;
}
var $clonedMatrix = $matrix.clone(true);
// go through the groups in the matrix question until no groups left
var g = 0;
while (true) {
// get row lists of the original and cloned matrices
var $groupTrList = $("tr:has(.group" + g + ")", this);
if ($groupTrList.length == 0) {
break;
}
// if rotation is off for the group - go to the next one
if ($groupTrList.eq(0).children().filter(".rotationOn").length == 0) {
g++;
continue;
}
// get list of the group tr's for the clone
var $clonedGroupTrList = $("tr:has(.group" + g +")", $clonedMatrix);
// create an array with random indices
var rowSize = $groupTrList.length;
var indices = new Array();
var randomIndices = new Array();
for (i=0;i 31 && (charCode < 48 || charCode > 57)) ? false : true;
return ((charCode >= 48 && charCode <= 57) || (charCode >= 96 && charCode <= 105));
}
// make sure numeric fields only accept numeric input
$(".matrixDec:not('.readonly')").bind("keydown keyup",function (e) {
var $el = $(e.target), caretPos = getCaretPosition($el.get(0));
if (isEditKey(e)) return;
var isNum = isNumberKey(e), isCommaOrDot = e.which == 190 || e.which == 188 || e.which == 110, val = $el.val(), isDash = e.which == 189 || e.which == 173;
//debug("
" + e.type + ", isNum:" + isNum + ", isCommaOrDot:" + isCommaOrDot + ", isDash:" + isDash + ", caretPos:" + caretPos);
if ( (!isNum && !isCommaOrDot && !isDash) ||
(isCommaOrDot && 0 <= val.indexOf(".") && !isNum && !isDash) ||
(((isDash && 0 < val.indexOf("-")) || (isDash && 0 < caretPos)) && !isCommaOrDot && !isNum)) {
e.preventDefault();
}
$el.val($el.val().replace(/[,]/g,'.'));
setCaretPosition($el.get(0), caretPos);
});
$(".matrixInt:not('.readonly')").bind("keydown keyup",function (e) {
var $el = $(this), caretPos = getCaretPosition($el.get(0));
var isNum = isNumberKey(e), isCommaOrDot = e.which == 190 || e.which == 188 || e.which == 110, val = $el.val(), isDash = e.which == 189 || e.which == 173;
if (isEditKey(e)) return;
//$el.val($el.val().replace(/[^\d\-].+/, ""));
if ((!isNum && !isDash) || (((isDash && 0 < val.indexOf("-")) || (isDash && 0 < caretPos)) && !isNum)) {
e.preventDefault();
}
});
// call only when survey is a panelist survey
if (document.URL.indexOf("panelPortal.do") != -1 || document.URL.indexOf("panelist.do") != -1) {
panelistAttributesOnload();
}
// filter checkboxes based on questions from previous pages
handleChoiceFiltering();
// bind multiple option filter method
$("input.multipleButton").bind('change', function(e) {
$.ObjectPlanet.choiceJustClicked = getChoiceUniqueName($(e.target));
handleChoiceFiltering()
});
// make sure the hidden jquery UI helper exists. Could be gone if template file is used.
if (!$("#hidden-ui-helper").length) {
$("head").append("");
}
});
}
}
/**
* Checks for IE and its version
*
* For example:
* if (isIE () && isIE () < 9) { ... }
*/
function isIE () {
var nav = navigator.userAgent.toLowerCase();
return (nav.indexOf('msie') != -1) ? parseInt(nav.split('msie')[1]) : false;
}
function setDeviceProperties() {
// check if the survey is displayed on iOS
var invokedDevice = getParamOrFieldValue("dt"); // device type from url param
$.ObjectPlanet.device = {};
$.ObjectPlanet.device.touch = Modernizr.touch;
$.ObjectPlanet.device.tablet = (navigator.userAgent.match(/(tablet|Tablet|iPad|Kindle|Silk|Nexus 7|Nexus 10)/g) && $.ObjectPlanet.device.touch ? true : false);
$.ObjectPlanet.device.handheld = ($.browser.mobile || $.ObjectPlanet.device.tablet) && $.ObjectPlanet.device.touch;
$.ObjectPlanet.device.iPhone = (navigator.userAgent.match(/(iPhone)/g) ? true : false);
$.ObjectPlanet.device.iPad = (navigator.userAgent.match(/(iPad)/g) ? true : false);
$.ObjectPlanet.device.android = (navigator.userAgent.match(/(Android)/g) ? true : false);
$.ObjectPlanet.device.screenHeight = window.screen.availHeight ? window.screen.availHeight : $(window).width();
$.ObjectPlanet.device.screenWidth = window.screen.availWidth ? window.screen.availWidth : $(window).width();
$.ObjectPlanet.device.devicePixelRatio = window.devicePixelRatio ? window.devicePixelRatio : 1;
$.ObjectPlanet.device.handheld = $.ObjectPlanet.device.handheld || ($.ObjectPlanet.device.android && $.ObjectPlanet.device.touch);
// override with invoked values
if (invokedDevice == "tablet") {
$.ObjectPlanet.device.tablet = true;
$.ObjectPlanet.device.handheld = true;
} else if (invokedDevice == "desktop") {
$.ObjectPlanet.device.tablet = false;
$.ObjectPlanet.device.handheld = false;
} else if (invokedDevice == "mobile") {
$.ObjectPlanet.device.tablet = false;
$.ObjectPlanet.device.handheld = true;
}
}
/**
* Handles option filtering based on the option being clicked
*/
function handleChoiceFiltering(event) {
hideFilteredOptions = typeof hideFilteredOptions === 'undefined' ? "disable" : hideFilteredOptions;
hideChoicesInitially(event);
// start over by enabling all options for the current question and all following questions. If type is include,
// hide all choices affected by filters
$("input[name*=multiple]").each(function() {
if (hideFilteredOptions == "hide") {
$(this).closest("table.multipleChoice").show();
} else {
if (hideFilteredOptions == "include") {
// Hide all choices affected by filters, so they can be included later
} else {
// type is "disable"; enable all disabled choices
$(this).removeAttr("disabled").parent().next().find(".multipleText").css('opacity','1');
}
}
});
// apply filter for the choices that has been clicked in the previous pages
if (typeof checkedOptStr !== 'undefined') {
var checkedOptArr = checkedOptStr.split(" ");
for (var i = 0; i < checkedOptArr.length; i++) {
applyFilterOptions(checkedOptArr[i], multChoiceFilterData.data, true);
}
}
// apply filter for the choice that was clicked just now
if (typeof event !== 'undefined' && event !== null) {
var name = $(event.target).attr("name");
// if (name.indexOf("_") < 0) {
// name = name + "_" + $(event.target).attr("value");
// }
// if ($("input[name=" + name + "]").is(':checked')) {
if ($(event.target).is(':checked')) {
applyFilterOptions(name, multChoiceFilterData.data, true);
}
}
// apply filter for the other choices that are selected in this page
$("input[name*=multiple]:checked").each(function(j) {
name = $(this).attr("name");
if (name.indexOf("_") < 0) {
name = name + "_" + $(this).attr("value");
}
if (typeof multChoiceFilterData !== 'undefined') {
applyFilterOptions(name, multChoiceFilterData.data, true);
}
});
}
/**
* Hides choices that are to be included later when filter mode is "include"
*/
function hideChoicesInitially(e) {
if (hideFilteredOptions != "include") return;
var filterData = multChoiceFilterData.data;
// get question # that was clicked, if none use 0
var clickedQNo = e ? $(e.target).closest(".questionTbl").attr("id").split("Tbl")[1] : 0;
clickedQNo = ($.ObjectPlanet.choiceJustClicked && clickedQNo == 0) ? $.ObjectPlanet.choiceJustClicked.substr(1).split("multiple")[0] : 0;
// for all questions
for (var i = 0; i < filterData.length; i++) {
var filt = filterData[i].filt;
// no need to hide questions before the question that was selected on
if (filterData[i].q < clickedQNo) {
continue;
}
// for all filters for a question
for (var j = 0; j < filt.length; j++) {
var refq = filt[j].refq;
var opts = filt[j].opts;
// for all choices within a question
for (var k = 0; k < opts.length; k++) {
var refopts = opts[k].refopts;
// all choices in target question affected by filter
for (var m = 0; m < refopts.length; m++) {
var str = "input[name=q" + refq + "multiple_" + refopts[m] + "]";
var str2 = "input[name=q" + refq + "multiple][value=" + refopts[m] + "]";
// multiple selection (checkbox)
var $check = $(str);
// single selection (radio button)
var $radio = $(str2);
var $el = $check.length ? $check : $radio;
if ($el.closest(".multiple").hasClass("multi-column")) {
$el.closest("table.multipleChoice").hide();
} else {
$el.closest("table").closest("tr").hide();
}
if (getChoiceUniqueName($el) != $.ObjectPlanet.choiceJustClicked) {
$el.prop("checked", false);
}
}
}
}
}
}
/**
* filters options based on the given option and the filter array
*/
function applyFilterOptions(name, filterData, checked) {
var index1 = name.indexOf("_");
var index2 = name.indexOf("multiple");
if (index1 < 0 || index2 < 0) {
return;
}
var qName = name.substring(0, index1+1);
var qNo = name.substring(1, index2);
var optNo = name.substring(index1+1);
for (var i = 0; i < filterData.length; i++) {
if (filterData[i].q == qNo) {
var filt = filterData[i].filt;
for (var j = 0; j < filt.length; j++) {
var refq = filt[j].refq;
var opts = filt[j].opts;
for (var k = 0; k < opts.length; k++) {
if (opts[k].myopt == optNo) {
var refopts = opts[k].refopts;
for (var m = 0; m < refopts.length; m++) {
var str = "input[name=q" + refq + "multiple_" + refopts[m] + "]";
var str2 = "input[name=q" + refq + "multiple][value=" + refopts[m] + "]";
if (hideFilteredOptions == "hide") {
// multiple selection
if (checked) {
$(str).prop("checked",false).closest("table.multipleChoice").hide();
} else {
$(str).closest("table.multipleChoice").show();
}
// single selection
if (qNo != refq) {
if (checked) {
$(str2).prop("checked",false).closest("table.multipleChoice").hide();
} else {
$(str2).closest("table.multipleChoice").show();
}
}
} else if (hideFilteredOptions == "disable") {
// multiple selection
if (checked) {
$(str).attr("disabled", true).prop("checked",false).parent().next().find(".multipleText").css('opacity','0.5');
} else {
$(str).removeAttr("disabled").parent().next().find(".multipleText").css('opacity','1');
}
// single selection
if (qNo != refq) {
if (checked) {
$(str2).attr("disabled", true).prop("checked",false).parent().next().find(".multipleText").css('opacity','0.5');
} else {
$(str2).removeAttr("disabled").parent().next().find(".multipleText").css('opacity','1');
}
}
} else {
var isMultiColumn = $(str).closest(".multiple").hasClass("multi-column");
var $btn = $(str);
var $btn2 = $(str2);
// filter type is "include"
// multiple selection
if (checked) {
$btn.closest("table.multipleChoice").show();
} else {
$btn.prop("checked",false).closest("table.multipleChoice").hide();
}
// single selection
if (qNo != refq) {
if (checked) {
$btn2.closest("table.multipleChoice").show();
} else {
$btn2.prop("checked",false).closest("table.multipleChoice").hide();
}
}
}
}
}
}
}
}
}
}
function adaptToMobile() {
var isTablet = $.ObjectPlanet.device.tablet;
var FLD_HEIGHT = 28, FLD_WIDTH = 70;
var $sections = $("table.sections");
var $btns = $(".buttons");
var $hdr = $(isTablet ? "#tabletHeader" : "#mobileHeader"), $fotr = $("#footer"),hdrHeight = ($hdr.outerHeight() ? $hdr.outerHeight() : 0), fotrHeight = ($fotr.outerHeight() ? $fotr.outerHeight() : 0);
var hdrFotrHeight = hdrHeight + fotrHeight;
$("body").css("font-size","20px").css("margin","0px").css("padding","0px").css("width","auto").css("background-color","#fff").css("background-image","none")
.addClass(isTablet ? "tablet":"").addClass(!isTablet && $.ObjectPlanet.device.handheld ? "mobile":"").addClass($.ObjectPlanet.device.handheld ? "handheld":"")
.closest("html");
$hdr.css("width","100%").attr("width","").show();
$fotr.show();
if (!isTablet) {
$hdr.find("td.header").css("padding","5px 35px");
}
$("#page-div").css("box-sizing","border-box").css("width","100%").css("padding",(isTablet ? "10" : "0") + "px").css("box-shadow","none").css("border-radius","0px").css("border","0px");
$(".page").attr("width","").css("width","100%").find("> tbody > tr > td.sections").css("padding",(isTablet ? "20" : "5") + "px").css("font-size",(isTablet ? "16" : "16") + "px");
$sections.parent().css("padding-top", "0px");
$(".topLeftCorner").removeClass("topLeftCorner");
$(".topRightCorner").removeClass("topRightCorner");
$(".bottomLeftCorner").removeClass("bottomLeftCorner");
$(".bottomRightCorner").removeClass("bottomRightCorner");
$(".leftSide").removeClass("leftSide");
$(".rightSide").removeClass("rightSide");
// need to add sections-class to title, to get the same bg
$("h1.title").css("background-image","none").css("font-size", (isTablet ? "1.8" : "1.4") + "em").css("padding-left",(isTablet ? "25" : "8") + "px")
.css("padding-top", (isTablet ? "5" : "10") + "px").css("padding-bottom", "5px")
.each(function(){
var bg = getBg($sections);
if (bg.img) { $(this).css("background-image", bg.img); }
if (bg.img) { $(this).css("background-color", bg.col); }
})
.closest("td.title").css("background-image","none");
$(".introduction").css("font-size", (isTablet ? "1.3" : "1.2") + "em").css("padding", (isTablet ? "10" : "5") +"px").css("padding-bottom", (isTablet ? "40" : "30") + "px").css("padding-top", (isTablet ? "40" : "30") + "px");
var $sectionTitle = $("td.sectionTitle");
$sectionTitleColor = $sectionTitle.css('color');
$sectionTitle.css('cssText','font-size:'+(isTablet ? "1.5" : "1.4") + 'em !important').css("padding", (isTablet ? "5px 10px" : "5px 5px")).css('color', $sectionTitleColor);
$(".sectionText").css("font-size",(isTablet ? "1.4" : "1.2") + "em").css("padding",(isTablet ? "10" : "5") + "px");
var styleButton = function($el, fontSize, padMob, padTablet){
$el.css("-webkit-appearance", "none");
padMob = padMob ? padMob : "10";
padTablet = padTablet ? padTablet : "10";
var fSize = (fontSize ? fontSize : 1.1);
setRoundedBorder($el.css("padding",(isTablet ? padTablet : padMob) + "px").css("font-size",fontSize + "em"), 5, "rgba(200,200,200,0.7)");
}
var styleField = function($el, attr) {
var def = { wMob: 70, hMob: 28, wTablet: 100, hTablet: 30, border: "1px #ccc solid", prefix: "px", fontSize: "1.0em" }
$.extend(def,attr);
$el.css("width",(isTablet ? def.wTablet : def.wMob) + "px").css("height",(isTablet ? def.hTablet : def.hMob) + def.prefix).css("font-size",def.fontSize);
if (def.border != "") {
$el.css("border",def.border);
}
}
var $questionTDs = $("td.question");
var questionsExist = 0 < $questionTDs.length;
if (!questionsExist) {
$("form").css("margin","0px");
$(".login").css("font-size",(isTablet ? "1.4" : "1.3") + "em").css("padding","10px");
var $thank = $(".thankYouNote");
if (0 < $thank.length) {
var h = $("table.page").outerHeight() - $btns.outerHeight();
if (!$btns.find("input").length) {
$btns.hide();
}
$btns.closest("tr").prev().find("td.sections").css("padding-bottom",scrHeight - h - hdrFotrHeight - $btns.height());
}
// login w/password
var $pw = $("input[type=password]");
if ($pw.length) {
var $plLogin = $pw.closest("tr").parent().find("input[name=plugin_loginName]");
$pw.add($plLogin).each(function(){ styleField($(this),{ wMob: FLD_WIDTH, hMob: FLD_HEIGHT, wTablet: "200", hTablet: FLD_HEIGHT+2, fontSize: "0.9em"}) });
$pw.parent().find("input[type=submit]").each(function(){ styleButton($(this), 1.0, "7", "10"); });
$pw.closest("tr").find("td[align=right]").css("text-align","right").parent().prev().css("height","50px");
var h = $("table.page").outerHeight() - $btns.outerHeight()
$btns.hide().closest("tr").prev().find("td.sections").css("padding-bottom",scrHeight - h - hdrFotrHeight);
}
// invitation login
var $inviteeId = $("td.login input[type=text][name=i]");
if (0 < $inviteeId.length) {
$inviteeId.parent().attr("width",(isTablet ? "88" : "70") + "%").prev().attr("width",(isTablet ? "12" : "30") + "%");
var $inviteeKey = $("td.login input[type=text][name=k]");
$inviteeId.add($inviteeKey).css("height",(isTablet ? "32" : "30") + "px").css("width",(isTablet ? "150" : "70") + "px").css("font-size",(isTablet ? "1.0" : "1.0") + "em");
styleButton($inviteeKey.parent().find("input[type=submit]"), 1.0, "7", "10");
var h = $("table.page").outerHeight() - $btns.outerHeight()
$btns.hide().closest("tr").prev().find("td.sections").css("padding-bottom",scrHeight - h - hdrFotrHeight); }
// save screen
var $saveBack = $(".saveAndComeBack");
if (0 < $saveBack.length) {
$saveBack.css("font-size",(isTablet ? "1.4" : "1.0") + "em");
$("#email").css("font-size","1.1em").closest("td.sections").css("padding", (isTablet ? "20px" : "5px")).css("padding-bottom","0px");
styleField($("#email"),{ wMob: FLD_WIDTH+30, hMob: FLD_HEIGHT+6, wTablet: "180", hTablet: FLD_HEIGHT+2, fontSize: "0.9em"});
if (!isTablet) $("input[name=cancelbutton]").after("
").before("
").css("margin-top","30px");
var $buttons = $("#sendbutton, input[name=cancelbutton]").addClass("button");
styleButton($buttons, (isTablet ? 0.8 : 0.85), "7", "10");
var h = $("table.page").outerHeight() - $btns.outerHeight()
$btns.hide().closest("tr").prev().find("td.sections").css("padding-bottom",scrHeight - h - hdrFotrHeight -5);
}
// if dialog (message), fill screen
var $dialog = $("td.dialog font").css("font-size", (isTablet ? "1.3" : "1.1") + "em").parent().css("height",(scrHeight - 157 - hdrFotrHeight) + "px");
if (0 < $dialog.length) {
var h = $("table.page").outerHeight() - $btns.outerHeight();
$btns.hide().closest("tr").prev().find("td.sections").css("padding-bottom",scrHeight - h - hdrFotrHeight);
}
// image upload
var $uploadPage = $("table.uploadPage");
if (0 < $uploadPage.length) {
$uploadPage.attr("width","").css("width","100%");
var $file = $uploadPage.find(".uploadField[name=file]");
$file.parent().css("width","70%");
styleButton($file.width((isTablet ? 250 : 170)), (isTablet ? 0.8 : 0.85), "7", "10");
styleField($uploadPage.find(".uploadField[name=newName]"),{ wMob: "170", hMob: FLD_HEIGHT, wTablet: "250", hTablet: FLD_HEIGHT+2, fontSize: "0.9em"});
styleButton($uploadPage.find(".uploadButtons input"), (isTablet ? 0.8 : 0.85), "7", "10");
}
var $boxicon = $(".boxicon");
if (0 < $boxicon.length) {
// general error, format message box
var title = $boxicon.closest("tr").find(".boxTitle").text();
var msg = $boxicon.closest("table").find(".dialogBox").text();
$("body").children().hide();
$( "" + title + "
" +
"" + msg + "
"
).appendTo("body");
}
} else {
// process questions
$(".essayText").each(function(){ styleField($(this),{ wMob: FLD_WIDTH, hMob: FLD_HEIGHT, wTablet: "200", hTablet: FLD_HEIGHT+2, fontSize: "0.95em"}) });
$("table.numeric").css("margin","0px").find(".numericInput").css("height","28px").css("width","100px").css("font-size","1.05em");
$("textarea.questionFreeText, input.questionFreeText").attr("cols", "").css("width","100%").css("max-width",(scrWidth-(isTablet ? 30 : 12)) + "px");
$("td.questionFreeText").css("padding","3px");
$(".questionText select, table.dropdown select").each(function(){ if (isTablet) {$(this).css("max-width","200px")} else {$(this).css("max-width","100px")}}).css("margin-left","0px").css("font-size","1.0em").css("height","30px").css("margin","3px").closest("table.dropdown").css("margin-left","0px");
// move question numbers to question text
$(".questionNo").each(function() {
var txt = $(this).text();
$(this).empty().next().prepend(txt).css("width","100%").attr("width","");
});
$(".questionText").css("font-size", (isTablet ? "1.5" : "1.3") + "em").css("padding",(isTablet ? "10" : "5") + "px");
// remove question number column, if question numbers are enabled
var $questionTbl = $(".questionTbl");
if ($questionTbl.eq(0).find(".questionNo").length > 0) {
$questionTbl.css("width","100%").parent().find(".questionTbl > tbody > tr > td:first-child:not([colspan])").remove();
}
var buttonify = function(el, padding, selected, paddingVertical){
var paddingVert = (paddingVertical ? paddingVertical : padding);
setRoundedBorder(el, 4, "rgba(200,200,200,0.7)");
$(el).css("padding",padding + "px").css("padding-top",paddingVert).css("padding-bottom",paddingVert)
.css("background-color", (selected ? "rgba(200,200,200,0.75)":"rgba(255,255,255,0.3)"))
.css("font-weight", (selected ? "bold" : "normal")).css("cursor", "pointer");
};
// multiple
var $multipleTbl = $("table.multiple");
if ($multipleTbl.length) {
$multipleTbl.css("width","100%").css("border-spacing",(isTablet ? 10 : 5)+"px").css("border-collapse","separate")
.find("> tbody > tr > td").css("background-color", "rgba(255,255,255,0.3)").css("padding","10px")
.each(function(){ buttonify(this, (isTablet ? 18 : 5), false, (isTablet ? 15 : 10)); })
.addClass("handheld")
.click( function(e){
if ($(e.target).is(":input")) return;
var $el = $(e.target).closest("table.multipleChoice");
if (!$el.length) $el = $(e.target);
var $but = $el.find(":checkbox,:radio");
$but.prop('checked', !$but.prop('checked'));
// remember which radio/checkbox was just clicked
$.ObjectPlanet.choiceJustClicked = getChoiceUniqueName($but);
handleChoiceFiltering();
} ) //.find("input").click(function(e){ e.stopPropagation() }).end()
.find(".multipleText").each(function(){ $(this).html($(this).html().replace(/ $/g,"")); })
.css("font-size",(isTablet ? "1.5" : "1.2") + "em").end()
.find(".multipleOther").each(function(){ styleField($(this),{ wMob: FLD_WIDTH, hMob: FLD_HEIGHT, wTablet: "200", hTablet: FLD_HEIGHT+2, fontSize: "0.9em"}) })
.keyup(function(e){
// if keyup is NOT tab (now entering values)
$(e.target).closest("table.multipleChoice").find(":checkbox, :radio").prop('checked', true);
$.ObjectPlanet.choiceJustClicked = getChoiceUniqueName($(e.target));
handleChoiceFiltering();
})
.end().end().find(".multipleButton").css("vertical-align","middle").find(":radio,:checkbox").css("width","1.25em").css("height","1.25em");
}
// matrix
var $matrixTbl = $("table.matrix").css("margin", "0px");
if (0 < $matrixTbl.length) {
$matrixTbl.find(".matrixCell").css("font-size", "1.2em").css("min-width", "20px").css("padding", (isTablet ? "8" : "5") + "px")
.click(function(){
$(this).find(":radio,:checkbox").click();
checkRankingGroup(this, true);
}).find(":radio,:checkbox").click(function(e){ e.stopPropagation() }).end()
.find("input[type=text]").css("height","28px").each(function(){
if (!isTablet) { $(this).css("max-width","70px"); }
}).end()
.find("select").css("height","28px").each(function(){
$(this).css("max-width",(isTablet ? "200" : "70") + "px");
})
.css("font-size","1.05em");
}
// rating
var $ratingTbl = $("table.rating");
if (0 < $ratingTbl.length) {
$ratingTbl.find(".rating td").css("font-size", (isTablet ? "1.4" : "1.2") + "em");
$ratingTbl.each(function(){
//var cnt = $(this).find(".ratingNumbers").length;
var pad = (isTablet ? 17 : 9);
var vPad = (isTablet ? 17 : 10);
var $minMax = $(this).css("margin","0px 0px 0px 10px").find(".ratingMinMax");
// move min/max texts
var txt = $minMax.map(function() { return $(this).text()}).get().join(" - ");
$(this).parents(".questionTbl").find(".questionText").append("" + txt + "
");
$minMax.empty();
// make value labels clickable
$(this).find("td.ratingNumbers, td.ratingNA")
.click(function(e){
var i = $(e.target).closest('td').index(), na = $(e.target).parent().hasClass("ratingNA");
var $input;
// reset buttons
$(e.target).closest("table.rating").find("td.ratingNumbers, td.ratingNA div").each(function(){ buttonify(this,pad,false,vPad) })
buttonify($(e.target),pad,true,vPad);
if (na) { $input = $(e.target).closest(".questionInput").find("td.ratingRadio:last").find("input");
} else { $input = $(e.target).closest(".questionInput").find("td.ratingRadio").eq(i).find("input"); }
$input.click();
})
.not(".ratingNA")
.each(function(){ buttonify(this,pad,false,vPad); })
.end().filter(".ratingNA").wrapInner("").find("div").each(function(){ buttonify(this,pad,false,vPad); });
// set the button selected if radio button is checked
var $radios = $(this).find("input"), checkedIndex = -1;
$radios.each(function(i) { if ($(this).is(":checked")) checkedIndex = i; });
if (-1 < checkedIndex) $(this).find("td.ratingNumbers, td.ratingNA div").eq(checkedIndex).each(function(){ buttonify(this,pad,true,vPad); });
// hide radios
$(this).find("> tbody > tr").eq(1).hide();
$(this).find(".ratingEmpty:last").next().css("width","8px")
});
}
// dropdown
var $dropdownTbl = $("table.dropdown");
if (0 < $dropdownTbl.length) {
var $select = $dropdownTbl.find("select");
$select.css("max-width",(scrWidth-20)+"px").css("padding","3px").css("height","32px").css("font-size","1.2em");;
}
} // done processing questions
$btns.css("background-image", "none").css("padding",(isTablet ? "20px" : "5px 5px 5px 7px") + "px");
styleButton($(".button"), 1.0);
$btns.css("padding",(isTablet ? "20px 20px 20px 20px" : "5px 5px 5px 7px")).find("input").css("margin-left", (isTablet ? "10px":"4px"));
$("table.progressBar").css("height","20px").find("table").attr("cellspacing","1").css("height","100%");
$fotr.attr("width","").css("width","100%").css("padding","0px").css("margin","0px").find("td").css("padding","5px");
}
function adaptToDeskTop() {
$("body").addClass("desktop");
$("#header, #footer").show();
var $multipleTbl = $("table.multiple").addClass("desktop");
$multipleTbl.find("table.multipleChoice").click(function(e){
if ($(e.target).is("input")) return;
var $but = $(e.target).closest("table.multipleChoice").find(":checkbox, :radio");
$.ObjectPlanet.choiceJustClicked = getChoiceUniqueName($but);
$but.prop('checked', !$but.prop('checked'));
handleChoiceFiltering();
}).find(".multipleOther").keyup(function(e){
var code = e.keyCode || e.which;
// do not select the choice if the key was tab, only if typing
if (code != '9') {
$(e.target).closest("table.multipleChoice").find(":checkbox, :radio").prop('checked', true);
handleChoiceFiltering();
}
});
var $matrixTbl = $("table.matrix");
if ($matrixTbl.length) {
$matrixTbl.find(".matrixCell")
.click(function(){
$(this).find(":radio,:checkbox").click();
checkRankingGroup(this, true);
}).find(":radio,:checkbox").click(function(e){ e.stopPropagation() }).end();
}
}
function getChoiceUniqueName($b) {
return $b.is(":radio") ? $b.attr("name") + $b.val() : $b.attr("name");
}
function getURLParameter(name) {
return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search)||[,""])[1].replace(/\+/g, '%20'))||null
}
function getParamOrFieldValue(name) {
var val = getURLParameter(name);
val = (!val || val=="" ? $("#"+name).val() : val);
return (val != "null" ? val : "");
}
// get parameter or field by id
function paramOrFieldEmpty(param) {
var val = getParamOrFieldValue(param);
return !val || val=="" || val=="null";
}
function getCaretPosition (oField) {
// Initialize
var iCaretPos = 0;
// IE Support
if (document.selection) {
// Set focus on the element
oField.focus ();
// To get cursor position, get empty selection range
var oSel = document.selection.createRange ();
// Move selection start to 0 position
oSel.moveStart ('character', -oField.value.length);
// The caret position is selection length
iCaretPos = oSel.text.length;
}
// Firefox support
else if (oField.selectionStart || oField.selectionStart == '0')
iCaretPos = oField.selectionStart;
// Return results
return (iCaretPos);
}
function setCaretPosition(elem, caretPos) {
if(elem != null) {
if(elem.createTextRange) {
var range = elem.createTextRange();
range.move('character', caretPos);
range.select();
}
else {
if(elem.selectionStart) {
elem.focus();
elem.setSelectionRange(caretPos, caretPos);
}
else
elem.focus();
}
}
}
function getBg(el) {
var $el = $(el);
var color = $el.css("background-color");
var img = $el.css("background-image");
if (img && img != "" && img != "none") {
return { img: img };
}
if ((color !== 'rgba(0, 0, 0, 0)') && (color !== 'transparent')) {
return { col: color };
}
return ($el.is("body") ? false : getBg($el.parent()) );
}
function setRoundedBorder(el, radius, borderColor) {
$(el).css("-webkit-border-radius", radius + "px")
.css("-moz-border-radius", radius + "px")
.css("border-radius", radius + "px")
.css("border","1px " + borderColor + " solid");
}
function addScript(URL){
var scriptArray = document.getElementsByTagName('script');
for (i = 0; i < scriptArray.length;i++){
var URLIndex = scriptArray[i].src.indexOf(URL);
if (0 <= URLIndex){
return;
}
}
var headID = document.getElementsByTagName("head")[0];
var newScript = document.createElement('script');
newScript.type = 'text/javascript';
newScript.src = URL;
headID.appendChild(newScript);
}
/**
* Check if current page has already been submitted.
* Do not allow respondent to click on the same buttons multiple times, this result in double submissions
* and might result in PK violation problem if database connection is slow.
*
* (used for surveys only, not polls!)
*/
function allowSubmit(){
if ($.ObjectPlanet.alreadySubmitted){
alert(document.surveyForm.doubleSubmitMessage.value);
return false;
}
$.ObjectPlanet.alreadySubmitted = true;
return true;
}
/**
* Submit survey form (used for surveys only, not polls!)
*/
function submitForm(){
if(allowSubmit()){
document.surveyForm.submit();
}
}
// Open popup with poll results
function openPollResultPopup(resultUrl){
return window.open(resultUrl, 'pollResultPopup', 'toolbar=0,location=0,directories=0,status=0,menubar=0,scrollbars=1,copyhistory=0,resizable=1,width=350,height=340,top=400,left=400');
}
//Text required, numeric required
function textRequiredChk(field) {
with (field){
if (value == null || value == "") {
return false;
}
return true;
}
}
//Text min length
function textMinChk(field, min) {
//If the field is empty - return
if(!textRequiredChk(field)){
return true;
}
if ( field.value.length < min ){
return false;
}
return true;
}
//Text max length
function textMaxChk(field, max) {
//If the field is empty - return
if(!textRequiredChk(field)){
return true;
}
if ( max !='' && field.value.length > max ){
return false;
}
return true;
}
//Text email
function textEmailChk(field) {
//If the field is empty - return
if(!textRequiredChk(field)){
return true;
}
if ( field.value.length < 5 || field.value.indexOf("@") < 1 || field.value.indexOf(".") < 1) {
return false;
}
return true;
}
//Text date
function textDateChk(field, pattern) {
if(!textRequiredChk(field)){
return true;
}
var ok = buildDate(field.value, pattern);
if (!ok) {
return false;
}
return true;
}
//Text regular expression ( + contains)
//For more infor about regExp: http://www.webreference.com/js/column5/index.html
function textRegExpChk(field, pattern) {
//If the field is empty - return
if(!textRequiredChk(field)){
return true;
}
var regexp = new RegExp(pattern);
var ok = regexp.test(field.value);
if(!ok){
return false;
}
return true;
}
// Rating required
function radioRequiredChk(fieldName) {
var optionSelected = -2; // -1 is NA
for (i = 0; i < fieldName.length; i++) {
if (fieldName[i].checked) {
optionSelected = fieldName[i].value;
}
}
if (optionSelected < -1) {
return false;
}
return true;
}
//Dropdown required
function dropdownRequiredChk(entered) {
with (entered) {
if (value == "") {
return false;
}
return true;
}
}
//Dropdown min choice
function dropdownMinChk(entered, minSelected) {
var selectedCounter = 0;
var length = entered.length;
for(i = 0; i < length; i++) {
opt = entered.options[i];
if(i == 0 && (opt.value == "") ){
}else if (opt.selected){
selectedCounter++;
}
}
if (selectedCounter < minSelected){
return false;
}
return true;
}
//Dropdown max choice
function dropdownMaxChk(entered, maxSelected) {
var selectedCounter = 0;
var length = entered.length;
for(i = 0; i < length; i++) {
opt = entered.options[i];
if(i == 0 && (opt.value == "") ){
}else if (opt.selected){
selectedCounter++;
}
}
if (selectedCounter > maxSelected){
return false;
}
return true;
}
//Numeric required
function numericChk(entered, datatype) {
//If the field is empty - return
if(!textRequiredChk(entered)){
return true;
}
with (entered) {
var checkvalue = parseFloat(value);
if (datatype.charAt(0)=="i"){
checkvalue = parseInt(value);
if (isNaN(checkvalue)){
return false;
}
}
if(value != checkvalue){
return false;
}
}
return true;
}
//Numeric minimum value
function numericMinChk(entered, datatype, minValue) {
//If the field is empty - return
if(!textRequiredChk(entered)){
return true;
}
with (entered) {
checkvalue = parseFloat(value);
min = parseFloat(minValue);
if (datatype.charAt(0)=="i"){
checkvalue = parseInt(value);
if (isNaN(checkvalue)){
return true;
}
}
if(value != checkvalue){
return true;
}
if (checkvalue < min) {
return false;
}
}
return true;
}
//Numeric maximum value
function numericMaxChk(entered, datatype, maxValue) {
//If the field is empty - return
if(!textRequiredChk(entered)){
return true;
}
with (entered) {
checkvalue = parseFloat(value);
max = parseFloat(maxValue);
if (datatype.charAt(0)=="i"){
checkvalue = parseInt(value);
if (isNaN(checkvalue)){
return true;
}
}
if(value != checkvalue){
return true;
}
if (checkvalue > max) {
return false;
}
}
return true;
}
//Multiple choice required
function multChoiceRequiredChk(fieldName) {
var optionSelected = -1;
for (i = 0; i < fieldName.length; i++) {
if (fieldName[i].checked){
optionSelected = fieldName[i].value;
}
}
if (optionSelected == -1) {
return false;
}
return true;
}
//Multiple choice minimum selections
function multChoiceMinChk(form, questionNo, optionCount, minSelected) {
var selectedCounter = 0;
for (i = 0; i < form.length; i++) {
if (form.elements[i].type == "checkbox") {
for (j = 0; j <= optionCount; j++) {
if (form.elements[i].name == ("q" + questionNo + "multiple_" + j)) {
if (form.elements[i].checked == true)
selectedCounter++
}
}
}
}
if (selectedCounter < minSelected){
return false;
}
return true;
}
//Multiple choice maximum selections
function multChoiceMaxChk(form, questionNo, optionCount, maxSelected) {
var selectedCounter = 0;
for (i = 0; i < form.length; i++) {
if (form.elements[i].type == "checkbox") {
for (j = 0; j <= optionCount; j++) {
if (form.elements[i].name == ("q" + questionNo + "multiple_" + j)) {
if (form.elements[i].checked == true)
selectedCounter++;
}
}
}
}
if (selectedCounter > maxSelected){
return false;
}
return true;
}
function matrixGroupRequiredChk(form, fieldName, fra, to, reqSel){
var log = "";
var searchPos = 0;
var name_;
var selectedCounter = 0;
for (p = fra; p <= to; p++) {
name_ = fieldName + "_" + p;
for (i = searchPos; i < form.length; i++) {
if (form.elements[i].name == name_){
searchPos = i;
if(form.elements[i].checked == true){
//log = log + "selected " +
selectedCounter++;
}
}
}
if(selectedCounter == reqSel){
return true;
}
}
return false;
}
function debug(msg) {
$("#op_debug").append(msg).show();
}
function freeTextKeyPressed(freeTextElement) {
$(freeTextElement).change();
}
function checkFreetextLength(freeTextElement, maxLength) {
var len = $(freeTextElement).val().length;
if(maxLength > 0 && maxLength < len) {
$(freeTextElement).val($(freeTextElement).val().substring(0,maxLength));
return false;
}
return true;
}
function matrixRating(form, fieldName, fromRow, toRow, colCount){
var name_;
var checkedCount = 0;
var i = 0;
for (var p = fromRow; p <= toRow; p++) {
checkedCount = 0;
name_ = fieldName + "_" + p;
i = getIndex(form, i, name_);
if(i >= 0){
for (var col = 0; col < colCount; col++) {
if(form.elements[i].checked == true){
checkedCount++;
}
i++;
}
if(checkedCount == 0){
return false;
}
}
}
return true;
}
function checkRankingGroup(fieldElement, clickedNow){
// alert("clickedNow: " + clickedNow + ", fieldElement.checked: " + fieldElement.checked);
if (!fieldElement.checked && clickedNow) {
checkRankingGroups();
return;
}
var g = 0;
var group = null;
// find the group name where the selected/deselected cell is located
while (true) {
// checks if there is a group with such index
var $groupTrList = $("tr:has(.group" + g + ")", $(fieldElement).parents(".matrix"));
if ($groupTrList.length == 0) {
break;
}
if ($(fieldElement).parent().hasClass("group" + g)) {
// the is the group we need
group = "group" + g;
}
g++;
}
if (group != null) {
// select or deselect the row
if ($(fieldElement).parent().parent().find("td." + group).find("input:checked").length > 0) {
$(fieldElement).parent().parent().find("td." + group).find("input:not(:checked)").attr("disabled","disabled").closest("td").addClass("disabledCell");
} else {
$(fieldElement).parent().parent().find("td." + group).find("input").removeAttr("disabled").closest("td").removeClass("disabledCell");
}
// select or deselect the column
var column = parseInt($(fieldElement).attr("name").split("_")[1]) + 1;
if ($(fieldElement).parent().parent().parent().find("td." + group).filter(':nth-child(' + column + ')').find("input:checked").length > 0) {
$(fieldElement).parent().parent().parent().find("td." + group).filter(':nth-child(' + column + ')').find("input:not(:checked)").attr("disabled","disabled").closest("td").addClass("disabledCell");
} else {
$(fieldElement).parent().parent().parent().find("td." + group).filter(':nth-child(' + column + ')').find("input").removeAttr("disabled").closest("td").removeClass("disabledCell");
}
}
}
function findFirstRowCell(form, startName, colPos, from){
var cellName = startName + "_" + colPos;
var i = getIndex(form, from, cellName);
return i;
}
function matrixGroupMinChk(form, fieldName, fromCol, toCol, fromRow, toRow, minSelected) {
var name_;
var checkedCount = 0;
var i = 0;
for(p = fromRow; p <= toRow; p++) {
name_ = fieldName + fromCol + "_" + p;
i = getIndex(form, i, name_);
if(i >= 0){
for(col = fromCol; col <= toCol; col++) {
var element = form.elements[i];
if(element.type == "checkbox" && element.checked == true){
checkedCount++;
}
i++;
}
}
}
if(checkedCount < minSelected){
return false;
}
return true;
}
function matrixGroupMaxChk(form, fieldName, fromCol, toCol, fromRow, toRow, maxSelected) {
var name_;
var checkedCount = 0;
var i = 0;
for(p = fromRow; p <= toRow; p++) {
name_ = fieldName + fromCol + "_" + p;
i = getIndex(form, i, name_);
if(i >= 0){
for(col = fromCol; col <= toCol; col++) {
var element = form.elements[i];
if(element.type == "checkbox" && element.checked == true){
checkedCount++;
}
i++;
}
}
}
if(checkedCount > maxSelected){
return false;
}
return true;
}
//************************************** Date validation *********************************
// http://javascript.internet.com/forms/validation-universal-date.html (with some changes)
/* Here's the list of tokens we support:
m (or M) : month number, one or two digits.
mm (or MM) : month number, strictly two digits (i.e. April is 04).
d (or D) : day number, one or two digits.
dd (or DD) : day number, strictly two digits.
y (or Y) : year, two or four digits.
yy (or YY) : year, strictly two digits.
yyyy (or YYYY) : year, strictly four digits.
mon : abbreviated month name (April is apr, Apr, APR, etc.)
Mon : abbreviated month name, mixed-case (i.e. April is Apr only).
MON : abbreviated month name, all upper-case (i.e. April is APR only).
mon_strict : abbreviated month name, all lower-case (i.e. April is apr
only).
month : full month name (April is april, April, APRIL, etc.)
Month : full month name, mixed-case (i.e. April only).
MONTH: full month name, all upper-case (i.e. APRIL only).
month_strict : full month name, all lower-case (i.e. april only).
h (or H) : hour, one or two digits.
hh (or HH) : hour, strictly two digits.
min (or MIN): minutes, one or two digits.
mins (or MINS) : minutes, strictly two digits.
s (or S) : seconds, one or two digits.
ss (or SS) : seconds, strictly two digits.
ampm (or AMPM) : am/pm setting. Valid values to match this token are
am, pm, AM, PM, a.m., p.m., A.M., P.M.
*/
// Be careful with this pattern. Longer tokens should be placed before shorter
// tokens to disambiguate them. For example, parsing "mon_strict" should
// result in one token "mon_strict" and not two tokens "mon" and a literal
// "_strict".
var delimPat = /(-|\.|\/|:| )/i;
var tokPat = new RegExp("^month_strict|month|Month|MONTH|yyyy|YYYY|mins|MINS|mon_strict|ampm|AMPM|mon|Mon|MON|min|MIN|dd|DD|mm|MM|yy|YY|hh|HH|ss|SS|m|M|d|D|y|Y|h|H|s|S");
// lowerMonArr is used to map months to their numeric values.
var lowerMonArr={jan:1, feb:2, mar:3, apr:4, may:5, jun:6, jul:7, aug:8, sep:9, oct:10, nov:11, dec:12};
// monPatArr contains regular expressions used for matching abbreviated months
// in a date string.
var monPatArr=new Array();
monPatArr['mon_strict']=new RegExp(/jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec/);
monPatArr['Mon']=new RegExp(/Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec/);
monPatArr['MON']=new RegExp(/JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC/);
monPatArr['mon']=new RegExp("jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec",'i');
// monthPatArr contains regular expressions used for matching full months
// in a date string.
var monthPatArr=new Array();
monthPatArr['month']=new RegExp(/^january|february|march|april|may|june|july|august|september|october|november|december/i);
monthPatArr['Month']=new RegExp(/^January|February|March|April|May|June|July|August|September|October|November|December/);
monthPatArr['MONTH']=new RegExp(/^JANUARY|FEBRUARY|MARCH|APRIL|MAY|JUNE|JULY|AUGUST|SEPTEMBER|OCTOBER|NOVEMBER|DECEMBER/);
monthPatArr['month_strict']=new RegExp(/^january|february|march|april|may|june|july|august|september|october|november|december/);
// cutoffYear is the cut-off for assigning "19" or "20" as century. Any
// two-digit year >= cutoffYear will get a century of "19", and everything
// else gets a century of "20".
var cutoffYear=50;
/* buildDate does all the real work.It takes a date string and format string,
tries to match the two up, and returns a Date object (with the supplied date
string value).If a date string doesn't contain all the fields that a Date
object contains (for example, a date string with just the month), all
unprovided fields are defaulted to those characteristics of the current
date. Time fields that aren't provided default to 0.Thus, a date string
like "3/30/2000" in "%mm/%dd/%yyyy" format results in a Date object for that
date at midnight.formatStr is a free-form string that indicates special
tokens via the % character.Here are some examples that will return a Date
object:
buildDate('3/30/2000','%mm/%dd/%y') // March 30, 2000
buildDate('March 30, 2000','%Mon %d, %y') // Same as above.
buildDate('Here is the date: 30-3-00','Here is the date: %dd-%m-%yy')
If the format string does not match the string provided, an error message
(i.e. String object) is returned.Thus, to see if buildDate succeeded, the
caller can use the "typeof" command on the return value.For example,
here's the dateCheck function, which returns true if a given date is
valid,and false otherwise (and reports an error in the false case):
function dateCheck(dateStr, formatStr) {
var myObj = buildDate(dateStr,formatStr);
if (typeof myObj=="object") {
// We got a Date object, so good.
return true;
} else {
// We got an error string.
alert(myObj);
return false;
}
}
*/
function buildDate(dateStr,formatStr) {
// parse the format string first.
var tokArr=parseFormatString(formatStr);
var strInd=0;
var tokInd=0;
var intMonth;
var intDay;
var intYear;
var intHour;
var intMin;
var intSec;
var ampm="";
var strOffset;
// Create a date object with the current date so that if the user only
// gives a month or day string, we can still return a valid date.
var curdate=new Date();
intMonth=curdate.getMonth()+1;
intDay=curdate.getDate();
intYear=curdate.getFullYear();
// Default time to midnight, so that if given just date info, we return
// a Date object for that date at midnight.
intHour=0;
intMin=0;
intSec=0;
// Walk across dateStr, matching the parsed formatStr until we find a
// mismatch or succeed.
while (strInd < dateStr.length && tokInd < tokArr.length) {
// Start with the easy case of matching a literal.
if (tokArr[tokInd].type=="literal") {
if (dateStr.indexOf(tokArr[tokInd].token, strInd) == strInd) {
// The current position in the string does match the format pattern.
strInd+=tokArr[tokInd++].token.length;
continue;
} else {
// ACK! There was a mismatch; return error.
return false;
}
}
// If we get here, we're matching to a symbolic token.
switch (tokArr[tokInd].token) {
case 'm':
case 'M':
case 'd':
case 'D':
case 'h':
case 'H':
case 'min':
case 'MIN':
case 's':
case 'S':
// Extract one or two characters from the date-time string and if
// it's a number, save it as the month, day, hour, or minute, as
// appropriate.
curChar=dateStr.charAt(strInd);
nextChar=dateStr.charAt(strInd+1);
matchArr=dateStr.substr(strInd).match(/^\d{1,2}/);
if (matchArr==null) {
// First character isn't a number; there's a mismatch between
// the pattern and date string, so return error.
switch (tokArr[tokInd].token.toLowerCase()) {
case 'd': var unit="day";
break;
case 'm': var unit="month"; break;
case 'h': var unit="hour"; break;
case 'min': var unit="minute"; break;
case 's': var unit="second"; break;
}
return false;
}
strOffset=matchArr[0].length;
switch (tokArr[tokInd].token.toLowerCase()) {
case 'd': intDay=parseInt(matchArr[0],10); break;
case 'm': intMonth=parseInt(matchArr[0],10); break;
case 'h': intHour=parseInt(matchArr[0],10); break;
case 'min': intMin=parseInt(matchArr[0],10); break;
case 's': intSec=parseInt(matchArr[0],10); break;
}
break;
case 'mm':
case 'MM':
case 'dd':
case 'DD':
case 'hh':
case 'HH':
case 'mins':
case 'MINS':
case 'ss':
case 'SS':
// Extract two characters from the date string and if it's a
// number, save it as the month, day, or hour, as appropriate.
strOffset=2;
matchArr=dateStr.substr(strInd).match(/^\d{2}/);
if (matchArr==null) {
// The two characters aren't a number; there's a mismatch
// between the pattern and date string, so return an error
// message.
return false;
}
switch (tokArr[tokInd].token.toLowerCase()) {
case 'dd': intDay=parseInt(matchArr[0],10);break;
case 'mm': intMonth=parseInt(matchArr[0],10);break;
case 'hh': intHour=parseInt(matchArr[0],10); break;
case 'mins': intMin=parseInt(matchArr[0],10); break;
case 'ss': intSec=parseInt(matchArr[0],10); break;
}
break;
case 'y':
case 'Y':
// Extract two or four characters from the date string and if it's
// a number, save it as the year.Convert two-digit years to four
// digit years by assigning a century of '19' if the year is >=
// cutoffYear, and '20' otherwise.
if (dateStr.substr(strInd,4).search(/\d{4}/) != -1) {
// Four digit year.
intYear=parseInt(dateStr.substr(strInd,4),10);
strOffset=4;
} else {
if (dateStr.substr(strInd,2).search(/\d{2}/) != -1) {
// Two digit year.
intYear=parseInt(dateStr.substr(strInd,2),10);
if (intYear>=cutoffYear) {
intYear+=1900;
}
else {
intYear+=2000;
}
strOffset=2;
} else {
// Bad year; return error.
return false;
}
}
break;
case 'yy':
case 'YY':
// Extract two characters from the date string and if it's a
// number, save it as the year.Convert two-digit years to four
// digit years by assigning a century of '19' if the year is >=
// cutoffYear, and '20' otherwise.
if (dateStr.substr(strInd,2).search(/\d{2}/) != -1) {
// Two digit year.
intYear=parseInt(dateStr.substr(strInd,2),10);
if (intYear>=cutoffYear) {
intYear+=1900;
}
else {
intYear+=2000;
}
strOffset=2;
} else {
// Bad year; return error
return false;
}
break;
case 'yyyy':
case 'YYYY':
// Extract four characters from the date string and if it's a
// number, save it as the year.
if (dateStr.substr(strInd,4).search(/\d{4}/) != -1) {
// Four digit year.
intYear=parseInt(dateStr.substr(strInd,4),10);
strOffset=4;
} else {
// Bad year; return error.
return false;
}
break;
case 'mon':
case 'Mon':
case 'MON':
case 'mon_strict':
// Extract three characters from dateStr and parse them as
// lower-case, mixed-case, or upper-case abbreviated months,
// as appropriate.
monPat=monPatArr[tokArr[tokInd].token];
if (dateStr.substr(strInd,3).search(monPat) != -1) {
intMonth=lowerMonArr[dateStr.substr(strInd,3).toLowerCase()];
} else {
// Bad month, return error.
return false;
}
strOffset=3;
break;
case 'month':
case 'Month':
case 'MONTH':
case 'month_strict':
// Extract a full month name at strInd from dateStr if possible.
monPat=monthPatArr[tokArr[tokInd].token];
matchArray=dateStr.substr(strInd).match(monPat);
if (matchArray==null) {
// Bad month, return error.
return false;
}
// It's a good month.
intMonth=lowerMonArr[matchArray[0].substr(0,3).toLowerCase()];
strOffset=matchArray[0].length;
break;
case 'ampm':
case 'AMPM':
matchArr=dateStr.substr(strInd).match(/^(am|pm|AM|PM|a\.m\.|p\.m\.|A\.M\.|P\.M\.)/);
if (matchArr==null) {
// There's no am/pm in the string.Return error msg.
return false;
}
// Store am/pm value for later (as just am or pm, to make things
// easier later).
if (matchArr[0].substr(0,1).toLowerCase() == "a") {
// This is am.
ampm = "am";
}
else {
ampm = "pm";
}
strOffset = matchArr[0].length;
break;
default:
break;
}
strInd += strOffset;
tokInd++;
}
if (tokInd != tokArr.length || strInd != dateStr.length) {
/* We got through the whole date string or format string, but there's
more data in the other, so there's a mismatch. */
return false;
}
// Make sure all components are in the right ranges.
if (intMonth < 1 || intMonth > 12) {
return false;
}
if (intDay < 1 || intDay > 31) {
return false;
}
// Make sure user doesn't put 31 for a month that only has 30 days
if ((intMonth == 4 || intMonth == 6 || intMonth == 9 || intMonth == 11) && intDay == 31) {
return false;
}
// Check for February date validity (including leap years)
if (intMonth == 2) {
// figure out if "year" is a leap year; don't forget that
// century years are only leap years if divisible by 400
var isleap=(intYear%4==0 && (intYear%100!=0 || intYear%400==0));
if (intDay > 29 || (intDay == 29 && !isleap)) {
return false;
}
}
// Check that if am/pm is not provided, hours are between 0 and 23.
if (ampm == "") {
if (intHour < 0 || intHour > 23) {
return false;
}
} else {
// non-military time, so make sure it's between 1 and 12.
if (intHour < 1|| intHour > 12) {
return false;
}
}
// If user specified amor pm, convert intHour to military.
if (ampm=="am" && intHour==12) {
intHour=0;
}
if (ampm=="pm" && intHour < 12) {
intHour += 12;
}
if (intMin < 0 || intMin > 59) {
return false;
}
if (intSec < 0 || intSec > 59) {
return false;
}
return true;
}
// FormatToken is a datatype we use for storing extracted tokens from the
// format string.
function FormatToken (token, type) {
this.token=token;
this.type=type;
}
function parseFormatString (formatStr) {
var tokArr=new Array;
var tokInd=0;
var strInd=0;
var foundTok=0;
while (strInd < formatStr.length) {
var charAtpos = formatStr.charAt(strInd);
if( charAtpos.match(delimPat) ){
tokArr[tokInd++] = new FormatToken(charAtpos, "literal");
strInd += 1;
}else if ((matchArray=formatStr.substr(strInd).match(tokPat)) != null) {
strInd += matchArray[0].length;
tokArr[tokInd++] = new FormatToken(matchArray[0], "symbolic");
}
}
return tokArr;
}
function getIndex(what, from, which) {
for (var i = from; i < what.elements.length; i++){
if (what.elements[i] != null && what.elements[i].name == which){
return i;
}
}
return -1;
}
function reloadSurveyWindow(){
document.location.reload();
}
function uploadFile(systemurl, formE, formName, freeTextField){
if(formE.s == null || formE.r == null){
return false;
}
var name = "upload_w";
var uploadUrl = systemurl + "/rupload?sId=" + formE.s.value + "&rId=" + formE.r.value + "&en=" + formE.enc.value;
uploadUrl = uploadUrl + "&ticket=" + formE.ticket.value + "&fn=" + formName +"&tan=" + freeTextField + "&lang=" + formE.lang.value;
var features ="toolbar=0,location=0,directories=0,status=0,menubar=0,scrollbars=1,copyhistory=1,resizable=1,width="+650+",height="+450;
//alert("uploadUrl = \n\n" + uploadUrl);
window.open(uploadUrl, name, features);
}
/**
* JSON (Added OPS_ infront to make sure there is no conflicts with JSON used in the main page)
*/
// Constructor -- pass a REST request URL to the constructor
//
function OPS_JSONscriptRequest(fullUrl) {
// REST request path
this.fullUrl = fullUrl;
// Keep IE from caching requests
this.noCacheIE = '&noCacheIE=' + (new Date()).getTime();
// Get the DOM location to put the script tag
this.headLoc = document.getElementsByTagName("head").item(0);
// Generate a unique script tag id
this.scriptId = 'JscriptId' + OPS_JSONscriptRequest.scriptCounter++;
if(!this.headLoc || this.headLoc == null){
alert("Unable to create server request - HEAD element is not found in the document.");
}
}
// Static script ID counter
OPS_JSONscriptRequest.scriptCounter = 1;
// buildScriptTag method
OPS_JSONscriptRequest.prototype.buildScriptTag = function () {
// Create the script tag
this.scriptObj = document.createElement("script");
// Add script object attributes
this.scriptObj.setAttribute("type", "text/javascript");
this.scriptObj.setAttribute("charset", "utf-8");
this.scriptObj.setAttribute("src", this.fullUrl + this.noCacheIE + '&scriptId=' + this.scriptId);
this.scriptObj.setAttribute("id", this.scriptId);
}
// removeScriptTag method
OPS_JSONscriptRequest.prototype.removeScriptTag = function () {
// Destroy the script tag
this.headLoc.removeChild(this.scriptObj);
}
// addScriptTag method
OPS_JSONscriptRequest.prototype.addScriptTag = function () {
// Create the script tag
this.headLoc.appendChild(this.scriptObj);
}
// remove the caller script element
function OPS_JSONremoveCallerScript(scriptId){
try {
var callerScript = document.getElementById(scriptId);
var headElement = document.getElementsByTagName("head").item(0);
headElement.removeChild(callerScript);
}catch(ignore){
}
}
var MATRIX_CELL_NUMERIC_INT = 6;
var MATRIX_CELL_NUMERIC_DEC = 7;
var operators = {
'+' : {operator: '+', precedence: 1, calculate: function(l,r) { return l + r; } },
'-' : {operator: '-', precedence: 1, calculate: function(l,r) { return l - r; } },
'*' : {operator: '*', precedence: 2, calculate: function(l,r) { return l * r; } },
'/' : {operator: '/', precedence: 2, calculate: function(l,r) { return l / r; } }
};
function roundNumber(num, dec) {
var result = Math.round(num*Math.pow(10,dec))/Math.pow(10,dec);
return result;
}
function parseVal(r) {
var startOffset = r.offset;
var value = 0;
// floating point number
var digits = "0123456789";
while(digits.indexOf(r.string.substr(r.offset, 1)) >= 0 && r.offset < r.string.length) r.offset++;
if(r.string.substr(r.offset, 1) == ".") {
r.offset++;
while(digits.indexOf(r.string.substr(r.offset, 1)) >= 0 && r.offset < r.string.length) r.offset++;
}
if(r.offset > startOffset) { // get the number
return parseFloat(r.string.substr(startOffset, r.offset-startOffset));
} else if(r.string.substr(r.offset, 1) == "+") { // unary plus
r.offset++;
return parseVal(r);
} else if(r.string.substr(r.offset, 1) == "-") { // unary minus
r.offset++;
return (-1)*(parseVal(r));
} else if(r.string.substr(r.offset, 1) == "(") { // expression in parenthesis
r.offset++; // eat "("
value = parseExpr(r);
if(r.string.substr(r.offset, 1) == ")") {
r.offset++;
return value;
}
r.error = "Parsing error: ')' expected";
throw 'parseError';
} else {
if(r.string.length == r.offset) {
r.error = 'Parsing error at end of string: value expected';
throw 'valueMissing';
} else {
r.error = "Parsing error: unrecognized value";
throw 'valueNotParsed';
}
}
}
function parseExpr(r) {
var stack = [{precedence: 0}];
var op;
var value = parseVal(r); // first value on the left
for(;;){
var nextOp = ("+-*/".indexOf(r.string.substr(r.offset,1)) >= 0) ? operators[r.string.substr(r.offset++, 1)] : null;
op = nextOp || {precedence: 0};
while(op.precedence <= stack[stack.length-1].precedence) {
// precedence of op is lower than the one in stack, calculate the left first
var tos = stack.pop();
if(!tos.calculate) return value; // end reached
// do the calculation ("reduce"), producing a new value
value = tos.calculate(tos.value, value);
}
// store on stack and continue parsing ("shift")
stack.push({operator: op.operator, precedence: op.precedence, calculate: op.calculate, value: value});
value = parseVal(r); // value on the right
}
}
function parseMatrixFormula(str) {
var r = {string: str, offset: 0};
var value = parseExpr(r);
if(value == Number.POSITIVE_INFINITY || value == Number.POSITIVE_INFINITY || value == Number.NaN) {
// show ####
throw 'number out of range';
}
if(r.offset < r.string.length){
r.error = 'Syntax error: junk found at offset ' + r.offset;
throw 'trailingJunk';
}
return value;
}
/**
* Expands a range for summation. For example:
*
* A2:B6(default: cells within same question as formula-cell), or Q2!A2:Q2!B6 (if question 2 and formula not on same page)
* could be expanded to:
* Q2!A2 + Q2!A4 + Q2!A5 + Q2!B5
*
* In this example, the cells expanded are the only cells in the matrix range which are numeric fields.
*
* @param range a string like "A2:B6", or "Q2!A2:Q2!B6"
* @param question the (default) question with the formula where range is a part of
* @param questionNo question number of the (default) question
* @return
*/
function expandMatrixSummationRange(range, question, questionNo) {
var q = question;
var sumAreaArray = range.split(":");
var indexExclamation = range.indexOf("!");
var prefix = "Q" + questionNo + "!"; // default prefix
if(indexExclamation > 1) {
var qNo = sumAreaArray[0].substring(1, indexExclamation);
prefix = range.substring(0, indexExclamation + 1); // a string like "Q2!"
q = matrixSummationInfo[qNo-1];
// get the cell refs
sumAreaArray[0] = sumAreaArray[0].substring(indexExclamation + 1);
sumAreaArray[1] = sumAreaArray[1].substring(indexExclamation + 1);
}
// check validity
if (!q || !q.matrix) return {summationString: "", summationCount: 0};
var col1 = toNumericFromAlphabeticPermutation(sumAreaArray[0].substring(0, sumAreaArray[0].search(/[0-9]/)));
var row1 = parseInt(sumAreaArray[0].substring(sumAreaArray[0].search(/[0-9]/)))-1;
var col2 = toNumericFromAlphabeticPermutation(sumAreaArray[1].substring(0, sumAreaArray[1].search(/[0-9]/)));
var row2 = parseInt(sumAreaArray[1].substring(sumAreaArray[1].search(/[0-9]/)))-1;
var colStart = Math.min(col1,col2);
var colEnd = Math.max(col1,col2);
var rowStart = Math.min(row1,row2);
var rowEnd = Math.max(row1,row2);
// check boundaries
colEnd = (q.matrix.columns.length <= colEnd)? q.matrix.columns.length-1 : colEnd;
rowEnd = (q.matrix.columns[0].length <= rowEnd)? q.matrix.columns[0].length-1 : rowEnd;
var expandString = "";
var count = 0;
for ( var col = colStart; col <= colEnd; col++) {
for ( var row = rowStart; row <= rowEnd; row++) {
if(q.matrix.columns[col][row]) {
var cellType = q.matrix.columns[col][row].cellType;
if(cellType == MATRIX_CELL_NUMERIC_INT || cellType == MATRIX_CELL_NUMERIC_DEC) {
expandString += prefix + toAlphabeticPermutation(col, true) + (row+1) + "+";
count++;
}
}
}
}
if(expandString != "") expandString = expandString.substr(0, expandString.length-1); // remove the last "+"
return {summationString: expandString, summationCount: count};
}
/**
* Expands math-functions (sum, avg) in a matrix. Searches the formula for these functions, then
* takes the ranges, and expands the expression. Ie:
* sum(A2:B6) (default: cells within same question as formula-cell), or sum(Q2!A2:Q2!B6)(if question 2 and formula not on same page)
* could be expanded to:
* Q2!A2 + Q2!A4 + Q2!A5 + Q2!B5
*
* Average will be expanded like this:
*
* avg(A2:B6)
* could be expanded to:
* (Q2!A2 + Q2!A4 + Q2!A5 + Q2!B5)/4
*
* In this example, the cells expanded are the only cells in the matrix range which are numeric fields.
*
* @param formula a mathematical formula that possibly includes mathematical functions
* @param question The (default) matrix question
* @param questionNo question number of the (default) question
* @return
*/
function expandMatrixMathFunction(formula, question, questionNo) {
if (!question || !question.matrix) {
return;
}
var summationObj;
var formulaStr = formula.toUpperCase().replace(/\s/g, ""); // remove spaces
// expand SUM function
var reSum = new RegExp("sum\\(((q|Q)[0-9]+!)?[a-zA-Z]+[0-9]+:((q|Q)[0-9]+!)?[a-zA-Z]+[0-9]+\\)", "gi");
var arraySum = formulaStr.match(reSum);
if (arraySum) {
var arraySumCopy = $.extend([], arraySum, true);
for ( var i = 0; i < arraySum.length; i++) {
arraySum[i] = arraySum[i].substring(4);
arraySum[i] = arraySum[i].substring(0, arraySum[i].length - 1);
summationObj = expandMatrixSummationRange(arraySum[i], question, questionNo);
if(summationObj.summationCount > 0) {
formulaStr = formulaStr.replace(arraySumCopy[i], "(" + summationObj.summationString + ")" );
} else {
formulaStr = formulaStr.replace(arraySumCopy[i], "0" );
}
}
}
// expand AVG function
var reAvg = new RegExp("avg\\(((q|Q)[0-9]+!)?[a-zA-Z]+[0-9]+:((q|Q)[0-9]+!)?[a-zA-Z]+[0-9]+\\)", "gi");
var arrayAvg = formulaStr.match(reAvg);
if (arrayAvg) {
var arrayAvgCopy = $.extend([], arrayAvg, true);
for ( var j = 0; j < arrayAvg.length; j++) {
arrayAvg[j] = arrayAvg[j].substring(4);
arrayAvg[j] = arrayAvg[j].substring(0, arrayAvg[j].length - 1);
summationObj = expandMatrixSummationRange(arrayAvg[j], question, questionNo);
if(summationObj.summationCount > 0) {
formulaStr = formulaStr.replace(arrayAvgCopy[j], "(" + summationObj.summationString + ")/" + summationObj.summationCount);
} else {
formulaStr = formulaStr.replace(arrayAvgCopy[j], "0" );
//throw 'invalidFormula: average count is 0';
}
}
}
// expand default strings, e.x. "A3" to "Q1!A3"
var re = new RegExp("((q|Q)[0-9]+!)?[a-zA-Z]+[0-9]+", "gi");
var arrayExpanded = formulaStr.match(re);
if (arrayExpanded) {
for ( var k = 0; k < arrayExpanded.length; k++) {
if(arrayExpanded[k].indexOf("!") == -1) {
// look-around should be applied here, so that we replace only "A3", not "Q2!A3" or "A36";
// since javascript does not support look-behind, a walk-around is used in replace function
var regExp = new RegExp("(!)?" + arrayExpanded[k] + "(?![0-9]+)", "gi");
formulaStr = formulaStr.replace(regExp, function($0, $1){
return $1 ? $0 : "Q"+questionNo+"!"+arrayExpanded[k];
});
}
}
}
return formulaStr;
}
/**
* Creates an alphanumeric permutation from an integer(0-based), i.e. 0 is "A", 1 is "B", 26 is "AA", etc.
*/
function toAlphabeticPermutation(num, useCapitalLetters) {
var alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
if(useCapitalLetters) {
alphabet = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
}
var modNum = num % alphabet.length;
var permutation = "";
permutation = permutation + alphabet[modNum];
var divNum = Math.round((num / alphabet.length) - 0.5);
if(divNum > 0) {
if(divNum > alphabet.length) {
permutation = toAlphabeticPermutation(divNum - 1, useCapitalLetters) + permutation;
} else {
permutation = alphabet[divNum - 1] + permutation;
}
}
return permutation;
}
/**
* Finds the position of a character in the latin alphabet.
*
* @param character
* @return The position in the alphabet.
*/
function alphabetPosition(character) {
var alphabet = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
for ( var i = 1; i <= alphabet.length; i++) {
if(character == alphabet[i-1]) {
return i;
}
}
}
/**
* Creates a number (0-based) from an alphanumeric permutation, i.e. "B" is 1, "AB" is 27, etc
*/
function toNumericFromAlphabeticPermutation(str) {
var strCopy = str.toUpperCase();
var result = 0;
for ( var i = 0; i < strCopy.length-1; i++) {
result = 26 * (result + alphabetPosition(strCopy.charAt(i)));
}
result += alphabetPosition(strCopy.charAt(strCopy.length-1));
return result - 1;
}
function addMatrixSummationHandlers() {
if(typeof matrixSummationInfo == 'undefined' || !matrixSummationInfo) return;
// loop through all matrix questions
for(var qIndex = 0; qIndex < matrixSummationInfo.length; qIndex++) {
if(!matrixSummationInfo[qIndex] || !matrixSummationInfo[qIndex].matrix) continue;
var cells = matrixSummationInfo[qIndex].matrix.columns;
// loop through all cells
for(var col = 0; col < cells.length; col++) {
for(var row = 0; row < cells[0].length; row++) {
var cell = cells[col][row];
// if a cell is numeric with formula
if(cell && cell.formula) {
// expand the formula and find cell names within it
var formula = expandMatrixMathFunction(cell.formula, matrixSummationInfo[qIndex], qIndex+1);
// match all formula cells (in the form like "Q2!A6")
var cellRefArray = formula.match(/(q|Q)[0-9]+![a-zA-Z]+[0-9]+/gi);
// loop through formula cells
for(var k = 0; cellRefArray && k < cellRefArray.length; k++) {
// fetch index of reference question and index of reference column/row
var qRefIndex = getFormulaCells(cellRefArray[k]).qIndex;
var colRefIndex = getFormulaCells(cellRefArray[k]).colIndex;
var rowRefIndex = getFormulaCells(cellRefArray[k]).rowIndex;
// the reference question in formula must exist and be matrix
if(!matrixSummationInfo[qRefIndex] || !matrixSummationInfo[qRefIndex].matrix) continue;
var cellsRef = matrixSummationInfo[qRefIndex].matrix.columns;
if(colRefIndex < cellsRef.length && rowRefIndex < cellsRef[0].length) {
var formulaCell = cellsRef[colRefIndex][rowRefIndex];
if(formulaCell && (formulaCell.cellType == 6 || formulaCell.cellType == 7)) {
// register "keyup" event on formulaCell
var qNo = qRefIndex + 1;
var eventData = { formulaCellSelector: "#q"+(qIndex+1)+"cell"+col+"_"+row, "formula": formula, "qNo": qNo, isInteger: (cell.cellType == 6), colIndex: colRefIndex, rowIndex: rowRefIndex};
$("#q"+qNo+"cell"+colRefIndex+"_"+rowRefIndex).bind("keyup", eventData, numericFieldKeyupHandler);
}
}
}
}
}
}
}
// initialize values on current page
calculateInitialMatrixValues();
}
function calculateInitialMatrixValues() {
// loop through matrix summation array, and find all formulas on current page
var fromSection = $("#fromS").val();
var toSection = $("#toS").val();
for ( var s = fromSection; s <= toSection; s++) {
var qNoOnPage = $("#section" + s).val().split("-");
for ( var i = 0; i < qNoOnPage.length; i++) {
var q = matrixSummationInfo[qNoOnPage[i]-1];
if(q && q.matrix.columns) {
var cells = q.matrix.columns;
// loop through all cells
for(var col = 0; col < cells.length; col++) {
for(var row = 0; row < cells[0].length; row++) {
var cell = cells[col][row];
// if it is a numeric cell with formula
if(cell && cell.formula) {
// calculate formula, and set field value
var formula = expandMatrixMathFunction(cell.formula, q, qNoOnPage[i]);
var $cellSelector = $("#q" + qNoOnPage[i] + "cell" + col + "_" + row);
var isInteger = (cell.cellType == 6)? true : false;
var result = calculateCellFormula(formula.replace(/\s/g, ""), isInteger);
// update response info and formula cell field value
result = (typeof result === "number" && !Number.isNaN(result) ? result : '');
matrixSummationResponseInfo[qNoOnPage[i]-1].matrix.columns[col][row] = result;
$cellSelector.val(result).trigger("keyup");
}
}
}
}
}
}
}
/**
* Handler for numeric fields in a matrix. Updates fields containing a formula referencing
* the field the handler is attached to; Updates matrixSummationResponseInfo.
*/
function numericFieldKeyupHandler(event) {
//check if value is valid: should contain at most one "," or "."
var fieldValue = $(event.target).val();
var cnt = fieldValue.replace(/,/g, ".").split(".").length;
if(cnt > 2) {
$(event.data.formulaCellSelector).val("####");
return;
}
// update value in matrixSummationResponseInfo
var col = event.data.colIndex;
var row = event.data.rowIndex;
matrixSummationResponseInfo[event.data.qNo-1].matrix.columns[col][row] = fieldValue;
// update result of formula
var formulaString = event.data.formula.replace(/\s/g, ""); // remove spaces
var result = calculateCellFormula(formulaString, event.data.isInteger);
// update response info and formula cell field value
var selector = event.data.formulaCellSelector;
var questionNo = selector.split("cell")[0].substring(2);
var colIndex = selector.split("cell")[1].split("_")[0];
var rowIndex = selector.split("cell")[1].split("_")[1];
result = (typeof result === "number" && !Number.isNaN(result) ? result : '');
matrixSummationResponseInfo[questionNo-1].matrix.columns[colIndex][rowIndex] = result;
$(selector).val(result).trigger("keyup");
}
function calculateCellFormula(formulaString, isInteger) {
var formulaStringCopy = formulaString;
// find all cell references
var refCellArray = formulaStringCopy.match(/(q|Q)[0-9]+![a-zA-Z]+[0-9]+/gi);
// loop through all cell references and fetch values
for(var m = 0; m < refCellArray.length; m++) {
var refQIndex = getFormulaCells(refCellArray[m]).qIndex;
var refColIndex = getFormulaCells(refCellArray[m]).colIndex;
var refRowIndex = getFormulaCells(refCellArray[m]).rowIndex;
// replace cell references in formula with values in the input fields
var value = matrixSummationResponseInfo[refQIndex].matrix.columns[refColIndex][refRowIndex];
if($.isNumeric(value) || (typeof value == "string" && value != "")) {
formulaStringCopy = formulaStringCopy.replace(refCellArray[m], value);
} else {
if(formulaStringCopy.indexOf("/") < 0){
formulaStringCopy = formulaStringCopy.replace(refCellArray[m], "0");
} else {
return "####";
}
}
}
// calculate the formula, now with numbers only
var result;
try {
result = parseMatrixFormula(formulaStringCopy.replace(/,/g, "."));
result = isInteger ? Math.round(result) : roundNumber(result, 2);
} catch (e) {
return "####";
}
// set the result into field referenced by "formulaCellSelector"
return result;
}
// return an object in the following format:
// {qIndex: 2, colIndex: 3, rowIndex: 5}
function getFormulaCells(cellRef) {
var indexExclamation = cellRef.indexOf("!");
var questionIndex = cellRef.substring(1, indexExclamation) - 1;
var cellRef = cellRef.substring(indexExclamation + 1);
var col = toNumericFromAlphabeticPermutation(cellRef.substring(0, cellRef.search(/[0-9]/)));
var row = cellRef.substring(cellRef.search(/[0-9]/)) - 1;
return {qIndex: questionIndex, colIndex: col, rowIndex: row};
}
// enables fields that are disabled for panelist (panel signup survey)
function onSubmitPanelSignupSurvey() {
$(".panelistAttributeInput").each(function () {
this.disabled = false;
});
// disable attribute that are not dispayed: they should not be saved
if ((typeof attributeDrilldownArray != 'undefined') && attributeDrilldownArray) {
for (var i=0; i < attributeDrilldownArray.length; i++) {
var dependentAttrName = attributeDrilldownArray[i].mapTo;
if (!isExpanded(dependentAttrName)) {
$("[attrname='" + dependentAttrName + "']").each(function(){
this.disabled = true;
});
$("[attrname='" + dependentAttrName + "'] input").each(function(){
this.disabled = true;
this.checked = false;
});
}
}
}
}
// ================================================================================
// functions to handle conditional display of the panelist attributes (drilldown)
// ================================================================================
if(!Array.prototype.indexOf) {
Array.prototype.indexOf = function(needle) {
for(var i = 0; i < this.length; i++) {
if(this[i] === needle) {
return i;
}
}
return -1;
};
}
function adjustPanelAttributeImages() {
// get the largest image width
var maxWidth = 0;
$(".multipleImage").each(function(index) {
var image = $(this).children('img');
if (image != 'undefined' && image.get(0) != undefined) {
var width = image.get(0).width;
if (width > maxWidth) {
maxWidth = width;
}
}
});
$(".multipleImage").css('width', maxWidth);
$(".multipleText").css('width', 'auto');
}
// all panelist attributes that depend on other attributes are initially hidden,
// this method displays attributes whoose parent attributes are checked and
// registers event for the parent attributes to show/hide dependent attributes
function panelistAttributesOnload() {
if((typeof attributeDrilldownArray === 'undefined') || !attributeDrilldownArray){
return;
}
var mainAttributeArray = new Array();
for (var i = 0; i < attributeDrilldownArray.length; i++) {
var mainAttrName = attributeDrilldownArray[i].attribute;
var dependentAttrName = attributeDrilldownArray[i].mapTo;
var mainAttr = $("[attrname='" + mainAttrName + "']");
var dependentAttr = $("[attrname='" + dependentAttrName + "']");
// set indentation depending on the level of dependence
var padding = getPanelistAttributePadding(dependentAttrName);
if (padding > 0) {
var questionTbl = dependentAttr.parents('.questionTbl');
questionTbl.parent().css('padding', '0px');
questionTbl.wrap('');
for (var j = 0; j < padding; j++) {
questionTbl.parent().before(' | ');
}
}
// if this is the first attribute in the category - find the category title and
// align with the attributes
var sectionTitleTr = dependentAttr.parents('.questionTbl').parents('tr:first').parents('tr:first').prev().prev().prev();
sectionTitleTr.find('td .sectionTitle').css('padding-left', padding+'px').css('border-collapse','separate');
// set the dependent attribute visible if it should be
if (isExpanded(dependentAttrName)) {
showPanelAttribute(dependentAttr);
} else {
hidePanelAttribute(dependentAttr);
}
// register event for the main attribute if not registered before: when attribute deselected check if nested element have value
if (mainAttr.parents('.questionTbl').attr("isAdminViewing") != undefined) {
if (mainAttributeArray.indexOf(mainAttrName) == -1) {
mainAttr.bind('click', {mainAttrName: mainAttrName}, hasNestedValues);
mainAttributeArray.push(mainAttrName);
}
}
// register event: it will be sent to the dependent attr when the parent attr will be selected or deselected
mainAttr.bind('click', {mainAttrName: mainAttrName, dependentAttrName: dependentAttrName}, showHidePanelistAttribute);
}
}
// gets padding for the attribute based on it's dependence from other attributes
function getPanelistAttributePadding(attrName) {
for (var i = 0; i < attributeDrilldownArray.length; i++) {
if (attrName == attributeDrilldownArray[i].mapTo) {
return getPanelistAttributePadding(attributeDrilldownArray[i].attribute) + 1;
}
}
return 0;
}
// checks if the attribute has to be displayed based on it's nested dependence on other attributes
function isExpanded(attrName) {
for (var i = 0; i < attributeDrilldownArray.length; i++) {
if (attrName == attributeDrilldownArray[i].mapTo) {
var mainAttrName = attributeDrilldownArray[i].attribute;
var mainAttr = $("[attrname='" + mainAttrName + "']");
if (mainAttr.is(':checked')) {
return isExpanded(mainAttrName);
} else {
return false;
}
}
}
return true;
}
// called when an event is triggered to show or hide an attribute
function showHidePanelistAttribute(event) {
var dependentAttrName = event.data.dependentAttrName;
var mainAttrName = event.data.mainAttrName;
var dependentAttr = $("[attrname='" + dependentAttrName + "']");
var mainAttr = $("[attrname='" + mainAttrName + "']");
if (mainAttr.is(':checked')) {
showPanelAttribute(dependentAttr);
showNestedPanelistAttributes(dependentAttrName);
} else {
hidePanelAttribute(dependentAttr);
hideNestedPanelistAttributes(dependentAttrName);
}
}
//recursively hides all panelist attributes that depend on current one
function hideNestedPanelistAttributes(mainAttrName) {
for (var i=0; i < attributeDrilldownArray.length; i++) {
if (mainAttrName == attributeDrilldownArray[i].attribute) {
var dependentAttrName = attributeDrilldownArray[i].mapTo;
var dependentAttr = $("[attrname='" + dependentAttrName + "']");
hidePanelAttribute(dependentAttr);
hideNestedPanelistAttributes(dependentAttrName);
}
}
}
//recursively shows all panelist that depend on current one (only if the parent attr is checked)
function showNestedPanelistAttributes(mainAttrName) {
for (var i = 0; i < attributeDrilldownArray.length; i++) {
if (mainAttrName == attributeDrilldownArray[i].attribute) {
var mainAttr = $("[attrname='" + mainAttrName + "']");
if (mainAttr.is(':checked')) {
var dependentAttrName = attributeDrilldownArray[i].mapTo;
var dependentAttr = $("[attrname='" + dependentAttrName + "']");
showPanelAttribute(dependentAttr);
showNestedPanelistAttributes(dependentAttrName);
}
}
}
}
// recursively check if nested attributes have values
function hasNestedValues(event) {
var mainAttrName = event.data.mainAttrName;
var has_nested_values = false;
for (var i = 0; i < attributeDrilldownArray.length; i++) {
if (mainAttrName == attributeDrilldownArray[i].attribute) {
var mainAttr = $("[attrname='" + mainAttrName + "']");
if (!mainAttr.is(":checked")) {
var dependentAttrName = attributeDrilldownArray[i].mapTo;
$("[attrname='" + dependentAttrName + "']").each(function() {
var attrType = $(this).attr("type");
var childAttr = $($(this).children()[0]);
if(attrType == "checkbox") {
if ($(this).is(":checked")) {
has_nested_values = true;
}
}
else if (childAttr !== undefined && childAttr.attr("class") == "multipleChoice") {
var inputAttr = childAttr.find("input");
if (inputAttr.is(":checked")) {
has_nested_values = true;
}
}
else {
if ($(this).val()) {
has_nested_values = true;
}
}
});
}
}
}
if (has_nested_values) {
alert($("#savingCollapsedWarning").val());
}
}
// shows given panel attribute including spacing and section title
function showPanelAttribute(attribute) {
// show only if the attribute is not hidden by admin
if(attribute.parents('.questionTbl').attr("hiddenQuestion") == undefined/* || attribute.parents('.questionTbl').attr("isadminviewing") !== undefined*/) {
attribute.parents('.questionTbl').css('display', '');
var attributeTr = attribute.parents('.questionTbl').parents('tr:first').parents('tr:first');
attributeTr.css('display', '');
attributeTr.prev().children('.spaceAfterSectionText').css('display', '');
attributeTr.prev().prev().children('.spaceBeforeSectionText').css('display', '');
attributeTr.prev().prev().prev().children('.sectionTitle,.betweenQuestions').css('display', '');
}
}
// hides given panel attribute including spacing and section title
function hidePanelAttribute(attribute) {
attribute.parents('.questionTbl').css('display', 'none');
var attributeTr = attribute.parents('.questionTbl').parents('tr:first').parents('tr:first');
attributeTr.css('display', 'none');
attributeTr.prev().children('.spaceAfterSectionText').css('display', 'none');
attributeTr.prev().prev().children('.spaceBeforeSectionText').css('display', 'none');
attributeTr.prev().prev().prev().children('.sectionTitle,.betweenQuestions').css('display', 'none');
}