1/** 2 * @file Javascript core function for public survey 3 * @description loaded before template javascript : allow template to use own function (if function is called after template.js) 4 * @copyright LimeSurvey <http://www.limesurvey.org/> 5 * @license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3-or-Later 6 */ 7 8/** 9 * Always set an empty LSvar 10 */ 11var LSvar = LSvar || { }; 12 13/** 14 * Action to do when relevance is set to on or off 15 */ 16function triggerEmRelevance(){ 17 triggerEmRelevanceQuestion(); 18 triggerEmRelevanceGroup(); 19 triggerEmRelevanceSubQuestion(); 20} 21/* On question */ 22function triggerEmRelevanceQuestion(){ 23 /* Action on this question */ 24 $("[id^='question']").on('relevance:on',function(event,data) { 25 /* @todo : attach only to this. Use http://stackoverflow.com/a/6411507/2239406 solution for now. 26 Don't want to stop propagation. */ 27 if(event.target != this) return; 28 $(this).removeClass("ls-irrelevant ls-hidden"); 29 }); 30 $("[id^='question']").on('relevance:off',function(event,data) { 31 if(event.target != this) return; 32 $(this).addClass("ls-irrelevant ls-hidden"); 33 }); 34 /* In all in one mode : need updating group too */ 35 $(".allinone [id^='group-']:not(.ls-irrelevant) [id^='question']").on('relevance:on',function(event,data) { 36 if(event.target != this) return; 37 $(this).closest("[id^='group-']").removeClass("ls-hidden"); 38 }); 39 $(".allinone [id^='group-']:not(.ls-irrelevant) [id^='question']").on('relevance:off',function(event,data) { 40 if(event.target != this) return; 41 if($(this).closest("[id^='group-']").find("[id^='question']").length==$(this).closest("[id^='group-']").find("[id^='question'].ls-hidden").length){ 42 $(this).closest("[id^='group-']").addClass("ls-hidden"); 43 } 44 }); 45} 46/* On Group */ 47function triggerEmRelevanceGroup(){ 48 $("[id^='group-']").on('relevance:on',function(event,data) { 49 if(event.target != this) return; 50 $(this).removeClass("ls-irrelevant ls-hidden"); 51 }); 52 $("[id^='group-']").on('relevance:off',function(event,data) { 53 if(event.target != this) return; 54 $(this).addClass("ls-irrelevant ls-hidden"); 55 }); 56} 57/* On sub-question and answers-list */ 58function triggerEmRelevanceSubQuestion(){ 59 $("[id^='question']").on('relevance:on',"[id^='javatbd']",function(event,data) { 60 if(event.target != this) return; // not needed now, but after (2016-11-07) 61 data = $.extend({style:'hidden'}, data); 62 $(this).removeClass("ls-irrelevant ls-"+data.style); 63 if(data.style=='disabled'){ 64 $(event.target).find('input').each(function(itrt, item ){ 65 $(item).prop("disabled", false ); 66 }); 67 } 68 if(data.style=='hidden'){ 69 updateLineClass($(this)); 70 updateRepeatHeading($(this).closest(".ls-answers")); 71 } 72 }); 73 $("[id^='question']").on('relevance:off',"[id^='javatbd']",function(event,data) { 74 if(event.target != this) return; // not needed now, but after (2016-11-07) 75 data = $.extend({style:'hidden'}, data); 76 $(this).addClass("ls-irrelevant ls-"+data.style); 77 78 if(data.style=='disabled'){ 79 $(event.target).find('input') 80 .each(function(itrt, item ){ 81 if($(item).attr('type') == 'checkbox' && $(item).prop('checked')) { 82 $(item).prop('checked', false).trigger('change'); 83 } 84 $(item).prop("disabled", true ); 85 }); 86 } 87 88 if(data.style=='hidden'){ 89 updateLineClass($(this)); 90 updateRepeatHeading($(this).closest(".ls-answers")); 91 } 92 93 console.ls.log($(this).find('input[disabled]')); 94 }); 95} 96 97/** 98 * relevance:(on|off) event 99 */ 100/* Update lines class when relevance:(on|off) */ 101function updateLineClass(line){ 102 if($(line).hasClass("ls-odd") || $(line).hasClass("ls-even")){ 103 $(line).closest(".ls-answers").find(".ls-odd:visible,.ls-even:visible").each(function(index){ // not limited to table 104 $(this).removeClass('ls-odd ls-even').addClass(((index+1)%2 == 0) ? "ls-odd" : "ls-even"); 105 }); 106 } 107} 108/* Update repeat heading */ 109function updateRepeatHeading(answers){
110 /* Update only (at start) when all hidden line is done : @todo : do it only once */ 111 $(function() { 112 if($(answers).data("repeatHeading") || $(answers).find("tbody").find(".ls-heading").length){ 113 /* set the data the first time */ 114 if(!$(answers).data("repeatHeading")){ 115 var repeatHeading=$(answers).find("tbody:first tr").length;/* first body don't have heading */ 116 $(answers).data("repeatHeading",repeatHeading) 117 $(answers).data("repeatHeader",$(answers).find("tbody .ls-heading").filter(":first")[0].outerHTML); 118 }else{ 119 var repeatHeading=$(answers).data("repeatHeading"); 120 } 121 /* can remove the heading and clone this one of thead */ 122 var header = $(answers).data("repeatHeader"); 123 $(answers).find("tbody .ls-heading").remove(); 124 var lines=$(answers).find('tr:visible'); 125 var max=$(answers).find('tr:visible').length-1; 126 $(lines).each(function(index){ 127 if(index != 0 && index % repeatHeading == 0 && index < max) 128 { 129 $(header).insertAfter($(this)); 130 } 131 }); 132 } 133 }); 134} 135/** 136 * Manage the index 137 */ 138function manageIndex(){ 139 /* only needed if it's not inside form (form#limesurvey) */ 140 $(".ls-index-buttons").on('click','[name="move"]',function(e){ 141 if(!$(this).closest('form').length && $('form#limesurvey').length==1){ 142 $(this).clone().addClass("hidden").appendTo('form#limesurvey').click(); 143 } 144 }); 145} 146 147/** 148 * Reload page when participant selects a new language. 149 * Sets input[name=lang] to new language and submits limesurvey form. 150 */ 151function activateLanguageChanger(){ 152 var limesurveyForm = $('form#limesurvey'); 153 if(limesurveyForm.length == 0 && $('form[name="limesurvey"]').length == 1) { /* #form-token for example */ 154 limesurveyForm = $('form[name="limesurvey"]'); 155 } 156 /** 157 * @param {string} lang Language to change to. 158 */ 159 var applyChangeAndSubmit = function(lang) { 160 // Remove existing onsubmitbuttoninput, no need to remove lang : last one is the submitted 161 $("#onsubmitbuttoninput").remove(); 162 // Append new input. 163 $('<input type="hidden">') 164 .attr('name', 'lang') 165 .val(lang) 166 .appendTo(limesurveyForm); 167 // Append move type. 168 /* onsubmitbuttoninput is related to template (and ajax) : MUST move to template with ajax ⦠*/ 169 $('<input type="hidden" id="onsubmitbuttoninput" name="move" value="changelang" />').appendTo(limesurveyForm); 170 limesurveyForm.submit(); 171 }; 172 173 $('.form-change-lang a.ls-language-link').on('click', function() { 174 var closestForm = $(this).closest('form'); 175 if (!closestForm.length) { 176 /* we are not in a forum, can not submit directly */ 177 if (limesurveyForm.length == 1) { 178 /* The limesurvey form exist in document, move select and button inside and click */ 179 var newLang = $(this).data('limesurvey-lang'); 180 applyChangeAndSubmit(newLang); 181 // TODO: Check all code below. When does it happen? 182 } else { 183 // If there are no form : we can't use it */ 184 if($(this).data('targeturl')){ 185 /* If we have a target url : just move location to this url with lang set */ 186 /* possible usage : in clear all */ 187 var target=$(this).data('targeturl'); 188 /* adding lang in get param manually */ 189 if(target.indexOf("?") >=0){ 190 target+="&lang="+$(this).val(); 191 }else{ 192 target+="?lang="+$(this).val(); 193 } 194 /* directly move to location */ 195 location.href = target; 196 return false; 197 }else{ 198 var lang = $(this).data('limesurvey-lang'); 199 /* No form, not targeturl : just see what happen */ 200 $("<form>", { 201 "class":'ls-js-hidden', 202 "html": '<input type="hidden" name="lang" value="' + lang + '" />', 203 "action": target, 204 "method": 'get' 205 }).appendTo(document.body).submit(); 206 } 207 208 } 209 }else{ 210 /* we are inside a form : just submit : but remove other lang input if exist : be sure it's this one send */ 211 $(this).closest('form').find("[name='lang']").not($(this)).remove(); 212 $(this).closest('.ls-language-changer-item').find(":submit").click(); 213 } 214 }); 215 /* Language changer dropdown */ 216 $('.form-change-lang [name="lang"] option:not(selected)').on('click', function(event) { 217 var closestForm = $(this).closest('form'); 218 var newLang = $(this).val();
219 if (!closestForm.length) { 220 /* we are not in a forum, can not submit directly */ 221 if (limesurveyForm.length == 1) { 222 /* The limesurvey form exist in document, move select and button inside and click */ 223 applyChangeAndSubmit(newLang); 224 // TODO: Check all code below. When does it happen? 225 // Answer : remind user can put language changer everywhere, not only in home page, but for example in clear all page etc ⦠226 } else { 227 // If there are no form : we can't use it */ 228 if($(this).parent().data('targeturl')){ 229 /* If we have a target url : just move location to this url with lang set */ 230 var target=$(this).parent().data('targeturl'); 231 /* adding lang in get param manually */ 232 if(target.indexOf("?") >=0){ 233 target+="&lang="+$(this).val(); 234 }else{ 235 target+="?lang="+$(this).val(); 236 } 237 /* directly move to location */ 238 location.href = target; 239 return false; 240 }else{ 241 /* No form, not targeturl : just see what happen */ 242 $("<form>", { 243 "class":'ls-js-hidden', 244 "html": '<input type="hidden" name="lang" value="' + newLang + '" />', 245 "action": target, 246 "method": 'get' 247 }).appendTo(document.body).submit(); 248 } 249 250 } 251 }else{ 252 /* we are inside a form : just submit : but remove other lang input if exist : be sure it's this one send */ 253 $(this).closest('form').find("[name='lang']").not($(this).parent()).remove(); 254 $(this).closest('.form-change-lang').find(':submit').click(); 255 } 256 }); 257} 258 259/** 260 * Action link with submit object (json) : add params to form and submit 261 */ 262function activateActionLink(){ 263 /* If no limesurvey form : don't need it */ 264 if(!$('form#limesurvey').length){ 265 $('[data-limesurvey-submit]').remove(); 266 } 267 /* Submit limesurvey form on click */ 268 else{ 269 $('[data-limesurvey-submit]').on('click',function(event) { 270 event.preventDefault(); 271 var submit=$(this).data('limesurvey-submit'); 272 var confirmedby=$(this).data('confirmedby'); 273 if(!confirmedby){ 274 $.each(submit, function(name, value) { 275 $("<input/>",{ 276 'type':"hidden", 277 'name':name, 278 'value':value, 279 }).appendTo('form#limesurvey'); 280 }); 281 $('form#limesurvey').submit(); 282 }else{ 283 var submits=$.extend(submit,confirmedby); 284 confirmSurveyDialog($(this).data('confirmlabel'),$(this).text(),submits) 285 } 286 }); 287 } 288} 289/** 290 * function for replacing submit after confirm 291 * @var string text : the text to be shown 292 * @var string optionnal title 293 * @var object[] submits : name.value to submit 294 */ 295function confirmSurveyDialog(text,title,submits){ 296 if($.bsconfirm !== undefined) { 297 $.bsconfirm(text, LSvar.lang.confirm, function(){ 298 $.each(submits, function(name, value) { 299 $("<input/>",{ 300 'type':"hidden", 301 'name':name, 302 'value':value, 303 }).appendTo('form#limesurvey'); 304 }); 305 $('form#limesurvey').submit(); 306 }); 307 } else { 308 if(confirm(text)){ 309 $.each(submits, function(name, value) { 310 $("<input/>",{ 311 'type':"hidden", 312 'name':name, 313 'value':value, 314 }).appendTo('form#limesurvey'); 315 }); 316 $('form#limesurvey').submit(); 317 } 318 } 319} 320/** 321 * Ask confirmation on click on .needconfirm 322 */ 323function activateConfirmButton(){ 324 /* With ajax mode : using $(document).on attache X times the same event */ 325 $("button[data-confirmedby]").on('click',function(event){ 326 var btnConfirm=$(this); 327 var cbConfirm=$(this).parent().find("[name='"+$(this).data('confirmedby')+"']"); 328 if(!$(cbConfirm).is(":checked")) { 329 event.preventDefault(); 330 var submits = { }; 331 submits[$(btnConfirm).attr('name')]=$(btnConfirm).val(); 332 submits[$(cbConfirm).attr('name')]=$(cbConfirm).val(); 333 confirmSurveyDialog($(cbConfirm).parent("label").text(),$(btnConfirm).text(),submits) 334 } 335 }); 336} 337/** 338 * Trigger tip class when classChangeGood/classChangeError happen 339 */ 340function triggerEmClassChange(){ 341 /* The tips */ 342 $(document).on('classChangeError','.ls-em-tip', function(event){ 343 $(this).removeClass("ls-em-success").addClass("ls-em-error text-danger"); 344 }); 345 $(document).on('classChangeGood','.ls-em-tip', function(event){ 346 $(this).removeClass("ls-em-error text-danger").addClass("ls-em-success"); 347 }); 348 /* The dynamic sum */ 349 $(document).on('classChangeError','.dynamic-total', function(event){ 350 $(this).removeClass("ls-em-success text-success").addClass("ls-em-error text-danger"); 351 }); 352 $(document).on('classChangeGood','.dynamic-total', function(event){ 353 $(this).removeClass("ls-em-error text-danger").addClass("ls-em-success text-success"); 354 }); 355 /* The input */ 356 $(document).on('classChangeError','input,select,textarea', function(event){ 357 $(this).closest(".form-control").addClass("has-warning"); // Use warning, not error : in multiple : if one input have error : it's apply to all input 358 }); 359 $(document).on('classChangeGood','input,select,textarea', function(event){ 360 $(this).closest(".form-control").removeClass("has-warning"); 361 }); 362} 363 364/** 365 * has-error management for ls-error-mandatory 366 * Only add ls-error-mandatory in PHP currently, not in js : different behaviour after try next and don't try next 367 * /!\ We can more easily doing without js ( usage of :empty in css with :text & select) but then no boostrap, for before submit : use only css in template 368 */ 369function updateMandatoryErrorClass(){ 370 $(".ls-error-mandatory .has-error,.ls-error-mandatory.has-error").on("blur",":text,textarea",function(event){ 371 if($(this).val()!==""){ 372 $(this).closest(".has-error").removeClass("has-error"); 373 if(!$(this).closest(".ls-error-mandatory").find(".has-error").length){ 374 $(this).closest(".ls-error-mandatory").find(".text-danger").removeClass("text-danger"); 375 } 376 } 377 }); 378 $(".ls-error-mandatory .has-error,.ls-error-mandatory.has-error").on("change","select",function(event){ 379 if($(this).val()!==""){ 380 $(this).closest(".has-error").removeClass("has-error"); 381 if(!$(this).closest(".ls-error-mandatory").find(".has-error").length){ 382 $(this).closest(".ls-error-mandatory").find(".text-danger").removeClass("text-danger"); 383 } 384 } 385 }); 386 $(".ls-error-mandatory.has-error").on("change",":radio",function(event){ 387 if($(this).closest(".array-flexible-duel-scale").length){ 388 if($(this).closest(".has-error").find("input:radio:checked").length>1){ 389 $(this).closest(".has-error").removeClass("has-error"); 390 } 391 }else{ 392 $(this).closest(".has-error").removeClass("has-error"); 393 } 394 }); 395 $(".ls-error-mandatory.has-error").on("change",":checkbox",function(event){ 396 $(this).closest(".has-error").removeClass("has-error"); 397 }); 398} 399 400function resetQuestionTimers(sid) { 401 var surveyTimersItemName = 'limesurvey_timers_by_sid_' + sid; 402 var timers = JSON.parse(window.localStorage.getItem(surveyTimersItemName) || "[]");
403 timers.forEach(function(timersessionname, idx){ 404 window.localStorage.removeItem('limesurvey_timers_' + timersessionname); 405 }); 406 window.localStorage.removeItem(surveyTimersItemName); 407}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.