1 2 window.fc_init_hide_dependent = 1; 3 window.fc_refreshing_dependent = 0; 4 window.fc_dependent_params = {}; 5 window.fc_cascade_field_funcs = {}; 6 window.fc_Dialogs = {}; 7 8 function fc_getAutoSizePos(winwidth, winheight, params) 9 { 10 var maxWidth = typeof winwidth === 'undefined' ? 0 : winwidth; 11 var maxHeight = typeof winheight === 'undefined' ? 0 : winheight; 12 13 var paddingW = (!!params && !!params.paddingW ? params.paddingW : 70); 14 var paddingH = (!!params && !!params.paddingH ? params.paddingH : 120); 15 16 var visibleWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; 17 var visibleHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; 18 19 var w = maxWidth ? maxWidth : visibleWidth - paddingW; 20 var h = maxHeight ? maxHeight : visibleHeight - paddingH; 21 22 // Add fixed scrolling class and ... also add auto-width / auto-height classes so dimensions are treated as MAX values 23 params.dialogClass = typeof params.dialogClass !== 'undefined' ? params.dialogClass : 'fc-fixed-dialog'; 24 params.dialogClass += ' fc-autow-dialog'; 25 params.dialogClass += ' fc-autoh-dialog'; 26 27 if (visibleWidth < 600 || visibleHeight < 600) 28 { 29 params.winwidth = w > (visibleWidth - 10) ? (visibleWidth - 10) : w; 30 params.winheight = h > (visibleHeight - 10) ? (visibleHeight - 10) : h; 31 } 32 else 33 { 34 params.winwidth = w > (visibleWidth - paddingW) ? (visibleWidth - paddingW) : w; 35 params.winheight = h > (visibleHeight - paddingH) ? (visibleHeight - paddingH) : h; 36 } 37 //window.console.log ('winwidth : ' + params.winwidth + ', winheight : ' + params.winheight ); 38 39 params.winleft = (visibleWidth - params.winwidth) / 2 - 5; 40 params.wintop = (visibleHeight - params.winheight) / 2 - 5; 41 //window.console.log ('winleft : ' + params.winleft + ', wintop : ' + params.wintop); 42 43 return params; 44 } 45 46 47 function fc_loadImagePreview(input_id, img_id, msg_id, thumb_w, thumb_h, nonimg_mssg) 48 { 49 var nonimg_mssg = typeof nonimg_mssg !== 'undefined' ? nonimg_mssg : ''; 50 var input = document.getElementById(input_id); 51 var msg_box = document.getElementById(msg_id); 52 var _msg = ''; 53 54 var input_files = input.files; 55 56 if (input_files && input_files[0]) 57 { 58 var imageType = /image.*/; 59 60 if (!input_files[0].type.match(imageType)) 61 { 62 if (nonimg_mssg=='-1') _msg = ''; 63 else if (nonimg_mssg=='-2') _msg = input.value; 64 else if (nonimg_mssg=='0' || nonimg_mssg=='') _msg = (nonimg_mssg!='' ? nonimg_mssg : input.value+' <br/> '+Joomla.JText._('FLEXI_NOT_AN_IMAGE_FILE')); 65 jQuery('#'+img_id).hide(); 66 } 67 else 68 { 69 if (nonimg_mssg=='-2' || nonimg_mssg=='0') _msg = input.value; 70 else _msg = ''; 71 var reader = new FileReader(); 72 reader.onload = function (e) { 73 var img = jQuery('#'+img_id); 74 img.attr('src', e.target.result); 75 if (thumb_w) parseInt(thumb_w) ? img.width(thumb_w) : img.css('width', thumb_w); 76 if (thumb_h) parseInt(thumb_h) ? img.height(thumb_h) : img.css('height', thumb_h); 77 img.show(); 78 }; 79 reader.readAsDataURL(input_files[0]); 80 } 81 } 82 msg_box.nodeName == 'INPUT' ? msg_box.value = input.value : msg_box.innerHTML = input.value; 83 } 84 85 86 // Display content in modal popup 87 function fc_showAsDialog(obj, winwidth, winheight, closeFunc, params) 88 { 89 params = typeof params !== 'undefined' ? params : {}; 90 params = fc_getAutoSizePos(winwidth, winheight, params); 91 92 // Make it jQuery object if it is not already 93 obj = jQuery(obj); 94 95 // Get close function 96 closeFunc = typeof closeFunc !== 'undefined' && closeFunc ? closeFunc : 0; 97 var keepPlace = !!params.keepPlace; 98 var visibleOnClose = !!params.visibleOnClose; 99 100 // Because allowing moving modal to be moved out of form (under body), we need to set form ATTRIBUTE to form, for any form elements inside it 101 if (!keepPlace) 102 { 103 var form_fields = obj.find('textarea, select, input, button').toArray(); 104 for ( var i = 0, l = form_fields.length; i < l; i++ ) 105 { 106 // Get field type / tag name 107 var $el = jQuery(form_fields[i]); 108 var form = form_fields[i].form; 109 if (form && form.id && !$el.attr('form')) 110 { 111 $el.attr('form', form.id); 112 } 113 } 114 } 115 116 var parent = obj.parent(); 117 var theDialog = obj.dialog({ 118 title: params.title, 119 closeOnEscape: (typeof params.closeOnEscape !== 'undefined' ? params.closeOnEscape : true), 120 resize: false, 121 autoOpen: false, 122 width: params.winwidth, 123 height: params.winheight, 124 //position: { at: 'center' }, 125 modal: (typeof params.modal !== 'undefined' ? params.modal : true), 126 dialogClass: params.dialogClass, 127 icons: { 128 primary: "ui-icon-heart" 129 }, 130 buttons: { 131 /*'Close': function() { jQuery(this).dialog('close'); }*/ 132 }, 133 open: function(ev, ui){ 134 // Fix for Pagebuilder CK modifying not-owned modals 135 jQuery('.ui-widgetck .ui-dialog-titlebar-close > .ui-icon').removeClass('ui-widgetck-overlay').css('top', '0').css('left', '0'); 136 jQuery('.ui-widgetck').removeClass('ui-widgetck').addClass('ui-widget fc-no-scroll'); 137 jQuery('.ui-widgetck-content').removeClass('ui-widgetck-content').addClass('ui-widget-content'); 138 jQuery('.ui-widgetck-header').removeClass('ui-widgetck-header').addClass('ui-widget-header'); 139 jQuery('.ui-widgetck-overlay').removeClass('ui-widgetck-overlay').addClass('ui-widget-overlay').css('z-index', '2049').css('position', 'fixed'); 140 141 // Close on click outside of modal popup 142 if (typeof params.closeOnOutClick !== 'undefined' ? params.closeOnOutClick : true) { 143 jQuery('.ui-widget-overlay, .pac-container').bind('click', function () { 144 obj.dialog('close'); 145 }); 146 } 147 }, 148 // Clear contents after dialog closes 149 close: function(ev, ui) 150 { 151 // Allow parent document to scroll again 152 var bodyTag = jQuery(this).closest('body'); 153 var fc_modal_count = parseInt(bodyTag.data('fc_modal_count')); 154 bodyTag.data('fc_modal_count', --fc_modal_count); 155 156 if (fc_modal_count == 0) 157 { 158 bodyTag.removeClass('fc-no-scroll'); 159 } 160 161 // Destroy the dialog completely, this is needed because we have moved the content back into its proper position 162 jQuery(this).dialog('destroy'); 163 164 // Allow CSS class to apply 165 if (visibleOnClose) obj.css({'height': '', 'width': '', 'display': '', 'visibility': ''}); 166 167 // Finalize by doing the closing operation 168 if (typeof closeFunc === 'function') closeFunc(obj); 169 else if (closeFunc == 1) window.location.reload(false); 170 else if (closeFunc == 0) ; 171 else alert('Unknown action'+closeFunc); 172 } 173 }) 174 .dialog('widget').next('.ui-widget-overlay').css('background', 'gray'); // Add an overlay 175 176 // Manually move the dialog content back into its proper position, (the extra dialog container will be destroyed on dialog close) 177 if (keepPlace) obj.parent().appendTo(parent); 178 179 // Force manual position of dialog 180 obj.parent().css({ 'left': params.winleft+'px', 'width': params.winwidth+'px', 'top': params.wintop+'px'}); 181 182 // Open the dialog manually 183 theDialog = obj.dialog('open'); 184 185 // Add modal's data to the data of the parent of the HTML container: max-width, max-height, params, dialog reference 186 theDialog.data('fc_dialog_params', params); 187 theDialog.data('fc_dialog_maxwidth', winwidth); 188 theDialog.data('fc_dialog_maxheight', winheight); 189 obj.parent().data('fc_dialog', theDialog); 190 191 // Stop scrolling of parent document 192 var bodyTag = obj.closest('body'); 193 var fc_modal_count = !! bodyTag.data('fc_modal_count') ? parseInt(bodyTag.data('fc_modal_count')) : 0; 194 bodyTag.data('fc_modal_count', ++fc_modal_count); 195 bodyTag.addClass('fc-no-scroll'); 196 197 // Return a reference of the dialog to the caller 198 return theDialog; 199 } 200 201 202 // Load given URL in an open dialog 203 function fc_showDialog(url, tagid, no_iframe, winwidth, winheight, closeFunc, params) 204 { 205 params = typeof params !== 'undefined' ? params : {}; 206 params = fc_getAutoSizePos(winwidth, winheight, params); 207 208 var loadFunc = typeof params.loadFunc !== 'undefined' && params.loadFunc ? params.loadFunc : false;
209 210 // Get close function 211 var closeFunc = typeof closeFunc !== 'undefined' && closeFunc ? closeFunc : 0; 212 213 // Get container creating it if it does not exist 214 var container = jQuery('#'+tagid); 215 if (!container.length) 216 { 217 container = jQuery('<div id="'+tagid+'"></div>').appendTo(document.body); 218 } 219 220 // Get loading animation tag, creating it if it does not exist, (re)showing if it is exists 221 var loading = jQuery('#'+tagid+'_loading'); 222 if (!loading.length) 223 { 224 loading = jQuery('<div id="'+tagid+'_loading" class="fc_loading_msg" style="position:absolute; background-color:transparent;">loading...</div>'); 225 container.prepend(loading); 226 } 227 else loading.show(); 228 229 // Add the iframe 230 var iframe; 231 if (!no_iframe) 232 { 233 iframe = jQuery('<iframe id="'+tagid+'_frame" style="visibility:hidden; width:100%; height:100%; border:0; margin:0; padding:0;" src=""></iframe>'); 234 container.append(iframe); 235 iframe.on('load', function() { 236 // Show retrieved contents and hide the loading animation 237 iframe.show().css('visibility', 'visible'); 238 loading.hide(); 239 240 // Remove unneeded scroll bar inside iframe document, new browser security disallows this ? 241 //iframe.contents().find('body').css({ 'height': 'unset' }); 242 }); 243 } 244 245 // Contaner CSS depending on usage of iframe 246 no_iframe ? 247 container.css('overflow', 'scroll') : 248 container.css('overflow', 'hidden').css('padding', '0') ; 249 250 // Initialize popup container 251 container.dialog({ 252 title: params.title, 253 closeOnEscape: (typeof params.closeOnEscape !== 'undefined' ? params.closeOnEscape : false), 254 autoOpen: false, 255 width: params.winwidth, 256 height: params.winheight, 257 modal: (typeof params.modal !== 'undefined' ? params.modal : true), 258 //position: { at: 'center' }, 259 dialogClass: params.dialogClass, 260 // Load contents (url) when dialog opens 261 open: function(ev, ui){ 262 no_iframe ? 263 container.load(url) : 264 jQuery('#'+tagid+'_frame').attr('src', url); 265 266 // Fix for Pagebuilder CK modifying not-owned modals 267 jQuery('.ui-widgetck .ui-dialog-titlebar-close > .ui-icon').removeClass('ui-widgetck-overlay').css('top', '0').css('left', '0'); 268 jQuery('.ui-widgetck').removeClass('ui-widgetck').addClass('ui-widget fc-no-scroll'); 269 jQuery('.ui-widgetck-content').removeClass('ui-widgetck-content').addClass('ui-widget-content'); 270 jQuery('.ui-widgetck-header').removeClass('ui-widgetck-header').addClass('ui-widget-header'); 271 jQuery('.ui-widgetck-overlay').removeClass('ui-widgetck-overlay').addClass('ui-widget-overlay').css('z-index', '2049').css('position', 'fixed'); 272 273 // Close on click outside of modal popup 274 jQuery('.ui-widget-overlay, .pac-container').bind('click', function(){ 275 container.dialog('close'); 276 }); 277 }, 278 // Clear contents after dialog closes 279 close: function(ev, ui) 280 { 281 // Allow parent document to scroll again 282 var bodyTag = jQuery(this).closest('body'); 283 var fc_modal_count = parseInt(bodyTag.data('fc_modal_count')); 284 bodyTag.data('fc_modal_count', --fc_modal_count); 285 286 if (fc_modal_count == 0) 287 { 288 bodyTag.removeClass('fc-no-scroll'); 289 } 290 291 // Remove container / iframe contents (we re-use it) 292 no_iframe ? container.html('') : jQuery('#'+tagid+'_frame').remove(); 293 294 // Finalize by doing the closing operation 295 if (typeof closeFunc === 'function') closeFunc(); 296 else if (closeFunc == 1) window.location.reload(false); 297 else if (closeFunc == 0) ; 298 else alert('Unknown action'+closeFunc); 299 } 300 }); 301 302 // Force manual position of dialog 303 container.parent().css({ 'left': params.winleft+'px', 'width': params.winwidth+'px', 'top': params.wintop+'px'}); 304 305 // Open the dialog manually 306 var theDialog = container.dialog('open'); 307 fc_Dialogs[tagid] = theDialog; 308 309 // Add modal's data to the data of the parent of the HTML container: max-width, max-height, params, dialog reference 310 theDialog.data('fc_dialog_params', params); 311 theDialog.data('fc_dialog_maxwidth', winwidth); 312 theDialog.data('fc_dialog_maxheight', winheight); 313 container.parent().data('fc_dialog', theDialog); 314 315 // Attach on-load function to the iframe 316 if (!no_iframe && loadFunc) 317 { 318 jQuery('#'+tagid).find('iframe').first().on('load', function(e, data) { 319 loadFunc( container ); 320 }); 321 } 322 323 // Stop scrolling of parent document 324 var bodyTag = container.closest('body'); 325 var fc_modal_count = !! bodyTag.data('fc_modal_count') ? parseInt(bodyTag.data('fc_modal_count')) : 0; 326 bodyTag.data('fc_modal_count', ++fc_modal_count); 327 bodyTag.addClass('fc-no-scroll'); 328 329 // Return a reference of the dialog to the caller 330 return theDialog; 331 } 332 333 334 // Close given dialog 335 function fc_closeDialog(name) 336 { 337 if (!!fc_Dialogs[name]) 338 { 339 fc_Dialogs[name].dialog('close'); 340 } 341 return false;
342 } 343 344 345 // Scroll into view 346 function fc_scrollIntoView (elem, smooth) 347 { 348 var cTop = elem.offset().top; 349 var cHeight = elem.outerHeight(true); 350 var windowTop = jQuery(window).scrollTop(); 351 var visibleHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; 352 var top_extra = 90; 353 var bottom_extra = 80; 354 355 //window.console.log ('cTop: ' + cTop + ' , windowTop: ' + windowTop); 356 //window.console.log ('cHeight: ' + cHeight + ' , visibleHeight: ' + visibleHeight); 357 if (cTop - top_extra < windowTop) { 358 if (smooth) { 359 jQuery('html, body').animate({scrollTop: cTop - top_extra}, 400); 360 } else { 361 jQuery('html, body').scrollTop(cTop - top_extra); 362 } 363 } else if (cTop + cHeight + bottom_extra > windowTop + visibleHeight) { 364 if (smooth) { 365 jQuery('html, body').animate({scrollTop: cTop - visibleHeight + cHeight + bottom_extra}, 400); 366 } else { 367 jQuery('html, body').scrollTop(cTop - visibleHeight + cHeight + bottom_extra); 368 } 369 } 370 } 371 372 373 function fc_findFormDependencies(el, toggleParent, toggleParentSelector, field) 374 { 375 var seton_list = el.data('_seton_list'); // (selector comma list) show elements by selector 376 var setoff_list= el.data('_setoff_list'); // (selector comma list) hide elements by selector 377 var refsh_list = el.data('_refsh_list'); // (selector comma list) trigger change on elements 378 379 var show_list = el.data('_show_list'); // (classnames comma list) grant display dependency to elements (container shown when dependencies are zero) 380 var hide_list = el.data('_hide_list'); // (classnames comma list) revoke display dependency to elements (container hidden when depen
380dencies non-zero) 381 var force_list = el.data('_force_list'); // (classnames comma list) show regardless of display dependencies (this is non-persistent -and- element's dependencies are not cleared) 382 383 var fcreadonly = el.data('_fcreadonly'); // (JSON format, element name : value) set readonly property of elements, 1:ON , 2:OFF 384 var fcconfigs = el.data('_fcconfigs'); // (JSON format, element name : value) set value of elements 385 386 var _d; 387 if (!seton_list) { 388 seton_list = {}; 389 seton_list[0] = el.attr('data-seton_list') ? el.attr('data-seton_list') : null; 390 el.data('_seton_list', seton_list); 391 } 392 if (!setoff_list) { 393 setoff_list = {}; 394 setoff_list[0] = el.attr('data-setoff_list') ? el.attr('data-setoff_list') : null; 395 el.data('_setoff_list', setoff_list); 396 } 397 if (!refsh_list) { 398 refsh_list = {}; 399 refsh_list[0] = el.attr('data-refsh_list') ? el.attr('data-refsh_list') : null; 400 el.data('_refsh_list', refsh_list); 401 } 402 403 if (!fcreadonly) { 404 var fcreadonly = el.attr('data-fcreadonly'); 405 if (fcreadonly) { 406 fcreadonly = fcreadonly.replace(/\'/g, '"'); 407 fcreadonly = jQuery.parseJSON(fcreadonly); 408 } 409 el.data('_fcconfigs', fcconfigs); 410 } 411 if (!fcconfigs) { 412 var fcconfigs = el.attr('data-fcconfigs'); 413 if (fcconfigs) { 414 fcconfigs = fcconfigs.replace(/\'/g, '"'); 415 fcconfigs = jQuery.parseJSON(fcconfigs); 416 } 417 el.data('_fcconfigs', fcconfigs); 418 } 419 420 if (!show_list) { 421 show_list = {}; 422 _d = el.attr('data-show_list') ? el.attr('data-show_list').split(',') : Array(); 423 for (var i = 0; i<_d.length; i++) show_list[_d[i].trim()] = 1; 424 el.data('_show_list', show_list); 425 } 426 if (!hide_list) { 427 hide_list = {}; 428 _d = el.attr('data-hide_list') ? el.attr('data-hide_list').split(',') : Array(); 429 for (var i = 0; i<_d.length; i++) hide_list[_d[i].trim()] = 1; 430 el.data('_hide_list', hide_list); 431 } 432 if (!force_list) { 433 force_list = {}; 434 _d = el.attr('data-force_list') ? el.attr('data-force_list').split(',') : Array(); 435 for (var i = 0; i<_d.length; i++) force_list[_d[i].trim()] = 1; 436 el.data('_force_list', force_list); 437 } 438 439 var toBeUpdated = Array(); 440 var u = 0; 441 jQuery.each( force_list, function( cname, val ) { 442 if (!fc_dependent_params.hasOwnProperty(cname)) fc_dependent_params[cname] = Array(); 443 fc_dependent_params[cname][fc_dependent_params[cname].length] = el; 444 445 if (val) { 446 jQuery('.'+cname).each(function( index ) { 447 var c = jQuery(this); 448 c.attr('data-fc_forced_display', '1'); 449 toBeUpdated[u++] = c; 450 }); 451 } 452 }); 453 jQuery.each( hide_list, function( cname, val ) { 454 if (!fc_dependent_params.hasOwnProperty(cname)) fc_dependent_params[cname] = Array(); 455 fc_dependent_params[cname][fc_dependent_params[cname].length] = el; 456 457 if (val) { 458 jQuery('.'+cname).each(function( index ) { 459 var c = jQuery(this); 460 var dlist = c.data('fc_depend_list'); 461 if (!dlist) dlist = {}; 462 if (dlist.hasOwnProperty(cname)) dlist[cname]++; else dlist[cname]= 1; 463 c.data('fc_depend_list', dlist); 464 if (c.attr('data-fc_forced_display')!='1') { 465 toBeUpdated[u++] = c; 466 } 467 }); 468 } 469 }); 470 471 // Display fields / enable input on them ( removeAttr + css ), force them to update display ( trigger:click ), and to validate new value ( trigger:blur ) 472 if (fcconfigs) for (var fieldname in fcconfigs) { 473 if (fcconfigs.hasOwnProperty(fieldname)) { 474 var jf_field = jQuery('#'+'jform_attribs_'+fieldname); // first try 'jform_attribs' 475 if (!jf_field.length) { 476 jf_field = jQuery('#'+'jform_params_'+fieldname); // then try 'jform_params' 477 if (!jf_field.length) { 478 jf_field = jQuery('#'+'jform_'+fieldname); // then try just 'jform_' 479 if (!jf_field.length) continue; 480 } 481 } 482 jf_field = jf_field.first(); 483 484 if (jf_field.is('fieldset')) { 485 jf_field.find('input').removeAttr('disabled').removeAttr('readonly'); 486 jf_field.find('label').removeAttr('disabled').css('pointer-events', 'auto').css('opacity', '1'); 487 jf_field.find(':input[value="'+fcconfigs[fieldname]+'"]').next().trigger('click').trigger('blur'); 488 } else if (jf_field.is('select')) { 489 490 jf_field.removeAttr('disabled').removeAttr('readonly'); 491 if (jf_field.prop('multiple')) { 492 jf_field.val('').trigger('change'); 493 jQuery.each(fcconfigs[fieldname].split(','), function(i, val){ 494 jf_field.find('option[value=\"' + val.trim() + '\"]').attr('selected', 'selected'); 495 }); 496 } else { 497 jf_field.val(fcconfigs[fieldname]); 498 } 499 jf_field.trigger('change'); 500 501 } else { 502 jf_field.removeAttr('disabled').removeAttr('readonly').val(fcconfigs[fieldname]).trigger('click').trigger('blur'); 503 } 504 } 505 } 506 507 if (fcreadonly) for (var fieldname in fcreadonly) { 508 if (fcreadonly.hasOwnProperty(fieldname)) { 509 var jf_field = jQuery('#'+'jform_attribs_'+fieldname); // first try 'jform_attribs' 510 if (!jf_field.length) { 511 jf_field = jQuery('#'+'jform_params_'+fieldname); // then try 'jform_params' 512 if (!jf_field.length) { 513 jf_field = jQuery('#'+'jform_'+fieldname); // then try just 'jform_' 514 if (!jf_field.length) continue; 515 } 516 } 517 jf_field = jf_field.first(); 518 519 if (fcreadonly[fieldname] && !field.hasClass('fccustom_revert')) { 520 if (jf_field.is('fieldset')) { 521 jf_field.find('input').attr('readonly', 'readonly'); 522 jf_field.find('label').attr('disabled', true).css('pointer-events', 'n
522one').css('opacity', '0.65'); 523 } else if (jf_field.is('select')) { 524 jf_field.attr('readonly', 'readonly').css('pointer-events', 'none').css('opacity', '0.85'); 525 } else { 526 jf_field.attr('readonly', 'readonly').css('opacity', '0.85') 527 } 528 } else { 529 if (jf_field.is('fieldset')) { 530 jf_field.find('input').removeAttr('disabled'); 531 jf_field.find('label').removeAttr('disabled').css('pointer-events', 'auto').css('opacity', '1'); 532 } 533 else { 534 jf_field.removeAttr('readonly').css('pointer-events', 'auto').css('opacity', '1'); 535 } 536 } 537 } 538 } 539 540 jQuery.each( show_list, function( cname, val ) { 541 if (!fc_dependent_params.hasOwnProperty(cname)) fc_dependent_params[cname] = Array(); 542 fc_dependent_params[cname][fc_dependent_params[cname].length] = el; 543 544 if (val) { 545 jQuery('.'+cname).each(function( index ) { 546 var c = jQuery(this); 547 var dlist = c.data('fc_depend_list'); 548 if (!dlist) dlist = {}; 549 if (dlist.hasOwnProperty(cname)) dlist[cname]--; else dlist[cname]= -1; 550 c.data('fc_depend_list', dlist); 551 if (c.attr('data-fc_forced_display')!='1') { 552 toBeUpdated[u++] = c; 553 } 554 }); 555 } 556 }); 557 558 setTimeout(function(){ 559 jQuery.each( setoff_list, function( i, selector ) { 560 if (selector) { 561 jQuery(selector).each(function( index ) { 562 var c = jQuery(this); 563 c.slideUp('fast'); 564 }); 565 } 566 }); 567 jQuery.each( seton_list, function( i, selector ) { 568 if (selector) { 569 jQuery(selector).each(function( index ) { 570 var c = jQuery(this); 571 c.slideDown('fast'); 572 }); 573 } 574 }); 575 }, !fc_init_hide_dependent ? 0 : 50); 576 577 578 if (!fc_init_hide_dependent) { 579 fc_applyFormDependencies(toBeUpdated, toggleParent, toggleParentSelector, 0); 580 581 if (!fc_refreshing_dependent) { 582 fc_refreshing_dependent = 1; 583 584 // Refresh needed dependencies 585 if (typeof refsh_list != 'string') jQuery.each( refsh_list, function( i, selector ) { 586 if (selector) { 587 jQuery(selector).each(function( index ) { 588 var c = jQuery(this); 589 if (c.is('select')) 590 c.trigger('fcform_run_deps'); // instead of change 591 else if (c.is('input[type="radio"]')) 592 c.closest('.fcform_toggler_element').find('input[type="radio"]:checked').trigger('fcform_run_deps'); // instead of click 593 else if (c.is('fieldset') && c.hasClass('radio')) 594 c.find('input[type="radio"]:checked').trigger('fcform_run_deps'); // instead of click 595 }); 596 } 597 }); 598 } 599 fc_refreshing_dependent = 0; 600 } 601 602 // Restore the form to select the element with value '' 603 if ( field.hasClass('fccustom_revert') && el.value!='' ) 604 { 605 var currVal; 606 if ( field.is('fieldset') ) { 607 currVal = field.find('input[type="radio"]:checked').val(); 608 if (currVal!='') { 609 field.find('input').attr('disabled', 'disabled'); 610 field.find('label').attr('disabled', true).css('pointer-events', 'none').css('opacity', '0.65'); 611 } 612 } else { 613 currVal = field.val(); 614 if (currVal!='') field.attr('disabled', 'disabled').css('pointer-events', 'none').css('opacity', '0.85'); 615 } 616 617 if (currVal!='') setTimeout(function(){ 618 if (field.is('fieldset')) { 619 field.find('input').removeAttr('disabled').removeAttr('readonly'); 620 field.find('label').removeAttr('disabled').css('pointer-events', 'auto').css('opacity', '1'); 621 field.find(':input[value=""]').next().trigger('click'); 622 } else { 623 field.removeAttr('disabled').removeAttr('readonly').css('pointer-events', 'auto').css('opacity', '1'); 624 field.val('').trigger('click'); 625 } 626 }, 200); 627 } 628 629 return toBeUpdated; 630 } 631 632 633 // Add toggling of dependent form elements 634 function fc_bindFormDependencies(container, toggleParent, toggleParentSelector) 635 { 636 var vTimeStart = new Date().getTime(); 637 638 var toBeUpdated_ALL = Array(); 639 var k = 0; 640 641 // Performance concern: use custom event 642 643 // Bind dependencies of select elements 644 jQuery(container+' select.fcform_toggler_element').on('change fcform_run_deps', function(e, data) { 645 var toBeUpdated = fc_findFormDependencies( jQuery('option:selected', this), toggleParent, toggleParentSelector, jQuery(this) ); 646 for (var i = 0; i < toBeUpdated.length; i++) { 647 toBeUpdated_ALL[k++] = toBeUpdated[i]; 648 } 649 }); 650 651 // Bind dependencies of radio elements
652 jQuery(container+' .fcform_toggler_element input:radio').on('click fcform_run_deps', function(e, data) { 653 var toBeUpdated = fc_findFormDependencies( jQuery(this), toggleParent, toggleParentSelector, jQuery(this).parent('.fcform_toggler_element') ); 654 for (var i = 0; i < toBeUpdated.length; i++) { 655 toBeUpdated_ALL[k++] = toBeUpdated[i]; 656 } 657 }); 658 659 // *** Update the form 660 jQuery('form').data('skip_validation' ,1); 661 662 // Enqueue dependencies by triggering change on select elements 663 jQuery('form select.fcform_toggler_element').trigger('fcform_run_deps'); 664 // Enqueue dependencies by triggering change on radio elements 665 jQuery('form .fcform_toggler_element input[type="radio"]:checked').trigger('fcform_run_deps'); 666 667 //alert(toBeUpdated_ALL.length); 668 // Apply form changes according to dependencies 669 fc_applyFormDependencies(toBeUpdated_ALL, toggleParent, toggleParentSelector, 1); 670 671 // Clear this flag to indicate that form initialization is done 672 fc_init_hide_dependent = 0; 673 674 jQuery('form').data('skip_validation', null); 675 676 /*setTimeout(function(){ }, 20);*/ 677 if (!!Joomla.fc_debug) window.console.log( 'fc_bindFormDependencies() time: ' + ((new Date()) - vTimeStart) + ' ms'); 678 } 679 680 681 /* Attach form validation to inner elements of the given selector */ 682 function fc_validationAttach(sel) 683 { 684 document.formvalidator.attachToForm(null, sel); 685 } 686 687 688 /* Set children to have same minimum height e.g. floated elements that need to wrap properly */ 689 function fc_setEqualHeights(box, property, delay) 690 { 691 property = !!property ? property : 0; // 0: both height + min-height, 1: height, 2: min-height 692 delay = !!delay ? delay : 20; 693 var elements = box.children(); 694 elements.css({'height': '', 'min-height': ''}); 695 setTimeout(function() { 696 var max_h = Number.NEGATIVE_INFINITY; 697 var max_mh = Number.NEGATIVE_INFINITY; 698 699 jQuery.each(elements, function(index, item) { 700 if (property==1 || property==0) 701 { 702 if (jQuery(item).height() > max_h) max_h = jQuery(item).height(); 703 } 704 if (property==2 || property==0) 705 { 706 if (jQuery(item).outerHeight() > max_mh) max_mh = jQuery(item).outerHeight(); 707 } 708 }); 709 710 var val_h = '' + max_h + 'px'; 711 var val_mh = '' + max_mh + 'px'; 712 elements.each(function(i, v) { 713 if (property==1 || property==0) 714 { 715 if (v.style.height != val_h) v.style.height = val_h; 716 } 717 if (property==2 || property==0) 718 { 719 if (v.style.minHeight != val_mh) v.style.minHeight = val_mh; 720 } 721 }); 722 }, delay); 723 } 724 725 726 function fc_toggleCompactValuesView(el, field_values_box, btn_class) 727 { 728 btn_class = btn_class || 'btn-info'; 729 // Get field value containers 730 var rows = field_values_box.find('.fcfieldval_container'); 731 var el = jQuery(el); 732 733 // Set expanding flag and expand or compact properties 734 if (el.prop('tagName')=='INPUT') 735 { 736 var expand_field = el.prop('type')=='checkbox' ? el.is(':checked') : el.val()=='1'; 737 } 738 else 739 { 740 var expand_field = !el.data('expandedFieldState'); 741 el.data('expandedFieldState', expand_field); 742 expand_field ? el.addClass('active ' + btn_class) : el.removeClass('active ' + btn_class); 743 } 744 expand_field ? rows.addClass('fc-expanded'): rows.removeClass('fc-expanded'); 745 } 746 747 748 /* Attach boostrap styling / behaviour to the inner contents of the given selector */ 749 function fc_bootstrapAttach(sel) 750 { 751 var sbox = jQuery(sel); 752 753 // Turn radios into btn-group 754 sbox.find('.radio.btn-group label').addClass('btn'); 755 756 sbox.find('fieldset.btn-group').each(function() { 757 // Handle disabled, prevent clicks on the container, and add disabled style to each button 758 if (jQuery(this).prop('disabled')) { 759 jQuery(this).css('pointer-events', 'none').off('click'); 760 jQuery(this).find('.btn').addClass('disabled'); 761 } 762 }); 763 764 sbox.find('.btn-group label:not(.active)').click(function() 765 { 766 var label = jQuery(this); 767 var input = jQuery('#' + label.attr('for')); 768 769 if (!input.prop('checked')) { 770 label.closest('.btn-group').find('label').removeClass('active btn-success btn-danger btn-primary'); 771 if (input.val() == '') { 772 label.addClass('active btn-primary'); 773 } else if (input.val() == 0) { 774 label.addClass('active btn-danger'); 775 } else { 776 label.addClass('active btn-success'); 777 } 778 input.prop('checked', true); 779 input.trigger('change'); 780 } 781 }); 782 783 sbox.find('.btn-group input[checked="checked"]').each(function() 784 { 785 var input = jQuery(this); 786 if (input.val() == '') { 787 input.parent().find('label[for="' + input.attr('id') + '"]').addClass('active btn-primary'); 788 } else if (input.val() == 0) { 789 input.parent().find('label[for="' + input.attr('id') + '"]').addClass('active btn-danger'); 790 } else { 791 input.parent().find('label[for="' + input.attr('id') + '"]').addClass('active btn-success'); 792 } 793 }); 794 } 795 796
797 function fc_applyFormDependencies(toBeUpdated, toggleParent, toggleParentSelector, noFX) 798 { 799 var emptySet = jQuery(); 800 jQuery.each( toBeUpdated, function( i, val ) { 801 var c = jQuery(this); 802 var dlist = c.data('fc_depend_list'); 803 if (!dlist) dlist = {}; 804 var forced = c.attr('data-fc_forced_display'); 805 806 jQuery.each(dlist, function( i, val ) { if(val<=0) delete dlist[i]; if(val>=1) dlist[i]=1 ;}); 807 c.data('fc_depend_list', dlist); 808 809 var toggledBox = !toggleParent || c.hasClass('fc_toggle_current') ? emptySet : (toggleParentSelector ? c.parents(toggleParentSelector) : c.parents().eq(toggleParent)); 810 811 if ( jQuery.isEmptyObject(dlist) || forced=='1' ) 812 { 813 toggledBox.length ? toggledBox.slideDown(noFX ? 0 : 500) : c.slideDown(noFX ? 0 : 500); 814 } 815 else 816 { 817 toggledBox.length ? toggledBox.slideUp(noFX ? 0 : 500) : c.slideUp(noFX ? 0 : 500); 818 } 819 }); 820 821 jQuery.each( toBeUpdated, function( i, val ) { 822 var c = jQuery(this); 823 c.attr('data-fc_forced_display', '0'); 824 }); 825 } 826 827 function fcCascadedField_update(elVal, trgID, field_id, item_id, field_type, cascade_prompt, prompt_enabled, valindex) 828 { 829 // Joomla Base URL 830 var base_url = !!jbase_url_fc ? jbase_url_fc : '';; 831 832 var trgEL = jQuery('#'+trgID); 833 trgEL.parent().find('.field_cascade_loading').html('<img src="'+base_url+'components/com_flexicontent/assets/images/ajax-loader.gif" align="center" /> ... Loading'); 834 835 var loading_prompt = ''; // Joomla.JText._('FLEXI_PLEASE_WAIT') 836 fcCascadedField_clear(trgEL, loading_prompt, prompt_enabled); 837 trgEL.removeAttr('data-defvals'); // Remove default values of select2 JS 838 839 jQuery.ajax({ 840 type: 'POST', 841 url: base_url + 'index.php?option=com_flexicontent&tmpl=component&format=raw', 842 data: { 843 lang: (typeof fc_sef_lang != 'undefined' ? fc_sef_lang : ''), 844 task: 'call_extfunc', 845 omethod: 'html', /* unused */ 846 exttype: 'plugins', 847 extfolder: 'flexicontent_fields', 848 extname: field_type, 849 extfunc: 'getCascadedField', 850 field_id: field_id, 851 item_id: item_id, 852 valgrps: elVal, 853 valindex: valindex 854 } 855 }).done( function(data) { 856 //window.console.log ('Got data for:' + trgEL.attr('id')); 857 trgEL.parent().find('.field_cascade_loading').html(''); 858 data = data.trim(); 859 860 if (data!='') 861 { 862 trgEL.empty().append(data).val(''); 863 var trgTagName = trgEL.prop("tagName"); 864 865 // Special case 0: Re-attach cascade function to the updated HTML of radio/checkbox set 866 if (fc_cascade_field_funcs.hasOwnProperty(trgID) && trgTagName!='SELECT') 867 { 868 //window.console.log ('Re-attach cascade function for new HTML source for tag ID:' + trgID); 869 fc_cascade_field_funcs[trgID](); 870 } 871 872 // Special case 1: Re-apply prettyCheckable to the updated HTML of radio/checkbox set 873 trgEL.find('.use_prettycheckable').each(function() { 874 var elem = jQuery(this); 875 var lbl = elem.next('label'); 876 var lbl_html = elem.next('label').html(); 877 lbl.remove(); 878 elem.prettyCheckable({ 879 color: 'blue', 880 label: lbl_html 881 }); 882 }); 883 } 884 else 885 { 886 trgEL.empty().append('<option value="" '+(!prompt_enabled ? 'disabled="disabled"' : '')+'>'+cascade_prompt+'</option>'); 887 } 888 trgEL.trigger('change'); // Retrigger change event to update select2 display 889 }); 890 } 891 892 function fcCascadedField_clear(el, prompt, prompt_enabled) 893 { 894 var trgTagName = el.prop("tagName"); 895 if (trgTagName=='SELECT') 896 { 897 el.empty(); 898 if (prompt) el.append('<option value="" '+(!prompt_enabled ? 'disabled="disabled"' : '')+'>' + prompt + '</option>'); 899 el.trigger('change', [{elementClear:1}]); 900 } 901 else 902 { 903 el.find('input').first().trigger('change', [{elementClear:1}]); 904 el.empty(); 905 if (prompt) el.append('<span class="fcpadded alert alert-info">'+prompt+'</span>'); 906 } 907 } 908 909 function fcCascadedField(field_id, item_id, field_type, srcSelector, trgID, cascade_prompt, prompt_enabled, valindex) 910 { 911 var onEL = jQuery(srcSelector); 912 var onEL2 = onEL.parent().find('select.use_select2_lib'); 913 var isSel2 = onEL2.length != 0; 914 915 var srcEL = isSel2 ? onEL2 : onEL; 916 var trgEL = jQuery('#'+trgID); 917 //window.console.log ('ATTACHING fcCascadedField() FOR source SELECTOR: ' + srcSelector + ' to UPDATE element with ID: ' + trgID + ' , valindex: ' + valindex); 918 919 var elementClear = (typeof data!== 'undefined' && typeof data.elementClear !== 'undefined') ? data.elementClear : 0; // workaround for radio, checkbox causing unneeded server call 920 var elType = srcEL.attr('type'); 921 if (elType=='radio' || elType=='checkbox') { 922 var elVal = Array();
923 srcEL.parent().parent().find('input:checked').each(function( index ) { 924 elVal[elVal.length] = jQuery(this).val(); 925 }); 926 elVal = elVal.join(','); 927 } else { 928 var elVal = srcEL.val(); 929 } 930 931 if ( !elementClear && !! elVal ) 932 { 933 trgEL.closest('.fcfieldval_container_outer, .control-group').show(); 934 } else { 935 trgEL.closest('.fcfieldval_container_outer, .control-group').hide(); 936 } 937 938 srcEL.on('change', function(e, data){ 939 var elementClear = (typeof data!== 'undefined' && typeof data.elementClear !== 'undefined') ? data.elementClear : 0; // workaround for radio, checkbox causing unneeded server call 940 var elType = srcEL.attr('type'); 941 if (elType=='radio' || elType=='checkbox') { 942 var elVal = Array(); 943 srcEL.parent().parent().find('input:checked').each(function( index ) { 944 elVal[elVal.length] = jQuery(this).val(); 945 }); 946 elVal = elVal.join(','); 947 } else { 948 var elVal = srcEL.val(); 949 } 950 951 //window.console.log ('CHANGED element ID: ' + srcEL.attr('id') + ' , isCHECKED: ' + srcEL.is(':checked') + ' type: '+srcEL.attr('type')); 952 if ( !elementClear && !! elVal ) 953 { 954 //window.console.log ('CHANGED element ID: ' + srcEL.attr('id') + ' --> Updating:' + trgEL.attr('id') + ' for VALGRP: -' + elVal + '- value of 1st element: ' + srcEL.val() + ' type: '+srcEL.attr('type')); 955 trgEL.closest('.fcfieldval_container_outer, .control-group').show(); 956 fcCascadedField_update(elVal, trgID, field_id, item_id, field_type, cascade_prompt, prompt_enabled, valindex); 957 } else { 958 //window.console.log ('CHANGED element ID: ' + srcEL.attr('id') + ' --> Clearing:' + trgEL.attr('id') + ' TAG type: ' + trgEL.prop("tagName")); 959 trgEL.closest('.fcfieldval_container_outer, .control-group').hide(); 960 fcCascadedField_clear(trgEL, cascade_prompt, prompt_enabled); 961 } 962 }); 963 } 964 965 966 967 // *** Check that a variable is not null and is defined (has a value) 968 function js_isset (variable) 969 { 970 if (variable==null) return false; 971 if (typeof variable == "undefined") return false; 972 return true; 973 } 974 975 976 // Store a configuration cookie (like current user choices) 977 function fc_config_store(conf, prop_name, prop_value) 978 { 979 var cookieName = conf.fc_man_config_cookie; 980 var managerName = conf.fc_man_manager_name; 981 var cookieValue = fclib_getCookie(cookieName); 982 983 //window.console.log('Using cookieName: ' + cookieName + ', managerName: ' + managerName); 984 //window.console.log(cookieName + ', Old value: ' +cookieValue); 985 986 cookieValue = jQuery.parseJSON(cookieValue ? cookieValue : '{}'); 987 988 if (typeof cookieValue[managerName] == 'undefined') 989 { 990 cookieValue[managerName] = {}; 991 } 992 cookieValue[managerName][prop_name] = prop_value; 993 window.console.log(cookieName + ', New value: ' + JSON.stringify(cookieValue)); 994 995 var nDays = 30; 996 fclib_setCookie(cookieName, JSON.stringify(cookieValue), nDays); 997 } 998 999 1000 //****************************************** 1001 //*** Column hide/show related functions *** 1002 //****************************************** 1003 1004 // *** Hide a column of a table 1005 function fc_tbl_toggle_column(container_div_id, data_tbl_id, col_no, firstrun) 1006 { 1007 // 1. Get column-status array for the table with id: data_tbl_id 1008 var show_col = eval('show_col_'+data_tbl_id); 1009 1010 // 2. Decide show or hide action and update the displayed number of the hidden columns (if any must be in the element with id: data_tbl_id+'_hidecolnum_box') 1011 if ( !js_isset(show_col[col_no]) || show_col[col_no] ) { 1012 var action_func = 'hide'; 1013 show_col[col_no] = 0; 1014 var hidecol_box = document.getElementById(data_tbl_id+'_hidecolnum_box'); 1015 if ( js_isset(hidecol_box) ) { 1016 hidecol_box.innerHTML = parseInt(hidecol_box.innerHTML) + 1; 1017 } 1018 } else { 1019 var action_func = 'show'; 1020 show_col[col_no] = 1; 1021 var hidecol_box = document.getElementById(data_tbl_id+'_hidecolnum_box'); 1022 if ( js_isset(hidecol_box) ) { 1023 hidecol_box.innerHTML = parseInt(hidecol_box.innerHTML) - 1; 1024 } 1025 } 1026 1027 1028 if (firstrun) 1029 { 1030 if (action_func === 'hide' && !document.getElementById('fc_' + container_div_id + '_btn').classList.contains('btn-inverse')) 1031 { 1032 document.getElementById('fc_' + container_div_id + '_btn').classList += ' btn-dark btn-inverse text-white'; 1033 } 1034 } 1035 1036 //var ffieldname_label = 'columnchoose_' + data_tbl_id + '_' + col_no + '_label'; 1037 //var ffieldname_label = document.getElementById(ffieldname_label); 1038 //if ( js_isset(ffieldname_label) ) if (action_func == 'show') ffieldname_label.style.color='black'; else ffieldname_label.style.color='#00aa00'; 1039 1040 // 3. Get table and all its rows 1041 var tbl = document.getElementById(data_tbl_id); 1042 var rows = jQuery(tbl).find('> thead > tr, > tbody > tr'); 1043 var toggle_amount = 1; 1044 1045 // Find 'colspan' start of the column given the -index- 'col_no' of the head cell 1046 var _col_no = 0; 1047 var tcells = jQuery(rows[0]).children('td, th'); 1048 for (cell=0; cell<col_no; cell++) { 1049 if (cell>=tcells.length) break;
1050 colspan = parseInt(jQuery(tcells[cell]).attr('colspan')); 1051 if (colspan) { 1052 _col_no = _col_no + colspan; 1053 } else { 1054 _col_no++; 1055 } 1056 } 1057 1058 // 4. Iterate through rows toggling the particular column 1059 for (var row=0; row<rows.length; row++) { 1060 var cell_cnt, cell; 1061 1062 // Get cell(s) of the current row 1063 var tcells = jQuery(rows[row]).children('td, th'); 1064 1065 // First row is header, we will get 'colspan' of the HEAD CELL, which indicates how many 'toggle_amount' single-colspan columns should be toggled 1066 if (row==0) { 1067 toggle_amount = parseInt(jQuery(tcells[col_no]).attr('colspan')); 1068 if (!toggle_amount) toggle_amount = 1; 1069 } 1070 1071 // Find where the cell's index in current row, we need this loop since previous cell of row maybe using colspan 1072 cell_cnt = 0; 1073 for (cell=0; cell<tcells.length; cell++) { 1074 var colspan; 1075 var data_colspan = jQuery(tcells[cell]).attr('data-colspan'); 1076 if (firstrun && !data_colspan) { 1077 colspan = parseInt(jQuery(tcells[cell]).attr('colspan')); 1078 if (colspan) { 1079 jQuery(tcells[cell]).attr('data-colspan', colspan); 1080 } 1081 } else { 1082 colspan = parseInt(jQuery(tcells[cell]).attr('data-colspan')); 1083 } 1084 1085 if (cell_cnt==_col_no+toggle_amount-1) break; 1086 var next_cnt = colspan ? cell_cnt + colspan : cell_cnt + 1; 1087 if (next_cnt > _col_no) break; 1088 cell_cnt = next_cnt; 1089 } 1090 1091 // Finally TOGGLE the found cell, we take into account that the given cell may have colspan, 1092 // if it does have colspan we increase / decrease, a ZERO remaining colspan, will make us hide the cell, and a non-zero makes us display the cell 1093 var _cell = cell; 1094 var colspan_remaining = toggle_amount; 1095 for (cell=_cell; cell<_cell+toggle_amount; cell++) { 1096 if (cell<tcells.length) { 1097 var colspan = parseInt(jQuery(tcells[cell]).attr('colspan')); 1098 1099 jQuery(tcells[cell]).removeClass('initiallyHidden'); 1100 if ( colspan ) 1101 { 1102 if ( action_func == 'hide' ) 1103 { 1104 if ( colspan > colspan_remaining ) { 1105 jQuery(tcells[cell]).attr('colspan', colspan - colspan_remaining); 1106 } else { 1107 firstrun ? 1108 eval('jQuery(tcells[cell]).'+action_func+'(0)') : 1109 eval('jQuery(tcells[cell]).'+action_func+'(0)'); 1110 jQuery(tcells[cell]).addClass('isHidden'); 1111 } 1112 } 1113 else if (!firstrun) 1114 { 1115 if ( !jQuery(tcells[cell]).hasClass('isHidden') ) { 1116 jQuery(tcells[cell]).attr('colspan', colspan + colspan_remaining); 1117 } else { 1118 eval('jQuery(tcells[cell]).'+action_func+'(0)'); 1119 jQuery(tcells[cell]).removeClass('isHidden'); 1120 } 1121 } 1122 colspan_remaining = colspan_remaining - colspan; 1123 } 1124 else if (action_func == 'hide' || !firstrun) 1125 { 1126 firstrun ? 1127 eval('jQuery(tcells[cell]).'+action_func+'(0)') : 1128 eval('jQuery(tcells[cell]).'+action_func+'(0)'); 1129 colspan_remaining--; 1130 } 1131 } 1132 if (colspan_remaining<1) break; // no more colspan to toggle columns 1133 } 1134 } 1135 1136 // Update cookie data and display data 1137 if (!firstrun && container_div_id) 1138 { 1139 column_toggles_update_data(container_div_id, data_tbl_id); 1140 } 1141 } 1142 1143 1144 // *** Update cookie data and display data 1145 function column_toggles_update_data(container_div_id, data_tbl_id) 1146 { 1147 var col_selectors = jQuery('#'+container_div_id+'_cols input'); 1148 var col_selected = new Array(); 1149 var i = 0; 1150 for (var cnt=0; cnt<col_selectors.length; cnt++) 1151 { 1152 if ( jQuery(col_selectors[cnt]).attr("checked") ) 1153 { 1154 col_selected[i++] = jQuery(col_selectors[cnt]).attr("data-colno"); 1155 } 1156 } 1157 1158 var cookieName = 'fc_columnchooser'; 1159 var cookieValue = fclib_getCookie(cookieName); 1160 //window.console.log(cookieName + ' - old value: ' +cookieValue); 1161 1162 cookieValue = jQuery.parseJSON(cookieValue ? cookieValue : '{}'); 1163 cookieValue[data_tbl_id] = col_selected.join(','); 1164 //window.console.log(cookieName + ' - new value: ' + JSON.stringify(cookieValue)); 1165 1166 var nDays = 30; 1167 fclib_setCookie(cookieName, JSON.stringify(cookieValue), nDays); 1168 1169 var totals_tag = jQuery('#columnchoose_totals'); 1170 if (totals_tag.length) 1171 { 1172 totals_tag.html(col_selectors.length == col_selected.length ? '' : ' '+(col_selected.length - col_selectors.length)); 1173 } 1174 } 1175 1176 1177 // *** Create column choosers row for a table. NOTE must have <th> cells at row 0 1178 function create_column_choosers(container_div_id, data_tbl_id, firstload, start_text, end_text, toggle_on_init) 1179 { 1180 // 1. Get column-status array for the table with id: data_tbl_id 1181 var show_col = eval('show_col_'+data_tbl_id); 1182 1183 // 2. Get table and its first row and then the 'th' cells in it 1184 var firstrow = jQuery("#"+data_tbl_id+" thead tr:first"); //document.getElementById(data_tbl_id); 1185 var thcells = firstrow.find('th'); 1186 1187 // 3. Iterate through the 'th' cells and create column hiders for those having the class 'hideOnDemandClass' 1188 var str = (typeof start_text != "undefined") ? start_text : ''; 1189 1190 for (var col = 0; col < thcells.length; col++) 1191 { 1192 // 4. Skip if not having 'hideOnDemandClass' class 1193 if (!jQuery(thcells[col]).hasClass('hideOnDemandClass')) continue; 1194 1195 // 5. Get column name 1196 var column_toggle_lbl = jQuery(thcells[col]).find('.column_toggle_lbl'); 1197 var col_display_name = column_toggle_lbl.length ? column_toggle_lbl.html() : jQuery(thcells[col]).text(); 1198 column_toggle_lbl.remove(); 1199 1200 // 6. Show / Hide current column 1201 if ( ( !firstload && !js_isset(show_col[col]) ) || ( jQuery(thcells[col]).hasClass('initiallyHidden') && !js_isset(show_col[col]) ) ) 1202 { 1203 var checked_str = ''; 1204 var fontcolor_str = 'black';//var fontcolor_str = '#aaaaaa'; 1205 1206 // *** It has value of 0 or not set, set it to 1 for fc_tbl_toggle_column() function to hide it 1207 show_col[col] = 1; 1208 if (toggle_on_init) fc_tbl_toggle_column(container_div_id, data_tbl_id, col, 1); 1209 } 1210 else 1211 {
1212 var checked_str = 'checked="checked"'; 1213 var fontcolor_str = 'black'; //var fontcolor_str = 'black'; 1214 1215 // *** It has value of 1 or not set, set it to 0 for fc_tbl_toggle_column() function to show it 1216 show_col[col] = 0; 1217 if (toggle_on_init) fc_tbl_toggle_column(container_div_id, data_tbl_id, col, 1); 1218 } 1219 1220 // 7. Create column checkbox and append it to str 1221 var ffieldid = 'columnchoose_' + data_tbl_id + '_' + col; 1222 var ffieldname = 'columnchoose_' + data_tbl_id + '[' + col + ']'; 1223 str = str + '<input id="' + ffieldid + '" name="' + ffieldname + '" type="checkbox" data-colno="' + col + '" ' + checked_str + ' onclick="fc_tbl_toggle_column(\''+container_div_id+'\', \''+data_tbl_id+'\', '+col+', 0);">' 1224 + '<label id="' + ffieldid + '_label" style="color:'+fontcolor_str+';" for="' + ffieldid + '">' + col_display_name + '</label>'; 1225 } 1226 1227 // 8. Fill in 'column choose box' 1228 str = '<span id="'+container_div_id+'_cols">' + str + '</span>' + end_text; 1229 document.getElementById(container_div_id).innerHTML=str; 1230 1231 // 9. Update cookie data and display data 1232 column_toggles_update_data(container_div_id, data_tbl_id); 1233 } 1234 1235 1236 /* Set a cookie */ 1237 function fclib_setCookie(cookieName, cookieValue, nDays, samesite="lax") 1238 { 1239 var today = new Date(); 1240 var expires = new Date(); 1241 var path = typeof jclient_path_fc != 'undefined' ? jclient_path_fc : window.location.hostname; 1242 if (nDays==null || nDays<0) nDays=0; 1243 1244 if (nDays) 1245 { 1246 expires.setTime(today.getTime() + 3600000*24*nDays); 1247 document.cookie = cookieName+"="+encodeURIComponent(cookieValue) + ";samesite=" + samesite + ";path=" + path + ";expires=" + expires.toGMTString(); 1248 } else { 1249 // nDays 0 , aka no expiration date, keep cookie till browser closes 1250 document.cookie = cookieName+"="+encodeURIComponent(cookieValue) + ";samesite=" + samesite + ";path=" + path; 1251 } 1252 //alert(cookieName+"="+encodeURIComponent(cookieValue) + ";path=" + path); 1253 } 1254 1255 1256 /* Get a cookie */ 1257 function fclib_getCookie(cookieName) 1258 { 1259 let matched = document.cookie.match(new RegExp('(^|;\\s*)' + cookieName + '=([^;]+)')); 1260 return matched ? decodeURIComponent(matched[2]) : ''; 1261 } 1262 1263 1264 /* Get a new list of 2-typles (key, element) living inside a cookie 1265 * List is an object with 'key' being the property name and 'element' being the value of the property 1266 */ 1267 function fclib_createCookieList(cookieName, nDays) 1268 { 1269 var cookieValue = fclib_getCookie(cookieName); 1270 var items = jQuery.parseJSON(cookieValue ? cookieValue : '{}'); 1271 nDays = nDays || 90; 1272 1273 return { 1274 // Add to the items 1275 "add": function(key, element) 1276 { 1277 items[key] = element; 1278 fclib_setCookie(cookieName, JSON.stringify(items), nDays); 1279 }, 1280 1281 // Remove from items 1282 "remove": function (key) 1283 { 1284 if (typeof items[key] != 'undefined') 1285 { 1286 delete items[key]; 1287 fclib_setCookie(cookieName, JSON.stringify(items), nDays); 1288 } 1289 }, 1290 1291 // Clear items 1292 "clear": function() 1293 { 1294 items = {}; 1295 fclib_setCookie(cookieName, JSON.stringify(items), nDays); 1296 }, 1297 1298 // Get all the items 1299 "items": function() 1300 { 1301 return items; 1302 } 1303 } 1304 } 1305 1306 1307 /* Remove known textarea editors, optionally add a flag to restore editors laters */ 1308 function fc_removeAreaEditors(txtareas, addRestoreClass) 1309 { 1310 addRestoreClass = typeof addRestoreClass != 'undefined' ? addRestoreClass : 0; 1311 1312 // Remove known JS editors 1313 txtareas.each(function(i, txtarea) 1314 { 1315 var areaid = jQuery(txtarea).attr('id'); 1316 1317 var hasTinyMCE = !!(!areaid || typeof tinyMCE === 'undefined' ? false : tinyMCE.get(areaid)); 1318 if (hasTinyMCE) { 1319 tinyMCE.majorVersion >= 4 ? 1320 tinymce.remove('#'+areaid) : 1321 tinymce.EditorManager.execCommand('mceRemoveEditor', false, areaid) ; 1322 if (addRestoreClass) jQuery(txtarea).addClass('fc_hadTinyMCE'); 1323 } 1324 1325 var hasCodeMirror = typeof CodeMirror === 'undefined' ? false : jQuery(txtarea).first().next().hasClass('CodeMirror'); 1326 if (hasCodeMirror) { 1327 jQuery(txtarea).first().next().get(0).CodeMirror.toTextArea(); 1328 if (addRestoreClass) jQuery(txtarea).addClass('fc_hadCodeMirror'); 1329
1330 // Remove codemirror container in case that removing it failed 1331 if (jQuery(txtarea).first().next('.CodeMirror').length) jQuery(txtarea).first().next('.CodeMirror').remove(); 1332 } 1333 }); 1334 } 1335 1336 1337 /* Restore known textarea editors to textareas with respective class */ 1338 function fc_restoreAreaEditors(txtareas) 1339 { 1340 fc_attachTinyMCE( txtareas.filter('.fc_hadTinyMCE') ); 1341 fc_attachCodeMirror( txtareas.filter('.fc_hadCodeMirror') ); 1342 } 1343 1344 1345 /* Attach tinyMCE with default settings */ 1346 function fc_attachTinyMCE(txtareas, MCEoptions, mceFieldname) 1347 { 1348 // Create a copy of the options, so that we do not modify the original options objet 1349 var _MCEoptions = typeof MCEoptions!=='undefined' ? jQuery.extend({}, MCEoptions) : {}; 1350 mceFieldname = typeof mceFieldname!=='undefined' ? mceFieldname : false; 1351 1352 var theArea, areaID; 1353 txtareas.each(function(i, txtarea) 1354 { 1355 var theArea = jQuery(txtarea); 1356 var areaID = theArea.attr('id'); 1357 1358 // Remove tinymce classes from the textarea 1359 theArea.removeClass('mce_editable'); 1360 1361 // J3.7.0+ (with integrated XTD buttons) is using new setup method 1362 if (typeof mceFieldname!=='undefined' && typeof Joomla.JoomlaTinyMCE != 'undefined' && typeof MCEoptions.joomlaExtButtons != 'undefined') 1363 { 1364 var tinyMCEOptions = {}; 1365 tinyMCEOptions[mceFieldname] = _MCEoptions; 1366 Joomla.JoomlaTinyMCE.setupEditor(jQuery('#' + areaID).get(0), {tinyMCE: tinyMCEOptions}); 1367 } 1368 else if (tinyMCE.majorVersion >= 4) 1369 { 1370 _MCEoptions.selector = '#' + areaID; 1371 tinyMCE.init(_MCEoptions); 1372 //tinyMCE.EditorManager.execCommand('mceAddEditor', true, areaID); //var editor = tinyMCE.get(areaid); //tinyMCE.editors[areaID]; 1373 } 1374 else 1375 { 1376 _MCEoptions.mode = 'exact'; 1377 _MCEoptions.elements = areaID; 1378 tinyMCE.init(_MCEoptions); 1379 //tinyMCE.EditorManager.execCommand('mceAddControl', true, areaID); //var editor = tinymce.EditorManager.get(area_id); // tinyMCE.editors[areaID]; 1380 } 1381 1382 // Some cleanups for proper display 1383 theArea.addClass('mce_editable'); 1384 theArea.parent().children('.mce-container').css('display', ''); // allow editor container to stretch to the full width of its external container 1385 }); 1386 1387 return txtareas.length==1 ? tinyMCE.get(areaID) : true; 1388 } 1389 1390 1391 /* Attach CodeMirror with optional settings */ 1392 function fc_attachCodeMirror(txtareas, CMoptions) 1393 { 1394 CMoptions = typeof CMoptions!=='undefined' ? CMoptions : { 1395 mode: 'application/x-httpd-php', 1396 indentUnit: 2, 1397 lineNumbers: true, 1398 matchBrackets: true, 1399 lineWrapping: true, 1400 onCursorActivity: function(CM) 1401 { 1402 CM.setLineClass(hlLine, null); 1403 hlLine = CM.setLineClass(CM.getCursor().line, 'activeline'); 1404 } 1405 }; 1406 1407 var editor, theArea; 1408 txtareas.each(function(i, txtarea) 1409 { 1410 theArea = jQuery(txtarea); 1411 theArea.removeClass(); // Remove all classes from the textarea 1412 editor = CodeMirror.fromTextArea(theArea.get(0), CMoptions); 1413 editor.refresh(); 1414 }); 1415 1416 return txtareas.length==1 ? editor : true; 1417 } 1418 1419 1420 /* Toggle box via a button and set CSS class to indicate that it is open */ 1421 function fc_toggle_box_via_btn(theBox, btn, btnClass, btnNew, mode, cookieName) 1422 { 1423 var box = typeof theBox=='string' ? jQuery('#'+theBox) : theBox; 1424 1425 if (btnNew) 1426 { 1427 // Show but remove 'display' property to allow CSS classes to take effect (possibly hiding it) 1428 btnNew.show().css('display', ''); 1429 jQuery(btn).hide(); 1430 } 1431 var cookieName = !!cookieName ? (typeof cookieName=='string' ? cookieName : theBox + '-disp') : false; 1432 //window.console.log(cookieName); 1433 1434 if ( 1435 (typeof mode!=='undefined' && parseInt(mode)) || // use the mode provided 1436 (typeof mode==='undefined' && box.is(':hidden')) // if any of the elements collection 'box' is hidden then open them all 1437 ) { 1438 if (cookieName) fclib_setCookie(cookieName, 1, 0); // nDays 0 , aka no expiration date, keep cookie till browser closes 1439 jQuery(btn).data('fc_noeffect') || jQuery(btn).hasClass('fc_noeffect') ? 1440 box.show() : 1441 box.slideDown(400) ; 1442 // Only remove 'data-fc_noeffect' but not the fc_noeffect class 1443 jQuery(btn).addClass(btnClass).data('fc_noeffect', null); 1444 } 1445 else 1446 { 1447 if (cookieName) fclib_setCookie(cookieName, 0, 0); // nDays 0 , aka no expiration date, keep cookie till browser closes 1448 jQuery(btn).data('fc_noeffect') || jQuery(btn).hasClass('fc_noeffect') ? 1449 box.hide() : 1450 box.slideUp(400) ; 1451 // Only remove 'data-fc_noeffect' but not the fc_noeffect class 1452 jQuery(btn).removeClass(btnClass).data('fc_noeffect', null); 1453 } 1454 } 1455 1456 1457 /* Disable/enable a check box group e.g. when 'Use Global' option is toggled */ 1458 function fc_toggle_checkbox_group(containerID, useGlobalElement) 1459 { 1460 var container = jQuery('#'+containerID); 1461 var inputs = container.find('input'); 1462 el = jQuery(useGlobalElement); 1463 if ( el.is(':checked') ) { 1464 inputs.each(function(index){ 1465 jQuery(this).attr('disabled', true); 1466 }); 1467 } else { 1468 inputs.each(function(index){ 1469 jQuery(this).attr('disabled', false); 1470 }); 1471 } 1472 el.attr('disabled', false); 1473 } 1474 1475 1476 /* Auto-resize the currently open dialog vertically or horizontally */ 1477 function fc_dialog_resize_now(boxWsel, boxHsel, contentSel) 1478 { 1479 boxWsel = typeof boxWsel != 'undefined' ? boxWsel : '.ui-dialog.fc-autow-dialog'; 1480 boxHsel = typeof boxHsel != 'undefined' ? boxHsel : '.ui-dialog.fc-autoh-dialog'; 1481 contentSel = typeof contentSel != 'undefined' ? contentSel : '.ui-dialog-content'; 1482 1483 // Resize the modal(s) 1484 var dialogs = jQuery(boxWsel + ' , '+ boxHsel); 1485 dialogs.each(function( index ) 1486 { 1487 var dialog_box = jQuery(this); 1488 var theDialog = dialog_box.data('fc_dialog'); 1489 if (theDialog) 1490 { 1491 var params = theDialog.data('fc_dialog_params'); 1492 var maxwidth = theDialog.data('fc_dialog_maxwidth'); 1493 var maxheight = theDialog.data('fc_dialog_maxheight'); 1494 params = params || {}; 1495 maxwidth = maxwidth || 0; 1496 maxheight = maxheight || 0; 1497 params = fc_getAutoSizePos(maxwidth, maxheight, params); 1498 1499 dialog_box 1500 .css({ 'left': params.winleft+'px', 'width': params.winwidth+'px' }) 1501 .css({ 'top': params.wintop+'px', 'height': params.winheight+'px' }); 1502 } 1503 }); 1504 1505 // Parameters for modal that should take full window 1506 var dialog_box_sbox = jQuery('#sbox-window'); 1507 var dialog_box_jmedia = jQuery('div.field-media-wrapper > div.modal'); 1508 1509 if (dialog_box_sbox.length || dialog_box_jmedia.length) 1510 { 1511 params = fc_getAutoSizePos(0, 0, {}); 1512 1513 // Maximize sbox modal 1514 if (dialog_box_sbox.length) 1515 { 1516 dialog_box_sbox 1517 .css({ 'position': 'fixed' }) 1518 .css({ 'left': params.winleft+'px', 'width': (params.winwidth-40)+'px' }) 1519 .css({ 'top': params.wintop+'px', 'height': (params.winheight-20)+'px' }) 1520 .find('#sbox-content').children('iframe') 1521 .removeAttr('width').removeAttr('height').css({ 'width': '100%', 'height': '100%' }); 1522 } 1523 1524 // Maximize joomla media modal 1525 if (dialog_box_jmedia.length) 1526 { 1527 dialog_box_jmedia.css({ 'top': (params.wintop-30)+'px', 'height': (params.winheight-60)+'px' }); 1528 } 1529 } 1530 1531 // Fix modal's inner container adding unneeded scrollbar 1532 var dialogs = jQuery(boxHsel); 1533 dialogs.each(function( index ) 1534 { 1535 var dialog_box = jQuery(this); 1536 var content_box = dialog_box.find(contentSel); 1537 var h = dialog_box.height() - content_box.prev().outerHeight(true) - content_box.next().outerHeight(true); 1538 content_box.css({ 'height': h+'px', 'margin': '0', 'box-sizing': 'border-box' }); 1539 1540 // Remove unneeded scroll bar inside iframe document, new browser security disallows this ? 1541 //var body = content_box.find('iframe').contents().find('body'); 1542 //body.css({ 'height': 'unset' }); 1543 }); 1544 } 1545 1546 1547 /* Debounced function execution by the given 'wait' time, forcing single function execution within the given 'wait' time */ 1548 function fc_debounce_exec(func, wait, immediate, func_context) 1549 { 1550 var timeout; 1551 return function() { 1552 var context = func_context || this, args = arguments; 1553 var later = function() { 1554 timeout = null;
1555 if (!immediate) func.apply(context, args); 1556 }; 1557 var callNow = immediate && !timeout; 1558 clearTimeout(timeout); 1559 timeout = setTimeout(later, wait); 1560 if (callNow) func.apply(context, args); 1561 }; 1562 } 1563 1564 var fc_dialog_resize = fc_debounce_exec(fc_dialog_resize_now, 200, false, null); 1565 1566 jQuery(window).resize(function() { 1567 fc_dialog_resize(); 1568 }); 1569 1570 1571 /* Apply select2 JS to targeted elements */ 1572 function fc_attachSelect2(sel, s2_elems) 1573 { 1574 sel = typeof sel !== 'undefined' && sel ? sel : 'body'; 1575 var sbox = jQuery(sel); 1576 1577 s2_elems = s2_elems || sbox.find('select.use_select2_lib'); 1578 1579 if (window.skip_select2_js) 1580 { 1581 s2_elems.removeClass('use_select2_lib').addClass('fc_isselect fc_ismobile fc_no_js_attach'); 1582 //s2_elems.filter(function(){return !jQuery(this).attr('multiple');}) 1583 sbox.find('.fc_mobile_label').show(); 1584 return; 1585 } 1586 1587 1588 // Attach select2 to specific to select elements having specific CSS class, for select-multiple show values as togglable checkboxes 1589 s2_elems.each(function() 1590 { 1591 function fc_formatSel2Option(item) 1592 { 1593 var data_title = jQuery(item.element).attr('data-title'); 1594 return !data_title ? item.text : "<div title='" + data_title + "'>" + item.text + "</div>"; 1595 } 1596 1597 var sel_EL = jQuery(this); 1598 1599 var sel2ops = { 1600 minimumResultsForSearch: 10, 1601 formatResult: fc_formatSel2Option 1602 }; 1603 1604 if ( sel_EL.hasClass('fc_select2_noselect') ) 1605 { 1606 sel2ops.formatNoMatches = function() { return ''; }; 1607 sel2ops.dropdownCssClass = 'select2-hidden'; 1608 sel2ops.minimumResultsForSearch = -1; 1609 } 1610 if (sel_EL.attr('multiple') && !sel_EL.hasClass('fc_select2_no_check')) 1611 { 1612 sel2ops.closeOnSelect = false; 1613 } 1614 1615 if (sel_EL.attr('multiple') && !sel_EL.hasClass('fc_select2_no_check')) 1616 sel_EL.select2(sel2ops).addClass('select2_fc_checkboxes'); 1617 else 1618 sel_EL.select2(sel2ops); 1619 1620 // Set initially selected data (this allows setting order too) 1621 if ( sel_EL.get(0).hasAttribute('data-select2-initdata') ) 1622 { 1623 sel_EL.select2('data', sel_EL.data('select2-initdata')); 1624 } 1625 1626 // Make sortable if requested 1627 if ( sel_EL.hasClass('fc_select2_sortable') ) 1628 { 1629 sel_EL.select2_sortable(); 1630 } 1631 }); 1632 1633 1634 // Customization of SELECT2 JS selectors 1635 sbox.find('div.use_select2_lib').each(function() 1636 { 1637 var el_container = jQuery(this); 1638 var sel_EL = el_container.next('select'); 1639 1640 1641 // MULTI-SELECT2: Initialize internal labels, placing the label so that it overlaps the text filter box 1642 var fc_label_text = sel_EL.attr('data-fc_label_text'); 1643 if (!fc_label_text) fc_label_text = sel_EL.attr('fc_label_text'); 1644 if (fc_label_text) 1645 { 1646 var _label = (fc_label_text.length >= 30) ? fc_label_text.substring(0, 28) + '...' : fc_label_text; 1647 1648 jQuery('<span/>', { 1649 'class': 'fc_has_inner_label fc_has_inner_label_select2', 1650 'text': _label 1651 }).prependTo(el_container.find('.select2-search-field')); 1652 } 1653 1654 1655 // MULTI-SELECT2: Initialize internal prompts, placing the prompt so that it overlaps the text filter box 1656 var fc_prompt_text = sel_EL.attr('data-fc_prompt_text'); 1657 if (!fc_prompt_text) fc_prompt_text = sel_EL.attr('fc_prompt_text'); 1658 if (fc_prompt_text) 1659 { 1660 var _prompt = (fc_prompt_text.length >= 30) ? fc_prompt_text.substring(0, 28) + '...' : fc_prompt_text; 1661 1662 jQuery('<span/>', { 1663 'class': 'fc_has_inner_prompt fc_has_inner_prompt_select2', 1664 'text': _prompt 1665 }).prependTo(el_container.find('.select2-search-field')).hide(); 1666 } 1667 1668 1669 // SINGLE-SELECT2: Highlight selects with an active value 1670 if ( ! sel_EL.attr('multiple') && sel_EL.hasClass('fc_add_highlight') ) 1671 { 1672 var el = el_container.find('.select2-choice'); 1673 var val = sel_EL.val(); 1674 if (val === null) { 1675 //el.addClass('fc_highlight_disabled'); 1676 } else if (!!val && val.length) { 1677 el.addClass('fc_highlight'); 1678 } else { 1679 el.removeClass('fc_highlight'); 1680 } 1681 } 1682 }); 1683 1684 1685 // MULTI-SELECT2: 1686 s2_elems.on('select2-open', function() 1687 { 1688 1689 // Add events to handle focusing the text filter box (hide inner label) 1690 var sel_EL = jQuery(this); 1691 var el = sel_EL.parent().find('.select2-input'); 1692 var el_label = el.prevAll('.fc_has_inner_label'); 1693 if (el_label) el_label.hide(); 1694 var el_prompt = el.prevAll('.fc_has_inner_prompt'); 1695 if (el_prompt) el_prompt.show(); 1696 1697 1698 // Allow listing already selected options WHEN having class 'select2_fc_checkboxes' 1699 if (sel_EL.hasClass('select2_fc_checkboxes')) { 1700 var els = jQuery('#select2-drop').find('.select2-selected'); 1701 els.addClass('select2-selected-visible').removeClass('select2-selected'); 1702
1703 // Suppress the onchange attribute while selector is open 1704 sel_EL.data('onchange', sel_EL.attr('onchange')); 1705 sel_EL.removeAttr('onchange'); 1706 } 1707 1708 1709 }).on('select2-close', function(e) 1710 { 1711 1712 // Add events to handle bluring the text filter box (show inner label) 1713 var sel_EL = jQuery(this); 1714 1715 // Re-open if this was closed while selecting, FOR select2 v4, use 'select2:closing' instead 1716 if ( sel_EL.data('field_being_selected') ) 1717 { 1718 sel_EL.select2('open'); 1719 jQuery('#select2-drop').find('.select2-no-results').remove(); 1720 return; 1721 } 1722 1723 var el = sel_EL.parent().find('.select2-input'); 1724 var el_label = el.prevAll('.fc_has_inner_label'); 1725 if (el_label) el_label.show(); 1726 var el_prompt = el.prevAll('.fc_has_inner_prompt'); 1727 if (el_prompt) el_prompt.hide(); 1728 1729 // Restore already selected options state 1730 if (sel_EL.hasClass('select2_fc_checkboxes')) { 1731 var els = jQuery('#select2-drop').find('.select2-selected-visible'); 1732 els.removeClass('select2-selected-visible').addClass('select2-selected'); 1733 } 1734 1735 1736 // Restore the onchange attribute when selector closes, running the JS if changes were made 1737 if ( sel_EL.data('onchange') ) 1738 { 1739 sel_EL.attr('onchange', sel_EL.data('onchange')); 1740 sel_EL.data('onchange', null); 1741 } 1742 1743 // Trigger change event on close if this was prevented 1744 if ( sel_EL.data('field_being_edited') ) 1745 { 1746 sel_EL.data('field_being_edited', null); 1747 sel_EL.trigger('change'); 1748 // LEGACY browsers ?? 1749 /*if ( sel_EL.attr('onchange') ) 1750 { 1751 eval(sel_EL.attr('onchange')); 1752 }*/ 1753 } 1754 1755 1756 }).on('select2-selecting', function(e) 1757 { 1758 1759 // Handle toggling MULTI-SELECT2 as checkboxes 1760 var sel_EL = jQuery(this); 1761 if ( sel_EL.attr('multiple') && sel_EL.hasClass('select2_fc_checkboxes') ) 1762 { 1763 var vals = sel_EL.val(); 1764 var nVals = new Array(); 1765 var i = 0; 1766 var found = 0; 1767 if (vals && vals.length) 1768 { 1769 for (var n = 0; n < vals.length; ++n) 1770 { 1771 if (vals[n] != e.val) nVals[i++] = vals[n]; 1772 else found = 1; 1773 } 1774 } 1775 1776 if (!found) nVals[i++] = e.val; 1777 sel_EL.data('set_selected_values', nVals); 1778 sel_EL.data('field_being_edited', true); 1779 sel_EL.data('field_being_selected', true); 1780 } 1781 1782 1783 }).on('change', function(e) 1784 { 1785 1786 // SELECT2: Handle change event 1787 var sel_EL = jQuery(this); 1788 1789 // Clear 'being_selected' FLAG but not the 'being_edited', as this will be done by the 'close' event, also stop event propagation if 'being_edited' 1790 sel_EL.data('field_being_selected', null); 1791 if (sel_EL.data('field_being_edited')) 1792 { 1793 e.preventDefault(); 1794 e.stopPropagation(); 1795 e.stopImmediatePropagation(); 1796 } 1797 1798 var nVals = sel_EL.data('set_selected_values'); 1799 if (nVals) 1800 { 1801 jQuery('#select2-drop').find('.select2-selected-visible, .select2-selected').removeClass('select2-selected-visible').removeClass('select2-selected'); 1802 jQuery('#select2-drop').find('.select2-selected').removeClass('select2-selected-visible').removeClass('select2-selected'); 1803 1804 // Specific values were requested to be set, but first clear data value, to prevent loop in the change event 1805 sel_EL.data('set_selected_values', null).select2('val', nVals).trigger('change'); 1806 } 1807 1808 1809 // SINGLE-SELECT2: 1810 if ( ! sel_EL.attr('multiple') && sel_EL.hasClass('fc_add_highlight') ) 1811 { 1812 // Handle highlighting selected value 1813 var el = jQuery(this).prev('div').find('.select2-choice'); 1814 var val = sel_EL.val(); 1815 if (!!val && val.length) { 1816 el.addClass('fc_highlight'); 1817 } else { 1818 el.removeClass('fc_highlight'); 1819 } 1820 } 1821 1822 1823 // MULTI-SELECT2: 1824 if ( sel_EL.attr('multiple') ) 1825 { 1826 // Allow listing already selected options WHEN having class 'select2_fc_checkboxes' 1827 if (jQuery(this).hasClass('select2_fc_checkboxes')) { 1828 var els = jQuery('#select2-drop').find('.select2-selected'); 1829 els.addClass('select2-selected-visible').removeClass('select2-selected');//.removeClass('select2-result-selectable'); 1830 } 1831 } 1832 1833 }); 1834 1835 1836 // MULTI-SELECT2: Handle highlighting selected value 1837 sbox.find('div.use_select2_lib.select2-container-multi input').on('keydown', function() 1838 { 1839 var el = jQuery(this); 1840 setTimeout(function() { 1841 var val = el.val(); 1842 if (!!val && val.length) { 1843 var el_prompt = el.prevAll('.fc_has_inner_prompt'); 1844 if (el_prompt) el_prompt.hide(); 1845 } else { 1846 var el_prompt = el.prevAll('.fc_has_inner_prompt'); 1847 if (el_prompt) el_prompt.show(); 1848 } 1849 }, 0); 1850 }); 1851 1852 1853 // SELECT2: scrollbar wrap problem 1854 s2_elems.on('loaded open', function() 1855 { 1856 var ul = jQuery('#select2-drop ul.select2-results'); 1857 var needsScroll= ul.prop('scrollHeight') > ul.prop('clientHeight'); 1858 if (needsScroll) ul.css('overflow-y', 'scroll'); 1859 else ul.css('overflow-y', 'auto'); 1860 }); 1861 } 1862 1863 1864 /* Valid HTML for legacy modals using rel, TODO: add more */ 1865 jQuery(document).ready(function() { 1866 jQuery(".modal").each(function(i, el) { 1867 if (jQuery(el).get(0).hasAttribute("data-rel")) jQuery(el).attr("rel", jQuery(el).attr("data-rel")); 1868 }); 1869 }); 1870 1871 1872 /* Restore the given form fields values into the given form */ 1873 function fc_restore_form_field_values(form, data) 1874 { 1875 if (!data) 1876 { 1877 form[0].reset(); 1878 1879 var elements = Array.from(form[0].elements); 1880 for (var i = 0, l = elements.length; i < l; i++) 1881 { 1882 var el = jQuery(elements[i]); 1883 var tagName = elements[i].tagName; 1884 var inputType = tagName != 'INPUT' ? false : elements[i].type; 1885 if (tagName == 'SELECT' || (inputType && inputType!='BUTTON')) 1886 { 1887 el.trigger('change'); 1888 } 1889 } 1890 1891 return; 1892 } 1893 1894 jQuery.each(data, function(name, val) 1895 { 1896 var el = form.find('[name="'+name+'"]'), 1897 type = el.attr('type'); 1898 1899 switch(type) 1900 { 1901 case 'checkbox': el.attr('checked', 'checked'); break; 1902 case 'radio': el.filter('[value="'+val+'"]').attr('checked', 'checked'); break; 1903 default: el.val(val); 1904 } 1905 el.trigger('change'); 1906 }); 1907 } 1908 1909 1910 if (typeof jQuery.fn.serializeObject == "undefined") 1911 { 1912 jQuery.fn.serializeObject = function() 1913 { 1914 var o = {}; 1915 var a = this.serializeArray(); 1916 jQuery.each(a, function() { 1917 if (o[this.name]) { 1918 if (!o[this.name].push) { 1919 o[this.name] = [o[this.name]]; 1920 } 1921 o[this.name].push(this.value || ''); 1922 } else { 1923 o[this.name] = this.value || ''; 1924 } 1925 }); 1926 return o; 1927 } 1928 } 1929 1930 1931 if (typeof fc_isIE == "undefined") 1932 { 1933 window.fc_ie_version_number = null; 1934 fc_isIE = function() 1935 { 1936 if (window.fc_ie_version_number === null) 1937 { 1938 var userAgent = navigator.userAgent.toLowerCase(); 1939 window.fc_ie_version_number = (userAgent.indexOf('msie') != -1) ? parseInt(userAgent.
1939split('msie')[1]) : false; 1940 } 1941 return window.fc_ie_version_number; 1942 } 1943 } 1944 1945 1946 window.fc_has_flash_addon_enabled = false; 1947 fc_has_flash_addon = function() 1948 { 1949 try { 1950 window.fc_has_flash_addon_enabled = Boolean(new ActiveXObject("ShockwaveFlash.ShockwaveFlash")); 1951 } catch(exception) { 1952 window.fc_has_flash_addon_enabled = ("undefined" != typeof navigator.mimeTypes["application/x-shockwave-flash"]); 1953 } 1954 return window.fc_has_flash_addon_enabled; 1955 } 1956 1957 1958 function fc_remove_non_alphanum_chars(text, allowed_chars) 1959 { 1960 var result = ''; 1961 if (!text) return result; 1962 allowed_chars = typeof allowed == 'undefined' ? '' : allowed_chars; 1963 1964 var num_reg = new RegExp('[0-9]+$'); 1965 var allowed_reg = new RegExp('['+allowed_chars+']+$'); 1966 1967 var lower = text.toLowerCase(); 1968 var upper = text.toUpperCase(); 1969 1970 for (var i = 0; i < lower.length; ++i) 1971 { 1972 if (num_reg.test(text[i]) || (lower[i] != upper[i]) || (lower[i].trim() === '')) 1973 { 1974 result += text[i]; 1975 } 1976 else if (allowed_chars.length && allowed_reg.test(text[i])) 1977 { 1978 result += text[i]; 1979 } 1980 } 1981 return result; 1982 } 1983 1984 1985 function fc_attachSingleSlider(cfg, type) 1986 { 1987 var slider_tag_id = cfg.name + (cfg.sfx || ''); 1988 var slider = document.getElementById(slider_tag_id + '_nouislider'); 1989 //if (jQuery(slider).length) { window.console.log('not found slider ID: ' + slider_tag_id + '_nouislider'); return; } 1990 1991 var selectSL = jQuery('#' + slider_tag_id + '-sel'); 1992 var inputSL = document.getElementById(slider_tag_id + '-val'); 1993 var isSingle = 1; 1994 !!type || (type = 2); // 1: drop-down select , 2: slider (default type) 1995 1996 var IEversion = fc_isIE(); 1997 var is_IE8 = IEversion && IEversion < 9; 1998 var use_select = is_IE8 || type == 1; 1999 if (use_select) 2000 { 2001 if (selectSL.length) 2002 { 2003 var selected; 2004 jQuery.each(cfg.step_values, function(key, value) 2005 { 2006 selectSL.append( 2007 jQuery('<option></option>') 2008 .attr('value', cfg.step_values[key]) 2009 .text(cfg.step_labels[key]) 2010 ); 2011 }); 2012 2013 selectSL 2014 .val(cfg.step_values[cfg.initial_pos]) 2015 .on('change', function(e, data) { 2016 var slider_input = jQuery('#' + slider_tag_id + '-val').get(0); 2017 2018 if (cfg.element_class_list != '') 2019 { 2020 jQuery(cfg.element_selector).removeClass(cfg.element_class_list).addClass(cfg.element_class_prefix + selectSL.val()); 2021 }
2022 if (cfg.elem_container_class != '') 2023 { 2024 jQuery(cfg.elem_container_selector).removeClass(cfg.elem_container_class).addClass(cfg.elem_container_prefix + selectSL.val()); 2025 } 2026 2027 fclib_setCookie(slider_input.name, selectSL.val(), 0); // nDays 0 , aka no expiration date, keep cookie till browser closes 2028 }) 2029 .css('display', ''); // avoid show() it adds display: block 2030 } 2031 return; 2032 } 2033 slider.style.display = ''; 2034 2035 var step_values = cfg.step_values; 2036 var step_labels = cfg.step_labels; 2037 2038 noUiSlider.create(slider, { 2039 start: cfg.initial_pos, 2040 connect: false, 2041 step: 1, 2042 range: {'min': 0, 'max': (cfg.step_values.length - 1)}, 2043 }); 2044 if (!!cfg.start_hidden) jQuery(slider).hide(); 2045 2046 var tipHandles = slider.getElementsByClassName('noUi-handle'), 2047 tooltips = []; 2048 2049 // Add divs to the slider handles. 2050 for ( var i = 0; i < tipHandles.length; i++ ) 2051 { 2052 tooltips[i] = document.createElement('span'); 2053 tipHandles[i].appendChild(tooltips[i]); 2054 2055 tooltips[i].className += 'fc-sliderTooltip fc-bottom'; // Add a class for styling 2056 tooltips[i].innerHTML = '<span></span>'; // Add additional markup 2057 tooltips[i] = tooltips[i].getElementsByTagName('span')[0]; // Replace the tooltip reference with the span we just added 2058 } 2059 2060 // When the slider changes, display the value in the tooltips and set it into the input form elements 2061 slider.noUiSlider.on('update', function( values, handle ) { 2062 var value = parseInt(values[handle]); 2063 var i = value; 2064 2065 if ( handle ) { 2066 alert('This slider does not have a right handler'); 2067 } else { 2068 inputSL.value = typeof step_values[value] !== 'undefined' ? step_values[value] : value; 2069 } 2070 var tooltip_text = typeof step_labels[value] !== 'undefined' ? step_labels[value] : value; 2071 var max_len = 36; 2072 tooltips[handle].innerHTML = '<span class=\"icon-image\"></span> ' + 2073 (tooltip_text.length > max_len+4 ? tooltip_text.substring(0, max_len)+' ...' : tooltip_text); 2074 var left = jQuery(tooltips[handle]).closest('.noUi-origin').position().left; 2075 var width = jQuery(tooltips[handle]).closest('.noUi-base').width(); 2076 2077 //window.console.log ('handle: ' + handle + ', left : ' + left + ', width : ' + width); 2078 if (isSingle) { 2079 left<(50/100)*width ? 2080 jQuery(tooltips[handle]).parent().removeClass('fc-left').addClass('fc-right') : 2081 jQuery(tooltips[handle]).parent().removeClass('fc-right').addClass('fc-left'); 2082 } 2083 else { 2084 alert('This slider only has 1 handle'); 2085 } 2086 }); 2087 2088 // Handle form autosubmit 2089 slider.noUiSlider.on('change', function() { 2090 var slider = jQuery('#' + slider_tag_id + '_nouislider'); 2091 var slider_input = jQuery('#' + slider_tag_id + '-val').get(0); 2092 2093 if (cfg.element_class_list != '') 2094 { 2095 jQuery(cfg.element_selector).removeClass(cfg.element_class_list).addClass(cfg.element_class_prefix + slider_input.value); 2096 }
2097 if (cfg.elem_container_class != '') 2098 { 2099 jQuery(cfg.elem_container_selector).removeClass(cfg.elem_container_class).addClass(cfg.elem_container_prefix + slider_input.value); 2100 } 2101 2102 fclib_setCookie(slider_input.name, slider_input.value, 0); // nDays 0 , aka no expiration date, keep cookie till browser closes 2103 }); 2104 2105 inputSL.addEventListener('change', function(){ 2106 var value = 0; // default is first value = empty 2107 for(var i=1; i<step_values.length-1; i++) 2108 { 2109 if (step_values[i] == this.value) { value=i; break; } 2110 } 2111 slider.noUiSlider.set([value, null]); 2112 }); 2113 } 2114 2115 2116 2117 // Toggle elements of all other views when switching between views (e.g. details / thumbnails views) 2118 function fc_toggle_view_mode(new_btn) 2119 { 2120 var btns = new_btn.parent().children(); 2121 2122 btns.removeClass('active'); 2123 btns.each(function(index, value) 2124 { 2125 var btn = jQuery(value); 2126 jQuery(btn.data('toggle_selector')).hide(); 2127 }); 2128 2129 new_btn.addClass('active'); 2130 jQuery(new_btn.data('toggle_selector')).show().css('display', '').css('visibility', ''); 2131 } 2132 2133 2134 2135 // Create a sanitized filename similar to what server-side code will accept 2136 fc_sanitize_filename = function(text) 2137 { 2138 if (!text) return ''; 2139 2140 var validChars = new RegExp('[A-Za-z0-9\.\_\-]+'); 2141 var result = ''; 2142 2143 for (var i = 0; i < text.length; ++i) 2144 { 2145 if (validChars.test(text[i])) 2146 { 2147 result += text[i]; 2148 } 2149 } 2150 return result; 2151 } 2152 2153 2154 2155 // Submit a form in parent window from a jQuery modal 2156 fc_parent_form_submit = function(container_id, form_id, fields, options) 2157 { 2158 var form = window.parent.document.getElementById(form_id); 2159 var task = typeof options.task !== 'undefined' ? options.task : false; 2160 var is_list = typeof options.is_list !== 'undefined' ? options.is_list : false; 2161 var is_jform = typeof options.is_jform !== 'undefined' ? options.is_jform : false; 2162 2163 for (var field_name in fields) 2164 { 2165 form.elements[field_name].value = fields[field_name]; 2166 } 2167 2168 if (is_list && form.boxchecked.value==0) 2169 { 2170 alert(Joomla.JText._('FLEXI_NO_ITEMS_SELECTED')); 2171 return; 2172 } 2173 2174 // *** 2175 // *** Submit progress bar 2176 // *** 2177 2178 if (typeof form.progressbar_submit_handler_success === 'undefined' || !form.progressbar_submit_handler_success) 2179 { 2180 form.progressbar_submit_handler_success = true; 2181 // Default to doing animation 2182 form.doanimated_submit = typeof form.doanimated_submit === 'undefined' ? 1 : 0; 2183 2184 form.addEventListener('submit', function(e) 2185 { 2186 if ( !form.doanimated_submit ) 2187 { 2188 return true; 2189 } 2190 //form.doanimated_submit = 0; // Clear FLAG until next time Joomla.submitform() is called 2191 2192 var fc_filter_form_blocker = jQuery('#fc_filter_form_blocker'); 2193 2194 if (!fc_filter_form_blocker.length) 2195 { 2196 fc_filter_form_blocker = jQuery( 2197 '<div id="fc_filter_form_blocker">' + 2198 '<div class="fc_blocker_overlay"></div>' + 2199 '<div class="fc_blocker_content">' + 2200 '<div class="fc_blocker_logo></div>' + 2201 '<div class="fc_blocker_mssg>' + Joomla.JText._('FLEXI_LOADING') + '</div>' + 2202 '<div class="fc_blocker_bar"><div></div></div>' + 2203 '</div>' + 2204 '</div>' 2205 ).prependTo(jQuery('body')); 2206 } 2207 2208 if (fc_filter_form_blocker) 2209 { 2210 fc_filter_form_blocker.css("display", "block"); 2211 fc_filter_form_blocker.find('.fc_blocker_mssg').html(Joomla.JText._('FLEXI_LOADING')); 2212 fc_admin_progress(95, jQuery('#fc_filter_form_blocker .fc_blocker_bar')); 2213 } 2214 }); 2215 } 2216 2217 // Close modal to allow click events to work on the parent window 's form 2218 jQuery('#'+container_id).dialog('close'); 2219 2220 // If it is a Joomla form 2221 if (is_jform) 2222 { 2223 window.parent.Joomla.submitbutton(task); 2224 return; 2225 } 2226 2227 // For proper submit, append a hidden submit button to the form and click it, then remove it if submit was prevented 2228 var button = document.createElement('input'); 2229 button.style.display = 'none'; 2230 button.type = 'submit'; 2231 form.appendChild(button).click(); 2232 form.removeChild(button); 2233 } 2234 2235 2236 2237 //******************************* 2238 //*** START OF fc_init*() methods 2239 //******************************* 2240 2241 2242 /* 2243 * Initialize CSS styles and effects 2244 */ 2245 function fc_initDynamicLayoutJsCss(container_id, reAddOnEvents, html) 2246 { 2247 const container_sel = '#' + container_id; 2248 jQuery(container_sel).html(html); 2249 2250 tabberAutomatic(tabberOptions, container_id); 2251 fc_bindFormDependencies(container_sel, 0, ''); 2252 2253 fc_initBootstrap(null, container_sel, reAddOnEvents); 2254 fc_initTooltips(null, container_sel, reAddOnEvents); 2255 fc_initCodeMirror(null, container_sel, reAddOnEvents); 2256 fc_initMinicolors(null, container_sel, reAddOnEvents); 2257 fc_initSubform(null, container_sel); 2258 2259 if (typeof(fcrecord_attach_sortable) == 'function') fcrecord_attach_sortable(container_sel); 2260 if (typeof(fcfield_attach_sortable) == 'function') fcfield_attach_sortable(container_sel); 2261 2262 fc_initSelect2(null, container_sel, reAddOnEvents); 2263 } 2264 2265 2266 /* 2267 * Initialize bootstrap styles and effects 2268 */ 2269 function fc_initBootstrap(event, container_sel, reAddOnEvents) 2270 { 2271 const container_el = jQuery(container_sel); 2272 2273 // Also run method on given "Add" events, e.g. 'subform-row-add'
2274 (reAddOnEvents || []).forEach(element => container_el.on(element, fc_initBootstrap)); 2275 2276 // Add bootstap styless and effects 2277 fc_bootstrapAttach(container_el); 2278 } 2279 2280 2281 /* 2282 * Initialize tooltips and popovers 2283 */ 2284 function fc_initTooltips(event, container_sel, reAddOnEvents) 2285 { 2286 const container_el = jQuery(container_sel); 2287 const elements_set_tooltip = container_el.find('.hasTooltip'); 2288 const elements_set_popover = container_el.find('.hasPopover'); 2289 2290 if (typeof jQuery === undefined || typeof jQuery.tooltip === undefined) 2291 { 2292 elements_set_tooltip.length && !!Joomla.fc_debug ? window.console.log('tooltip() not loaded. Skipping it') : false; 2293 } 2294 if (typeof jQuery === undefined || typeof jQuery.popover === undefined) 2295 { 2296 elements_set_popover.length && !!Joomla.fc_debug ? window.console.log('popover() not loaded. Skipping it') : false; 2297 } 2298 if (typeof jQuery === undefined || (typeof jQuery.tooltip === undefined && typeof jQuery.popover === undefined)) 2299 { 2300 return; 2301 } 2302 2303 // Also run method on given "Add" events, e.g. 'subform-row-add' 2304 (reAddOnEvents || []).forEach(element => container_el.on(element, fc_initTooltips)); 2305 2306 // Add tooltips and popovers 2307 typeof jQuery.tooltip !== undefined ? elements_set_tooltip.tooltip({html: true, container: container_el}) : false; 2308 typeof jQuery.popover !== undefined ? elements_set_popover.popover({html: true, container: container_el, trigger : 'hover focus'}) : false; 2309 } 2310 2311 2312 /* 2313 * Initialize select2 behaviour 2314 */ 2315 function fc_initSelect2(event, container_sel, reAddOnEvents) 2316 { 2317 const container_el = jQuery(container_sel); 2318 const elements_set = container_el.find('select.use_select2_lib'); 2319 2320 if (typeof jQuery === undefined || typeof jQuery.select2 === undefined) 2321 { 2322 elements_set.length && !!Joomla.fc_debug ? window.console.log('subformRepeatable() not loaded. Skipping it') : false; 2323 return; 2324 } 2325 2326 // Also run method on given "Add" events, e.g. 'subform-row-add' 2327 (reAddOnEvents || []).forEach(element => container_el.on(element, fc_initSelect2)); 2328 2329 // Attach select2 2330 fc_attachSelect2(container_el, elements_set); 2331 } 2332 2333 2334 function fc_initCodeMirror(event, container_sel, reAddOnEvents) 2335 { 2336 const container_el = jQuery(container_sel); 2337 const elements_set = container_el.find('textarea.codemirror-source'); 2338 2339 if (typeof Joomla.editors === undefined || typeof CodeMirror === undefined) 2340 { 2341 elements_set.length && !!Joomla.fc_debug ? window.console.log('CodeMirror not loaded. Skipping it') : false; 2342 return; 2343 } 2344 2345 // Also run method on given "Add" events, e.g. 'subform-row-add' 2346 (reAddOnEvents || []).forEach(element => container_el.on(element, fc_initCodeMirror)); 2347 2348 elements_set.each(function () { 2349 var input = jQuery(this).removeClass('codemirror-source'); 2350 var id = input.prop('id'); 2351 2352 Joomla.editors.instances[id] = CodeMirror.fromTextArea(this, input.data('options')); 2353 }); 2354 } 2355 2356 2357 2358 /* 2359 * Initialize subform fields 2360 */ 2361 function fc_initSubform (event, container_sel) 2362 { 2363 const container_el = jQuery(container_sel); 2364 const elements_set = container_el.find('div.subform-repeatable'); 2365 2366 if (typeof jQuery === undefined || typeof jQuery.subformRepeatable) 2367 { 2368 elements_set.length && !!Joomla.fc_debug ? window.console.log('subformRepeatable() not loaded. Skipping it') : false; 2369 return; 2370 } 2371 elements_set.subformRepeatable(); 2372 } 2373 2374 2375 /* 2376 * Initialize any minicolor fields 2377 */ 2378 function fc_initMinicolors(event, container_sel, reAddOnEvents) 2379 { 2380 const container_el = jQuery(container_sel); 2381 const elements_set = container_el.find('.minicolors'); 2382 2383 if (typeof jQuery === undefined || typeof jQuery.minicolors === undefined) 2384 { 2385 elements_set.length && !!Joomla.fc_debug ? window.console.log('minicolors() not loaded. Skipping it') : false; 2386 return; 2387 } 2388 2389 // Also run method on given "Add" events, e.g. 'subform-row-add' 2390 (reAddOnEvents || []).forEach(element => container_el.on(element, fc_initMinicolors)); 2391 2392 elements_set.each(function() { 2393 var $this = jQuery(this); 2394 var format = $this.data('validate') === 'color' ? 'hex' : $this.data('format') || 'hex'; 2395 2396 $this.minicolors({ 2397 control: $this.data('control') || 'hue', 2398 format: format === 'rgba' ? 'rgb' : format, 2399 keywords: $this.data('keywords') || '', 2400 opacity: format === 'rgba', 2401 position: $this.data('position') || 'default', 2402 theme: $this.data('theme') || 'bootstrap', 2403 }); 2404 }); 2405 } 2406 2407 2408 //***************************** 2409 //*** END OF fc_init*() methods 2410 //***************************** 2411 2412 2413 2414 /* 2415 * Allow custom input in date fields having the custom text class 2416 */ 2417 document.addEventListener('DOMContentLoaded', function() 2418 { 2419 if (typeof JoomlaCalendar != 'undefined') 2420 { 2421 var JoomlaCalendar_setAltValue_fc = JoomlaCalendar.prototype.setAltValue; 2422 JoomlaCalendar.prototype.setAltValue = function() 2423 { 2424 if (this.inputField.classList.contains('fc_date_allow_text')) 2425 { 2426 return; 2427 } 2428 return JoomlaCalendar_setAltValue_fc.call(this, arguments); 2429 }; 2430 2431 var JoomlaCalendar_init_fc = JoomlaCalendar.init; 2432 JoomlaCalendar.init = function() 2433 { 2434 var result = JoomlaCalendar_init_fc.apply(null, arguments); 2435 2436 var element = arguments[0]; 2437 var input = element ? element.getElementsByTagName('input')[0] : false;
2438 2439 if (input) 2440 { 2441 if (!!input.id && input.classList.contains('fc_date_allow_text')) 2442 { 2443 input.value = document.getElementById(input.id + '_fc_value').getAttribute('data-fc-value'); 2444 } 2445 } 2446 2447 return result; 2448 } 2449 } 2450 });
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.