PageSourceSearch

https://servizi.comunemalcesine.it/openweb/js/portal-php.js?v=02.10.26.12.pm

js comunemalcesine.it collected 2026-10-02 10:09:06 UTC 44,341 bytes, 1,280 lines download raw bytes

1/*
2 * Il codice contenuto in questo file js viene eseguito
3 * su ogni pagina di portal
4 * 
5 */
6
7$(document).ready(function() {
8
9  if(typeof(openweb_csrf)!="undefined") {
10    $("form").append('<input type="hidden" name="CSRF" value="'+openweb_csrf+'">');
11    $("a").each(function(){
12      if(!$(this).hasClass("noCSRF") && $(this).prop("href")!="" && $(this).prop("href").indexOf(".php")>=0 && $(this).prop("href").indexOf(".php?")<0) {
13        $(this).prop("href", $(this).prop("href")+"?");
14      }
15      if(!$(this).hasClass("noCSRF") && $(this).prop("href")!="" && $(this).prop("href").indexOf("javascript:")<0 && $(this).prop("href").indexOf(".aspx")<0 && $(this).prop("href").indexOf("?")>=0 && $(this).prop("href").indexOf("CSRF")<0) {
16        $(this).prop("href", $(this).prop("href")+"&CSRF="+openweb_csrf);
17      }
18    });
19    $allResponsiveTables = $("table.table-responsive");
20    $allResponsiveTables.each(function() {
21
22      if (!$(this).hasClass("no-responsive")) {
23      
24      tableToUl($(this))
25
26      }
27    });
28  }
29
30  /* =============================================================
31 * bootstrap-typeahead.js v2.0.1
32 * http://twitter.github.com/bootstrap/javascript.html#typeahead
33 * =============================================================
34 * Copyright 2012 Twitter, Inc.
35 *
36 * Licensed under the Apache License, Version 2.0 (the "License");
37 * you may not use this file except in compliance with the License.
38 * You may obtain a copy of the License at
39 *
40 * http://www.apache.org/licenses/LICENSE-2.0
41 *
42 * Unless required by applicable law or agreed to in writing, software
43 * distributed under the License is distributed on an "AS IS" BASIS,
44 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
45 * See the License for the specific language governing permissions and
46 * limitations under the License.
47 * ============================================================ */
48
49!function( $ ){
50
51  "use strict"
52
53  var Typeahead = function ( element, options ) {
54    this.$element = $(element)
55    this.$keyField = this.$element.data( "key-field" )!=""?this.$element.nextAll("#"+this.$element.data( "key-field" )):{};
56    this.options = $.extend({}, $.fn.typeahead.defaults, options)
57    this.matcher = this.options.matcher || this.matcher
58    this.sorter = this.options.sorter || this.sorter
59    this.highlighter = this.options.highlighter || this.highlighter
60    this.$menu = $(this.options.menu).appendTo('body')
61    this.source = this.options.source
62    this.keys = this.options.keys
63    this.shown = false
64    this.listen()
65  }
66
67  Typeahead.prototype = {
68
69    constructor: Typeahead
70
71  , select: function () {
72      var val = this.$menu.find('.active').attr('data-value')
73      var index = $.inArray(val, this.source);
74      if (index < 0) {
75	this.$element.val("");
76        if(this.$keyField.length) { this.$keyField.val(""); this.$keyField.trigger("change"); }
77      }
78      else {
79	this.$element.val(val);
80        if(this.$keyField.length) { this.$keyField.val(this.keys[index]); this.$keyField.trigger("change"); }
81      }
82      
83      return this.hide()
84    }
85
86  , show: function () {
87      var pos = $.extend({}, this.$element.offset(), {
88        height: this.$element[0].offsetHeight
89      })
90
91      this.$menu.css({
92        top: pos.top + pos.height
93      , left: pos.left
94      })
95
96      this.$menu.show()
97      this.shown = true
98      return this
99    }
100
101  , hide: function () {
102      this.$menu.hide()
103      this.shown = false
104      return this
105    }
106
107  , lookup: function (event) {
108      var that = this
109        , items
110        , q
111
112      this.query = this.$element.val()
113
114      if (!this.query) {
115        return this.shown ? this.hide() : this
116      }
117
118      items = $.grep(this.source, function (item) {
119        if (that.matcher(item)) return item
120      })
121
122      items = this.sorter(items)
123
124      if (!items.length) {
125        return this.shown ? this.hide() : this
126      }
127
128      return this.render(items.slice(0, this.options.items)).show()
129    }
130
131  , matcher: function (item) {
132      return item?~item.toLowerCase().indexOf(this.query.toLowerCase()):false
133    }
134
135  , sorter: function (items) {
136      var beginswith = []
137        , caseSensitive = []
138        , caseInsensitive = []
139        , item
140
141      while (item = items.shift()) {
142        if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item)
143        else if (~item.indexOf(this.query)) caseSensitive.push(item)
144        else caseInsensitive.push(item)
145      }
146
147      return beginswith.concat(caseSensitive, caseInsensitive)
148    }
149
150  , highlighter: function (item) {
151      return item.replace(new RegExp('(' + this.query + ')', 'ig'), function ($1, match) {
152        return '<strong>' + match + '</strong>'
153      })
154    }
155
156  , render: function (items) {
157      var that = this
158
159      items = $(items).map(function (i, item) {
160        i = $(that.options.item).attr('data-value', item)
161        i.find('a').html(that.highlighter(item))
162        return i[0]
163      })
164
165      items.first().addClass('active')
166      this.$menu.html(items)
167      return this
168    }
169
170  , next: function (event) {
171      var active = this.$menu.find('.active').removeClass('active')
172        , next = active.next()
173
174      if (!next.length) {
175        next = $(this.$menu.find('li')[0])
176      }
177
178      next.addClass('active')
179    }
180
181  , prev: function (event) {
182      var active = this.$menu.find('.active').removeClass('active')
183        , prev = active.prev()
184
185      if (!prev.length) {
186        prev = this.$menu.find('li').last()
187      }
188
189      prev.addClass('active')
190    }
191
192  , listen: function () {
193      this.$element
194        .on('blur',     $.proxy(this.blur, this))
195        .on('keypress', $.proxy(this.keypress, this))
196        .on('keyup',    $.proxy(this.keyup, this))
197
198      // CONTROLO DEPRECATO RIMOSSO PER COMPATIBILITA' CON JQUERY 3.5.1
199      // if ($.browser.webkit || $.browser.msie) {
200      //   this.$element.on('keydown', $.proxy(this.keypress, this))
201      // }
202
203
204      this.$menu
205        .on('click', $.proxy(this.click, this))
206        .on('mouseenter', 'li', $.proxy(this.mouseenter, this))
207    }
208
209  , keyup: function (e) {
210
211      switch(e.keyCode) {
212        case 40: // down arrow
213        case 38: // up arrow
214	  e.stopPropagation()
215	  e.preventDefault()
216          break
217
218        case 9: // tab
219	  if (!this.shown) return
220	  this.select()
221	  break;
222        case 13: // enter
223	  e.stopPropagation()
224	  e.preventDefault()
225          if (!this.shown) return
226          this.select()
227          break
228
229        case 27: // escape
230	  e.stopPropagation()
231	  e.preventDefault()
232          this.hide()
233          break
234
235        default:
236	  e.stopPropagation()
237	  e.preventDefault()
238          this.lookup()
239      }
240
241  }
242
243  , keypress: function (e) {
244      e.stopPropagation()
245      if (!this.shown) return
246
247      switch(e.keyCode) {
248        case 9: // tab
249        case 13: // enter
250        case 27: // escape
251          e.preventDefault()
252          break
253
254        case 38: // up arrow
255          e.preventDefault()
256          this.prev()
257          break
258
259        case 40: // down arrow
260          e.preventDefault()
261          this.next()
262          break
263      }
264    }
265
266  , blur: function (e) {	    
267      var val = this.$element.val();
268      var index = $.inArray(val, this.source);
269      if (index < 0) {
270	this.$element.val("");
271	if(this.$keyField.length) { this.$keyField.val(""); }
272      }
273      var that = this
274      e.stopPropagation()
275      e.preventDefault()
276      setTimeout(function () { that.hide() }, 150)
277    }
278
279  , click: function (e) {
280      e.stopPropagation()
281      e.preventDefault()
282      this.select()
283    }
284
285  , mouseenter: function (e) {
286      this.$menu.find('.active').removeClass('active')
287      $(e.currentTarget).addClass('active')
288    }
289
290  }
291
292
293  /* TYPEAHEAD PLUGIN DEFINITION
294   * =========================== */
295
296  $.fn.typeahead = function ( option ) {
297    return this.each(function () {
298      var $this = $(this)
299        , data = $this.data('typeahead')
300        , options = typeof option == 'object' && option
301      if (!data) $this.data('typeahead', (data = new Typeahead(this, options)))
302      if (typeof option == 'string') data[option]()
303    })
304  }
305
306  $.fn.typeahead.defaults = {
307    source: []
308  , items: 8
309  , menu: '<ul class="typeahead dropdown-menu"></ul>'
310  , item: '<li><a href="#"></a></li>'
311  }
312
313  $.fn.typeahead.Constructor = Typeahead
314
315
316 /* TYPEAHEAD DATA-API
317  * ================== */
318
319  $(function () {
320    $('body').on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) {
321      var $this = $(this)
322      if ($this.data('typeahead')) return
323      e.preventDefault()
324      $this.typeahead($this.data())
325    })
326  })
327
328}( window.jQuery );
329  /*
330   * Ogni elemento con classe form-hidable verrà dotato di un pulsante per mostrare il form (sopra lo stesso)
331   * ed un pulsante per nascondere il form (all'interno dello stesso, nel div con classe .buttons-row)
332   * 
333   * La classe form-hidable viene aggiunta automaticamente nel template dei widget quando $W->config['hidable'] == true
334   */
335  $(".form-hidable").each(function() {
336      $form = $(this);
337      $form.find(".buttons-row").append('<input type="button" class="btn btn-default btn-hide mt10" value="Nascondi ricerca">');
338      $form.before('<div class="col-xs-12 mb15"><input type="button" class="btn btn-default btn-show btn-outline-primary" value="Ricerca"></div>');
339      
340      $hideButton = $form.find(".btn-hide");
341      $showButton = $form.prev().find(".btn-show");
342      
343      $hideButton.click(function() {$form.hide(); $showButton.show();});
344      $showButton.click(function() {$form.show(); $showButton.hide();});
345
346      var searchActive = false;
347      $form.find("input,select,textarea").not(':button').not(':hidden').not(':submit').each(function(){
348	if($(this).val()!="") {
349	  searchActive = true;
350	}
351      });      
352
353      if(!searchActive){$form.hide();}
354      else {$showButton.hide();}
355    });
356  $(".nav-pills a").click(function(e) {
357      console.log($(this).text());
358      $("html").scrollTop( $($(this).attr("href")).offset().top-116 );
359  });
360  
361  if($('input.datepicker').length > 0) {
362    $('input.datepicker').each(function(){
363      var value = $(this).val();
364      $(this).datepicker({
365	"dateFormat": "dd/mm/yy",
366	constrainInput: true,
367	dayNames: [ "Domenica", "Lunedì", "Martedì", "Mercoledì", "Giovedì", "Venerdì", "Sabato" ],
368	dayNamesShort: [ "Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab" ],
369	dayNamesMin: [ "Do", "Lu", "Ma", "Me", "Gi", "Ve", "Sa" ],
370	monthNames: [ "Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno", "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre" ],
371	monthNamesShort: [ "Gen", "Feb", "Mar", "Apr", "Mag", "Giu", "Lug", "Ago", "Set", "Ott", "Nov", "Dic" ],
372	firstDay: 1,
373	setDate: value,
374      });      
375    });
376  }
377  
378  if($('#current_page').length > 0) {
379    var current_page = $('#current_page').val();
380    if(!page && current_page) {page=current_page;}
381    var show_per_page = parseInt($('body').find("#items_per_page").val());
382    var number_of_items = parseInt($('body').find('.pagination_content .paginated_element').length);
383    var last_page_number = Math.ceil(number_of_items/show_per_page);
384    
385    
386    function paginatorListeners($element) {
387      var ulContent = $element.find('ul').html();
388      if(ulContent) {
389	$element.html(ulContent);
390      }
391      $element.find('li').each(function() {
392	$(this).find('a').click(function() {
393	  var href = $(this).attr('href');
394	  var targetPage = 1;
395	  if(href.indexOf("go_to_page") > -1) {
396	    targetPage = href.replace("javascript:go_to_page(","").replace(", 'body')","").replace(",'body')","");
397	  }
398	  else if(href.indexOf("first_page") > -1) {
399	    targetPage = 1;
400	  }
401	  else if(href.indexOf("previous") > -1) {
402	    targetPage = parseInt($('body').find('#current_page').val())-1;
403	  }
404	  else if(href.indexOf("next") > -1) {
405	    targetPage = parseInt($('body').find('#current_page').val())+1;
406	  }
407	  else if(href.indexOf("last_page") > -1) {
408	    targetPage = last_page_number;
409	  }
410	  if(targetPage<1) {targetPage=1;}
411	  console.log("setting target to "+targetPage);
412	  $.post( paginatorPOSTurl, { paginatorPOSTparam: targetPage } );
413	});
414      });
415    }
416    
417    if(number_of_items>show_per_page) {
418      
419      init_paginatore();
420      
421      paginatorListeners($('#paginator_div'));
422      paginatorListeners($('.lista_pagine'));
423      $('#paginator_div').bind("DOMSubtreeModified",function(event){
424	paginatorListeners($(this));
425	paginatorListeners($('.lista_pagine'));
426	current_page = $('#current_page').val();
427      });
428      
429      if (page && page>1) 
430      { 
431	go_to_page(page, 'body'); 
432      } 
433    } else {
434      $('#paginator_div').remove();
435    }
436    
437  }
438
439  $('.row_linked').on('click', 'tr', function(){
440    if(typeof($(this).find('a').attr('href'))!="undefined") {
441      console.log("Going to "+$(this).find('a').attr('href'));
442      window.location = $(this).find('a').attr('href');
443    }
444  });
445  /*$('.row_linked tbody tr').each(function() {
446    $(this).css( "cursor", "pointer" );
447    $(this).click( function() {
448        window.location = $(this).find('a').attr('href');
449    }).hover( function() {
450        $(this).toggleClass('hover');
451    });
452  });*/
453
454  
455  var $labels = $("label:contains('*')" );
456  if($labels.length) {
457    var forms = [];
458    $labels.each(function(){
459      $(this).next("div").find("input, select, textarea").attr("required", true);
460      var noval = $(this).closest("form").attr("novalidate");
461      if(typeof noval === typeof undefined || noval === false || noval == "force") {
462	$(this).closest("form").attr("novalidate", true);
463	forms.push($(this).closest("form"));
464      }
465    });
466    for (var i in forms) {
467      initValidation(forms[i]);
468    }
469  }
470  
471  $("#menu_responsive_laterale").removeAttr("style");
472});
473
474var typeaheads = {};
475function enableTypeahead($element, keys, values)
476{
477  typeaheads[$element.prop("id")] = $element;
478  $elementTypeahead = $element.clone(true,true);
479  $elementTypeahead.insertAfter($element);
480  $element.remove();
481  $elementTypeahead.val("");
482  $elementTypeahead.attr( 'autocomplete', 'off' );
483  
484  $elementTypeahead.typeahead({source: values, keys: keys},{fitToElement: true});
485  $elementTypeahead.data("has-typeahead", true);
486  console.log("typeahead enabled on "+$element.attr("id"));
487}
488
489function disableTypeahead($element) {
490  if(typeof(typeaheads[$element.prop("id")])!="undefined") {
491    typeaheads[$element.prop("id")].insertAfter($element);
492    $element.remove();    
493    delete typeaheads[$element.prop("id")];
494    $elementTypeahead.removeData("has-typeahead");
495    console.log("typeahead disabled on "+$element.attr("id"));
496  }
497}
498
499function stradario($input, comune) {
500  console.log("stradario on "+$input.attr("id")+" for comune "+comune);
501  disableTypeahead($input);
502  var $wait = $('#'+$input.attr("id")+'_wait');
503  var $container = $input.parent();
504  if(!$wait.length) {
505    $wait = $("<input>");
506    $wait.attr("type", "text").attr("id", "referente_comuneResidenza_via_wait").val("caricamento stradario...").attr("disabled","true").addClass("form-control");
507    $container.append($wait);
508  }
509  $wait.hide();
510  if(comune!="") {
511    $input.hide();
512    $wait.show();
513    $.get( "get_indirizzi.php?comune="+comune, function( data ) {
514      $wait.hide();
515      $input.show();
516      var res = jQuery.parseJSON(data.replace(/'/g,'"'));
517      if(res.length>0) {
518	var ids = [];
519	var descrizioni = [];
520	for (var i in res) {
521	  ids.push(res[i].codice);
522	  descrizioni.push(decodeEntities(res[i].descrizione));
523	}
524	enableTypeahead($input, ids, descrizioni);
525	if($input.val()){$('#'+$input.attr("id")).val($input.val());}
526      }
527      else {
528	disableTypeahead($input);
529      }
530    });
531  }
532  else {
533    $wait.hide();
534    $input.show();
535  }
536}
537
538var decodeEntities = (function() {
539  // this prevents any overhead from creating the object each time
540  var element = document.createElement('div');
541
542  function decodeHTMLEntities (str) {
543    if(str && typeof str === 'string') {
544      // strip script/html tags
545      str = str.replace(/<script[^>]*>([\S\s]*?)<\/script>/gmi, '');
546      str = str.replace(/<\/?\w(?:[^"'>]|"[^"]*"|'[^']*')*>/gmi, '');
547      element.innerHTML = str;
548      str = element.textContent;
549      element.textContent = '';
550    }
551
552    return str;
553  }
554
555  return decodeHTMLEntities;
556})();
557
558function initValidation($form, callback) {
559  if($form && $form.length) {
560    console.log("initValidation on "+$form.attr("id"));
561    console.log("received callback ["+callback+"]");
562    savedCallback = callback;
563    // $form.find('input, select, textarea').blur(function(){
564    $form.on('blur', 'input,select,textarea', function(e){
565      // valida al blur solo se non è datepicker
566      if(Object.keys($(this).data()).indexOf("datepicker")===-1){validate($(this));}
567    });
568    $form.find('input[type=radio]').change(function(){validate($(this));});
569    $form.find('input, select').keypress(function (e) {
570      if (e.which == 13) {
571        return false;
572      }
573    });
574    
575    $form.submit(function( event, triggered ) {
576      event.stopImmediatePropagation(); // avoid double submission
577      console.log("-----------------");
578      console.log("form submitted");
579      var invalidFields = $.map($form.find("input,textarea,select"), function(element) { if(typeof $(element).data("is-valid") !== 'undefined' && $(element).data("is-valid")===false) return $(element).attr("id"); });
580      if(triggered) {
581        console.log("form is triggered, return true without checking");
582        $form.find("input[name='submit']").removeAttr("name"); // remove input with name="submit" in form, which overrides the native form.submit (programmatically submits the form) method that is being called internally in jQuery causing the form not to submit
583        return true;
584      }
585      else if(validateForm($(this), savedCallback) && invalidFields.length == 0) {
586        console.log("callback is "+savedCallback);
587        console.log("form is valid, return true");
588        $form.find("input[name='submit']").removeAttr("name"); // remove input with name="submit" in form, which overrides the native form.submit (programmatically submits the form) method that is being called internally in jQuery causing the form not to submit
589        return true;
590      }
591      else {
592        console.log("form is not valid, return false");
593        console.log("prevent default");
594        event.preventDefault();
595        if(!$(".bootbox").is(":visible") && invalidFields.length>0) {
596          bootbox.alert("I dati inseriti contengono degli errori.", function(){
597            var addOffset = 0;
598            if($('#header_border_fixed').length) {
599              addOffset = $('#header_border_fixed').height()+20;
600            }
601            var offset = $form.find(".text-danger").first().length?$form.find(".text-danger").first().offset().top-addOffset:0;
602            $('html, body').animate({scrollTop: offset}, 200);
603          })
604        }
605        return false;
606      }
607    });
608  }
609}
610
611function validate($field) {
612  if($field.next('.help-block').length>0) {$field.next('.help-block').remove();}
613  if($field.parent().parent().find(".help-block").length>0) {$field.parent().parent().find(".help-block").remove();}
614  var valid = false;
615  if($field.data("validate") && $field.is(":visible")) {
616    console.log("calling validatePhpType for field "+$field.attr("name"));
617    valid = validatePhpType($field,$field.data("validate"));
618  }
619  else if($field.attr("required") && $field.is(":visible")) {
620    if($field.attr("type")=="radio") {
621      //if($field.parent().prev("td").find('.help-block').length>0) {$field.parent().prev("td").find('.help-block').remove();}
622      /*var radios = $("[name="+$field.attr("name").replace( /(:|\.|\[|\]|,|=|@)/g, "\\$1" )+"]");
623      for(var r in radios) {
624        if($field.is(':checked')) { valid = true; }        
625      }*/
626      var checkedVal = $("input[name="+$field.attr("name").replace( /(:|\.|\[|\]|,|=|@)/g, "\\$1" )+"]:checked").val();
627      valid = checkedVal == "1" || checkedVal == "0";
628      if($field.parent().prop("tagName")=="TD") {
629        if($field.parent().prev("td").find('.help-block').length<1) {$('<span class="help-block"></span>').appendTo($field.parent().prev("td"));}
630	      $field.parent().parent().toggleClass("text-danger",!valid);
631        $field.parent().parent().toggleClass("has-success",valid);
632        if(!valid) {
633          //$('<span class="help-block">&Egrave; obbligatorio specificare una risposta.</span>').appendTo($field.parent().prev("td"));
634          $field.parent().prev("td").find(".help-block").html("&Egrave; obbligatorio specificare una risposta.");
635        } else {
636          $field.parent().prev("td").find(".help-block").html("Risposta impostata correttamente.");
637        }
638      } else {
639	      if($field.parent().prev("td").find('.help-block').length>0) {$field.parent().prev("td").find('.help-block').remove();}
640        $field.parent().toggleClass("text-danger",!valid);
641        $field.parent().toggleClass("has-success",valid);
642        if(!valid) {
643          $('<span class="help-block">&Egrave; obbligatorio scegliere un\'opzione.</span>').insertAfter($field);
644        }
645      }
646    } else {
647      valid = $field.val()!="" && $field.val()!=null;
648      if($field.next('.help-block').length>0) {$field.next('.help-block').remove();}
649      if($field.parent().parent().find(".help-block").length>0) {$field.parent().parent().find(".help-block").remove();}
650      if($field.parent().hasClass("input-group")) {
651        $field.parent().parent().toggleClass("text-danger",!valid);
652        $field.parent().parent().toggleClass("has-success",valid);
653        if(!valid) {
654          $('<span class="help-block">Questo campo &egrave; obbligatorio.</span>').insertAfter($field.parent());
655        }
656      } else {
657        $field.parent().toggleClass("text-danger",!valid);
658        $field.parent().toggleClass("has-success",valid);
659        if(!valid) {
660          $('<span class="help-block">Questo campo &egrave; obbligatorio.</span>').insertAfter($field);
661        }
662      }
663    }
664  }
665  else {
666    valid = true;
667    if($field.parent().hasClass("input-group")) {
668      $field.parent().parent().toggleClass("text-danger",!valid);
669      $field.parent().parent().toggleClass("has-success",valid);
670    } else {
671      $field.parent().toggleClass("text-danger",!valid);
672      $field.parent().toggleClass("has-success",valid);
673    }
674  }
675  
676  $field.data( "is-valid", valid );
677
678  if(valid && $field.data("field-callback")) {
679    if($field.parent().hasClass("input-group")) {
680      $field.parent().parent().removeClass("text-danger");
681      $field.parent().parent().removeClass("has-success");
682    } else {
683      $field.parent().removeClass("text-danger");
684      $field.parent().removeClass("has-success");
685    }
686    $field.trigger($field.data("field-callback"));
687  }
688
689  return valid;
690}
691
692function validatePhpType($field, type) {
693  var value = $field.val().replace("C:\\fakepath\\","");
694  var valid = false;
695  var required = $field.attr("required");
696  var minLength = $field.data("min-length");
697  var maxLength = $field.data("max-length");
698  var maxSize = $field.data("max-size");
699  var fixedLength = $field.data("fixed-length");
700  var notFuture = $field.data("not-future");
701  var warning = $field.data("error-type")&&$field.data("error-type")=="warning";
702  var message = "";
703  
704  if(required && value == "") {
705    valid = false;
706    warning = false;
707    message = "&egrave; obbligatorio";
708  }
709  else if(required && value != "" && type=="money" && isNumber(value) && ( ( $field.data("allow-zero") && value.replace(".","").replace(",",".") < 0 ) || ( !$field.data("allow-zero") && value.replace(".","").replace(",",".")<=0) )) {
710    valid = false;
711    warning = false;
712    message = $field.data("allow-zero")?"non pu&ograve; essere negativo":"dev'essere maggiore di 0";
713  }
714  else if(!required && value == "") {
715    valid = true;
716  }
717  else if(value != "" && minLength && value.length<minLength) {
718    valid = false;
719    message = "deve contenere almeno "+minLength+" caratteri";
720  }
721  else if(value != "" && maxLength && value.length>maxLength) {
722    valid = false;
723    message = "non pu&ograve; contenere pi&ugrave; di "+maxLength+" caratteri";
724    if(warning) { message += ".<br>Proseguendo i caratteri eccessivi verranno troncati"; }
725  }
726  else if(value != "" && fixedLength && value.length!=fixedLength) {
727    valid = false;
728    message = "deve contenere "+fixedLength+" caratteri";
729  }
730  else {
731    switch(type) {
732      case "piva":
733        valid = /^\d{11}$/.test(value);
734        message = "non contiene una Partita IVA valida";
735        break;
736      case "cf":
737        var sesso = $('#'+$field.data('sesso-field')).val();
738        var validCF =  isCodiceFiscale(value, $('#'+$field.data('nascita-field')).val(), sesso);
739        var validCFformat = /^[A-Z]{6}[\dLMNP-V]{2}[A-EHLMPRST][\dLMNP-V]{2}[A-Z][\dLMNP-V]{3}[A-Z]$/.test(value);
740        valid = validCF;
741        if(warning && !valid && !validCFformat) {
742          warning = false;
743        }
744        message = "non contiene un codice fiscale valido";
745	    break;
746      case "cforpiva":
747        if($('#'+$field.data('sesso-field')).length==0) {
748          // non avendo specificato il sesso, non possiamo sapere se è persona fisica o giuridica o ditta individuale (ad es. partecipante benefici)
749          var validCF = isCodiceFiscale(value,false, false);
750          var validPiva = /^\d{11}$/.test(value);
751          var validCFformat = /^[A-Z]{6}[\dLMNP-V]{2}[A-EHLMPRST][\dLMNP-V]{2}[A-Z][\dLMNP-V]{3}[A-Z]$/.test(value);
752          valid = validPiva || validCF;
753          // warning è sempre a true perchè non posso determinare il tipo (cf o piva)
754        } else {
755          var sesso = $('#'+$field.data('sesso-field')).val();
756          var validPFCF = isCodiceFiscale(value, $('#'+$field.data('nascita-field')).val(), sesso);
757          var validPiva = /^\d{11}$/.test(value);
758          var validCFformat = /^[A-Z]{6}[\dLMNP-V]{2}[A-EHLMPRST][\dLMNP-V]{2}[A-Z][\dLMNP-V]{3}[A-Z]$/.test(value);
759          var personaFisica = !sesso || (["M", "F"].indexOf(sesso)>-1);
760          var personaGiuridica = sesso == "G";
761          valid = (!personaFisica && validPiva) || (personaGiuridica && validPiva) || ((personaFisica||!personaGiuridica) && validPFCF);
762          if(warning && !valid && (personaFisica && !validCFformat) && (personaGiuridica && !validPiva) && (!personaGiuridica && !personaFisica && !validPiva  && !validCFformat)) {
763            warning = false;
764          }
765        }
766        message = "non contiene un codice fiscale o una p.iva valida";
767        break;
768      case "cforpiva_length":
769        valid = value.length==11 || value.length==16;
770        message = "deve contenere 11 o 16 caratteri";
771        break;
772      case "number":
773        valid = /^\d+$/.test(value);
774        message = "deve contenere un numero valido";
775        break;
776      case "alphanumeric":
777        valid = /^[a-zA-Z0-9]+$/.test(value);
778        message = "puo' contenere solo lettere e numeri";
779        break;
780      case "string":
781        valid = /^[a-zA-Z0-9 \.\-&"\u00C0-\u017F]+$/.test(value);
782        message = "puo' contenere solo lettere, lettere accentate, numeri, spazi, . - \" e &";
783        break;
784      case "email":
785        valid = emailIsValid(value);
786        message = "deve contenere un indirizzo email valido";
787        break;
788      case "money":
789        valid = isNumber(value);
790        message = "deve contenere un importo valido";
791        break;
792      case "filesize":
793        var notZeroSize = isNotZeroSize($field);
794        if(!notZeroSize) {
795          valid = false;
796          message = "deve contenere un file di dimensioni maggiori di 0 byte";
797        } else {
798          if(maxSize) {
799            valid = isBelowMaxSize($field, maxSize);
800            if(!valid) {
801              message = "contiene un file troppo grande. Le dimensioni massime consentite sono di "+((maxSize / 1048576).toFixed(0))+ "MB ("+maxSize+" byte)";
802            }
803          } else {
804            valid = true;
805          }
806        }
807        break;
808      case "filename":
809        var filenameOk = isFilename(value);
810        var sizeOk = isNotZeroSize($field);
811        valid = filenameOk && sizeOk;
812        message = !sizeOk?"deve contenere un file di dimensioni maggiori di 0 byte":"pu&ograve; contenere solo un nome file composto da lettere non accentate, numeri, punti singoli, trattini ed underscore (trattino basso). Non vengono accettati caratteri accentati, simboli, doppi punti, spazi e caratteri speciali";
813        if(warning && sizeOk) { message += ".<br>I caratteri non validi verranno eliminati automaticamente"; }
814        break;
815      case "extension":
816        var sizeOk = isNotZeroSize($field);
817        valid = sizeOk;
818        // non faccio il warning sul filename che tanto viene rinominato automaticamente
819        // var filenameOk = isFilename(value);
820        // valid = filenameOk && sizeOk;
821        // message = !sizeOk?"deve contenere un file di dimensioni maggiori di 0 byte":"pu&ograve; contenere solo un nome file composto da lettere non accentate, numeri, punti singoli, trattini ed underscore (trattino basso). Non vengono accettati caratteri accentati, simboli, doppi punti, spazi e caratteri speciali";
822        // if(sizeOk && !filenameOk) { warning = true; message += ".<br>I caratteri non validi verranno eliminati automaticamente"; }
823        if(valid) {
824          var hasExtension = RegExp(/^(.*?)((?:\.[a-zA-Z0-9]{2,4})|(?:\.p7m|\.m7m)|(?:\.[a-zA-Z0-9]{2,4})(?:\.p7m|\.m7m))$/i);
825          if(hasExtension.test(value)) {
826            valid = hasValidExtension(value);
827            message = "deve contenere un file con una doppia estensione se il file &egrave; firmato digitalmente (ad esempio filefirmato.pdf.p7m)";
828          } else {
829            valid = false;
830            message = "non pu&ograve; contenere file senza estensione";
831          }
832        } else {
833          message = "deve contenere un file di dimensioni maggiori di 0 byte";
834        }
835	      break;
836      case "date":
837        valid = isDate(value, notFuture);
838        message = "deve contenere una data valida";
839        break;
840      default:
841        valid = true;
842        break;
843    }
844  }
845
846  if($field.parent().hasClass("input-group")) {
847    $field.parent().parent().toggleClass("has-success",valid);
848    $field.parent().parent().toggleClass("has-warning",!valid&&warning);
849    $field.parent().parent().toggleClass("text-danger",!valid&&!warning);
850    if(!valid) {
851      $('<span class="help-block">Questo campo '+message+'.</span>').insertAfter($field.parent());
852    }
853  } else {
854    $field.parent().toggleClass("has-success",valid);
855    $field.parent().toggleClass("has-warning",!valid&&warning);
856    $field.parent().toggleClass("text-danger",!valid&&!warning);
857    if(!valid) {
858      $('<span class="help-block">Questo campo '+message+'.</span>').insertAfter($field);
859    }
860  }
861  if(warning&&!valid){valid = warning;}
862  return valid;
863}
864
865// mi salvo qui callback, altrimenti diventa undefined tempo che facciamo il submit del form 
866var savedCallback;
867function validateForm($form, callback) {
868  if(typeof callback === typeof undefined) { callback = false; }
869  $form.find(".has-success").removeClass("has-success");
870  $form.find(".has-warning").removeClass("has-warning");
871  $form.find(".text-danger").removeClass("text-danger");
872  var formIsValid = true;
873  $form.find('input, select, textarea').each(function() {
874    if(typeof($(this).attr("id")) != "undefined" && $(this).is(":visible")) {
875      if(!validate($(this))){formIsValid=false;}
876    }
877  });
878  var warnings = $form.find(".has-warning").length;
879  console.log("Form is valid: "+formIsValid);
880  console.log("Warnings: "+warnings);
881 
882  if(!formIsValid) {
883    // se ci sono errori nel form interrompo l'esecuzione del submit ancora prima di verificare callback
884    bootbox.alert("I dati inseriti contengono degli errori.", function(){
885      var addOffset = 0;
886      if($('#header_border_fixed').length) {
887        addOffset = $('#header_border_fixed').height()+20;
888      }
889      var offset = $form.find(".text-danger").first().length?$form.find(".text-danger").first().offset().top-addOffset:0;
890      $('html, body').animate({scrollTop: offset}, 200);
891    })
892    return false;
893  } else {
894    // nessun errore sul form, verifichiamo callback
895    var callbackResult = {result: true, message: ""};
896    console.log("check callback function "+callback);
897    if(callback) { 
898      console.log("callback function "+callback+" exists");
899      callbackResult = callback();    
900    } else {
901      console.log("callback function "+callback+" is not a valid callback");
902    }
903    formIsValid = formIsValid && callbackResult.result;
904    var message = callbackResult.message && callbackResult.message!=""?callbackResult.message:"Si &egrave; verificato un errore.";
905    console.log("Callback result: "+callbackResult.result);
906    if(!formIsValid && callbackResult.result===false) {
907      console.log("Showing error message for !formIsValid (after callback)");
908      bootbox.alert(message, function(){ }); 
909      return false;
910    }
911    
912    /*if(!formIsValid) {
913      bootbox.alert("I dati inseriti contengono degli errori.", function(){ 
914	var addOffset = 0;
915	if($('#header_border_fixed').length) {
916	  addOffset = $('#header_border_fixed').height()+20;
917	}
918        var offset = $form.find(".text-danger").first().length?$form.find(".text-danger").first().offset().top-addOffset:0;
919	$('html, body').animate({scrollTop: offset}, 200);	
920      });   
921      return false;
922    }*/
923    else { 
924      // nessun errore anche su callback, verifichiamo i warning
925      console.log("Warnings: "+warnings);
926      if(warnings) {
927        console.log("Showing force dialog");
928        bootbox.dialog({
929          message: "Attenzione: i dati inseriti non risultano corretti. Proseguire comunque?",
930          buttons: {
931            "force": {
932              label: "Forza inserimento",
933              className: "btn-default",
934              callback: function() { console.log("Force dialog closing and forcing"); $form.trigger('submit', true); }
935            },
936            "fix": {
937              label: "Modifica dati",
938              className: "btn-primary",
939              callback: function() { 
940                console.log("Force dialog closing and staying");
941                var addOffset = 0;
942                if($('#header_border_fixed').length) {
943                  addOffset = $('#header_border_fixed').height()+20;
944                }
945                $('html, body').animate({scrollTop: $form.find(".has-warning").first().offset().top-addOffset}, 200);  
946              }
947            }
948          }
949        });	
950	      return false; // restituisco sempre false perchè bootbox non interrompe il processo in attesa di user input
951      	// eventualmente faccio il submit se l'utente decide di forzare
952      }
953      else {  return true; }
954    }
955  }
956}
957
958function hasValidExtension(fileName) {
959  var fileNameSplit = fileName.split("\\");
960  if(fileNameSplit.length<2) {
961    fileNameSplit = fileName.split("/");
962  }
963  fileName = fileNameSplit[fileNameSplit.length-1];
964  
965  var signed = RegExp(/(?:\.p7m|\.m7m)$/i);
966  var valid = true;
967  if(signed.test(fileName)) {
968    /*var validSignedExt = RegExp(/^(.*?)((?:\.[a-zA-Z0-9]{2,3})(?:\.p7m|\.m7m))$/i);
969    valid = validSignedExt.test(fileName);*/
970    var validSignedExt = /^(?:.*?)(?:\.([a-zA-Z0-9]{2,4})){1}(?:\.(p7m|m7m)){1}$/i;
971    var matches = fileName.match(validSignedExt);
972    if(matches && matches.length>1) {
973      valid = matches[1] != "p7m" && matches[1] != "m7m";
974    } else {
975      valid = false;
976    }
977  }
978  
979  return valid;
980}
981
982
983function isFilename(fileName) {
984  var fileNameSplit = fileName.split("\\");
985  if(fileNameSplit.length<2)
986  {
987    fileNameSplit = fileName.split("/");
988  }
989  fileName = fileNameSplit[fileNameSplit.length-1];
990  
991  var regex = RegExp(/^[a-zA-Z_\.\-0-9]*$/);
992  var regex2 = RegExp(/\.{2,}/);
993  
994  return regex.test(fileName)&&!regex2.test(fileName);
995}
996
997function isBelowMaxSize($field, maxSize) {
998  var belowMaxSize = false;
999  if(!window.FileReader) {
1000    // impossibile leggere il file
1001  }
1002  var input = $field[0];
1003  if (!input) {
1004    // impossibile leggere il file
1005  }
1006  else if (!input.files) {
1007    // impossibile leggere il file
1008  }
1009  else if (!input.files[0]) {
1010    // impossibile leggere il file
1011  }
1012  else {
1013    file = input.files[0];
1014    belowMaxSize = file.size<=maxSize;
1015  }
1016  return belowMaxSize;
1017}
1018
1019function isNotZeroSize($field) {
1020  var notZeroSize = false;
1021  if(!window.FileReader) {
1022    notZeroSize = true;
1023  }
1024  var input = $field[0];
1025  if (!input) {
1026    notZeroSize = true;
1027  }
1028  else if (!input.files) {
1029    notZeroSize = true;
1030  }
1031  else if (!input.files[0]) {
1032    notZeroSize = true;
1033  }
1034  else {
1035    file = input.files[0];
1036    notZeroSize = file.size>0;
1037  }
1038  return notZeroSize;
1039}
1040
1041function isCodiceFiscale(cf, dataNascita, sesso) {
1042  var str = cf.replace(/\s/g,'').toUpperCase(); // converte in maiuscolo e rimuove spazi bianchi
1043  
1044  if(cf.length!=16) {
1045    return false;
1046  }
1047  
1048  // verifica formato
1049  if(!/^[A-Z]{6}[\dLMNP-V]{2}[A-EHLMPRST][\dLMNP-V]{2}[A-Z][\dLMNP-V]{3}[A-Z]$/.test(str)) {
1050    return false;
1051  }
1052  
1053  // verifica vocali/consonanti in nome/cognome
1054  var re = /^[^AEIOU]*[AEIOU]*X*$/;
1055  if(!re.test(str.substr(0,3)) || !re.test(str.substr(3,3))) {
1056    return false;
1057  }
1058  
1059  // verifica data
1060  var day = str.substr(9,2);
1061  // TODO: gestire anni di nascita > 1999?
1062  var year = '19'+str.substr(6,2);
1063  
1064  var female = false;  
1065  if(day > 31){day = day -40; female = true;}
1066  
1067  var months = 'ABCDEHLMPRST';  
1068  var month = months.indexOf(str.charAt(8));
1069  if(dataNascita) {
1070    var dateString = day+'/'+(month+1)+'/'+year;
1071    
1072    if(!isDate(dateString)) {
1073      return false;
1074    }
1075  }
1076  
1077  // verifica corrispondenza date nascita
1078  var cfDate = new Date(year, month, day, 0,0,0,0);
1079  if(dataNascita) {
1080    var data = dataNascita.split('/');
1081    var birthDate = new Date(data[2], data[1]-1, data[0], 0, 0, 0, 0);
1082    
1083    if(cfDate.getTime() != birthDate.getTime()) {
1084      return false;
1085    }
1086  }
1087  
1088  // verifica corrispondenza sesso
1089  if(!sesso || (["M", "F"].indexOf(sesso)<0) || sesso == 'F' && female || sesso == 'M' && !female) {
1090    // ok
1091  } else {
1092    return false;
1093  }
1094  
1095  // verifica codice controllo (converte numeri in lettere e calcola checksum)
1096  str = str.replace(/\d/g, function(c) { return 'ABCDEFGHIJ'[c]; });
1097  
1098  for(var s=str.charCodeAt(15),i=1;i<15;i+=2) {
1099    s -= str.charCodeAt(i);
1100  }
1101  for(i=0;i<15;i+=2) {
1102    s -= 'BAFHJNPRTVCESULDGIMOQKWZYX'.charCodeAt(str.charCodeAt(i)-65);
1103  }
1104  
1105  return Math.abs(s%26) == 0;
1106}
1107
1108function isNumber(n) {
1109  var nIT = n.replace(".","").replace(",",".");
1110  var numeroIT = !isNaN(parseFloat(nIT)) && isFinite(nIT);
1111  var numeroEN = !isNaN(parseFloat(n)) && isFinite(n);
1112  return (numeroIT && isFinite(numeroIT)) || (numeroEN && isFinite(numeroEN));
1113}
1114
1115function emailIsValid(email) {
1116  var isValid = false;
1117  var user, domain;
1118  var emailsplit = email.split('@');
1119  if(emailsplit.length == 2) {
1120    user = emailsplit[0];
1121    domain = emailsplit[1];
1122    if(domain.indexOf('.')>-1) {
1123      isValid = true;
1124    }
1125  }
1126  return isValid;
1127}
1128
1129function isDate(dateString, notFuture) {
1130  var data = dateString.split('/');
1131  var dataDate = new Date(data[2], data[1]-1, data[0], 0, 0, 0, 0);
1132  var nowDate = new Date();
1133  var dataMonth = data[1] - 1;
1134  var dataDateMonth = dataDate.getMonth();
1135  var validDay = data[0] == dataDate.getDate();
1136  var validMonth = data[1] - 1 == dataDate.getMonth();
1137  var validYear = data[2] == dataDate.getFullYear() && dataDate.getFullYear() >= 1900;
1138  return validDay && validMonth && validYear && (!notFuture || (notFuture && dataDate.getTime() < nowDate.getTime()));
1139}
1140
1141function tableToUl($table){
1142  if($table.is("table")){
1143      var $ul=$("<ul>");
1144      var empty=$table.find("td").length<1;
1145      var balanceColumns=false;
1146      $ul.addClass($table.attr("class"));
1147      if($table.find("[class^=cell-wide]").length==0){
1148          $table.find("td").addClass("cell-wide");
1149          balanceColumns=true
1150      }else{$ul.addClass("no-filler")}
1151      $ul.attr("id",$table.attr("id"));
1152      if($ul.attr("id")==""||typeof($ul.attr("id"))=="undefined"){
1153          $ul.attr("id",$table.find("tbody").attr("id"))
1154      }
1155      if($ul.attr("id")==""||typeof($ul.attr("id"))=="undefined"){
1156          var index=-1;
1157          for(var i=0;i<$allResponsiveTables.length;i++){
1158              if($table.is($allResponsiveTables[i])){index=i}
1159          }if(index>-1){$ul.attr("id","table_"+index)}
1160      }
1161      var columns=[];
1162      var htmlColumns=[];
1163      var $allTableHeaders=$table.find("tr:has(th)");
1164
1165      $allTableHeaders.each(function(){
1166          var $li=$("<li>");
1167          if($(this).find("th").length==1){
1168              $li.addClass("table-caption");
1169              $li.html($(this).find("th").html())
1170          }else{
1171              $li.addClass("table-header");
1172              $li.addClass($(this).attr("class"));
1173              $(this).find("th").each(function(){
1174                  var $div=$("<div>"+$(this).html()+"</div>");
1175                  columns.push($(this).text());
1176                  var $link=$(this).find("a");
1177                  if($link.length>0){
1178                      htmlColumns.push($(this).html());
1179                      $link.addClass("btn btn-default");
1180                      $table.parent().find(".mobile-sorting").append($link)
1181                  }
1182                  $li.append($div)
1183              });
1184              if(empty){
1185                  $li.find("div").css("width",((100/columns.length)*1.1)+"%")
1186              }
1187          }
1188          $li.appendTo($ul)
1189      });
1190      $ul.insertBefore($table);
1191      var $tbody=$table.find("tbody");
1192      $table.find("tfoot tr").each(function(){
1193          $(this).appendTo($tbody)});
1194          if(!empty){
1195              var largestCol=rowsToLi($tbody,$ul,columns,balanceColumns);
1196              setCellWidths(largestCol,columns,$ul)
1197          }
1198          if($ul.find("li:not(.table-header)").find("a").length<1){
1199              $ul.removeClass("row_linked")
1200          }if($(".page_navigation.pagination.pagination-desktop").length<1){
1201              $(".page_navigation.pagination").addClass("pagination-desktop");
1202              $(".sel_pagine").addClass("sel_pagine-desktop");
1203              var $loadMore=$('<a class="btn btn-default btn-block">Carica altri</a>');
1204              $loadMore.click(function(){
1205                  $(this).hide();
1206                  $(this).parent().append('<i class="fa fa-circle-o-notch fa-spin fa-3x fa-fw muted"></i><span class="sr-only">Caricamento...</span>');
1207                  find(".fa-spin").remove();
1208                  $hiddenRows.slice(0,show_per_page).show();
1209                  var $hiddenRows=$container.find(".pagination_content .paginated_element:hidden");
1210                  if($hiddenRows.length>0){
1211                      $(this).show()
1212                  }
1213              });
1214              if($ul.find(".paginated_element:hidden").length>0){
1215                  if($(".pagination-mobile-loadmore").length<1){
1216                      $('<div class="pagination-mobile pagination-mobile-loadmore"></div>').insertAfter($ul)
1217                  }
1218                  $(".pagination-mobile-loadmore").append($loadMore)
1219              }
1220          }
1221          if($table.is("table")){
1222              $table.remove()
1223          }
1224      }
1225  }
1226
1227/**
1228* 
1229* @param {any} campoParam 
1230* @param {string} alertMsg
1231*/
1232function disableCampo(campoParam, alertMsg) {
1233  const campoToDisable = getCampo(campoParam);
1234
1235  if (!campoToDisable) {
1236    return;
1237  }
1238
1239  campoToDisable.attr('disabled', 'disabled');
1240  if (alertMsg) {
1241    addAlertInfo(alertMsg, campoToDisable.parent());
1242  }
1243  campoToDisable.val(null);
1244}
1245
1246/**
1247 * 
1248 * @param {any} campoParam 
1249 */
1250function enableCampo(campoParam) {
1251
1252  const campoToEnable = getCampo(campoParam);
1253
1254  if (!campoToEnable) {
1255    return;
1256  }
1257
1258  campoToEnable.removeAttr('disabled');
1259  campoToEnable.parent().find('.alert').remove();
1260}
1261
1262function getCampo(campoParam) {
1263
1264  if (typeof campoParam === 'string') {
1265
1266    if (!campoParam || campoParam.length === 0) {
1267      return;
1268    }
1269
1270    if (campoParam.includes('#')) {
1271      return $(campoParam);
1272
1273    } else {
1274      return $('#' + campoParam);
1275    }
1276  } else if (campoParam instanceof jQuery) {
1277    return campoParam;
1278  }
1279
1280}

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.