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]).prop("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 //console.log('Updated columns selector cookie'); 1169 1170 var totals_tag = jQuery('#columnchoose_totals'); 1171 if (totals_tag.length) 1172 { 1173 totals_tag.html(col_selectors.length == col_selected.length ? '' : ' '+(col_selected.length - col_selectors.length)); 1174 } 1175 } 1176 1177 1178 // *** Create column choosers row for a table. NOTE must have <th> cells at row 0 1179 function create_column_choosers(container_div_id, data_tbl_id, firstload, start_text, end_text, toggle_on_init) 1180 { 1181 // 1. Get column-status array for the table with id: data_tbl_id 1182 var show_col = eval('show_col_'+data_tbl_id); 1183 1184 // 2. Get table and its first row and then the 'th' cells in it 1185 var firstrow = jQuery("#"+data_tbl_id+" thead tr:first"); //document.getElementById(data_tbl_id); 1186 var thcells = firstrow.find('th'); 1187 1188 // 3. Iterate through the 'th' cells and create column hiders for those having the class 'hideOnDemandClass' 1189 var str = (typeof start_text != "undefined") ? start_text : ''; 1190 1191 for (var col = 0; col < thcells.length; col++) 1192 { 1193 // 4. Skip if not having 'hideOnDemandClass' class 1194 if (!jQuery(thcells[col]).hasClass('hideOnDemandClass')) continue; 1195 1196 // 5. Get column name 1197 var column_toggle_lbl = jQuery(thcells[col]).find('.column_toggle_lbl'); 1198 var col_display_name = column_toggle_lbl.length ? column_toggle_lbl.html() : jQuery(thcells[col]).text(); 1199 column_toggle_lbl.remove(); 1200 1201 // 6. Show / Hide current column 1202 if ( ( !firstload && !js_isset(show_col[col]) ) || ( jQuery(thcells[col]).hasClass('initiallyHidden') && !js_isset(show_col[col]) ) ) 1203 { 1204 var checked_str = ''; 1205 var fontcolor_str = 'black';//var fontcolor_str = '#aaaaaa'; 1206 1207 // *** It has value of 0 or not set, set it to 1 for fc_tbl_toggle_column() function to hide it 1208 show_col[col] = 1; 1209 if (toggle_on_init) fc_tbl_toggle_column(container_div_id, data_tbl_id, col, 1); 1210 } 1211 else 1212 {
1213 var checked_str = 'checked="checked"'; 1214 var fontcolor_str = 'black'; //var fontcolor_str = 'black'; 1215 1216 // *** It has value of 1 or not set, set it to 0 for fc_tbl_toggle_column() function to show it 1217 show_col[col] = 0; 1218 if (toggle_on_init) fc_tbl_toggle_column(container_div_id, data_tbl_id, col, 1); 1219 } 1220 1221 // 7. Create column checkbox and append it to str 1222 var ffieldid = 'columnchoose_' + data_tbl_id + '_' + col; 1223 var ffieldname = 'columnchoose_' + data_tbl_id + '[' + col + ']'; 1224 str = str + '<li><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);">' 1225 + '<label id="' + ffieldid + '_label" style="color:'+fontcolor_str+';" for="' + ffieldid + '">' + col_display_name + '</label></li>'; 1226 } 1227 1228 // 8. Fill in 'column choose box' 1229 str = '<span id="'+container_div_id+'_cols"><ul>' + str + '</ul></span>' + end_text; 1230 document.getElementById(container_div_id).innerHTML=str; 1231 1232 // 9. Update cookie data and display data 1233 column_toggles_update_data(container_div_id, data_tbl_id); 1234 } 1235 1236 1237 /* Set a cookie */ 1238 function fclib_setCookie(cookieName, cookieValue, nDays, samesite="lax") 1239 { 1240 var today = new Date(); 1241 var expires = new Date(); 1242 var path = typeof jclient_path_fc != 'undefined' ? jclient_path_fc : window.location.hostname; 1243 if (nDays==null || nDays<0) nDays=0; 1244 1245 if (nDays) 1246 { 1247 expires.setTime(today.getTime() + 3600000*24*nDays); 1248 document.cookie = cookieName+"="+encodeURIComponent(cookieValue) + ";samesite=" + samesite + ";path=" + path + ";expires=" + expires.toGMTString(); 1249 } else { 1250 // nDays 0 , aka no expiration date, keep cookie till browser closes 1251 document.cookie = cookieName+"="+encodeURIComponent(cookieValue) + ";samesite=" + samesite + ";path=" + path; 1252 } 1253 //alert(cookieName+"="+encodeURIComponent(cookieValue) + ";path=" + path); 1254 } 1255 1256 1257 /* Get a cookie */ 1258 function fclib_getCookie(cookieName) 1259 { 1260 let matched = document.cookie.match(new RegExp('(^|;\\s*)' + cookieName + '=([^;]+)')); 1261 return matched ? decodeURIComponent(matched[2]) : ''; 1262 } 1263 1264 1265 /* Get a new list of 2-typles (key, element) living inside a cookie 1266 * List is an object with 'key' being the property name and 'element' being the value of the property 1267 */ 1268 function fclib_createCookieList(cookieName, nDays) 1269 { 1270 var cookieValue = fclib_getCookie(cookieName); 1271 var items = jQuery.parseJSON(cookieValue ? cookieValue : '{}'); 1272 nDays = nDays || 90; 1273 1274 return { 1275 // Add to the items 1276 "add": function(key, element) 1277 { 1278 items[key] = element; 1279 fclib_setCookie(cookieName, JSON.stringify(items), nDays); 1280 }, 1281 1282 // Remove from items 1283 "remove": function (key) 1284 { 1285 if (typeof items[key] != 'undefined') 1286 { 1287 delete items[key]; 1288 fclib_setCookie(cookieName, JSON.stringify(items), nDays); 1289 } 1290 }, 1291 1292 // Clear items 1293 "clear": function() 1294 { 1295 items = {}; 1296 fclib_setCookie(cookieName, JSON.stringify(items), nDays); 1297 }, 1298 1299 // Get all the items 1300 "items": function() 1301 { 1302 return items; 1303 } 1304 } 1305 } 1306 1307 1308 /* Remove known textarea editors, optionally add a flag to restore editors laters */ 1309 function fc_removeAreaEditors(txtareas, addRestoreClass) 1310 { 1311 addRestoreClass = typeof addRestoreClass != 'undefined' ? addRestoreClass : 0; 1312 1313 // Remove known JS editors 1314 txtareas.each(function(i, txtarea) 1315 { 1316 var areaid = jQuery(txtarea).attr('id'); 1317 1318 var hasTinyMCE = !!(!areaid || typeof tinyMCE === 'undefined' ? false : tinyMCE.get(areaid)); 1319 if (hasTinyMCE) { 1320 tinyMCE.majorVersion >= 4 ? 1321 tinymce.remove('#'+areaid) : 1322 tinymce.EditorManager.execCommand('mceRemoveEditor', false, areaid) ; 1323 if (addRestoreClass) jQuery(txtarea).addClass('fc_hadTinyMCE'); 1324 } 1325 1326 var hasCodeMirror = typeof CodeMirror === 'undefined' ? false : jQuery(txtarea).first().next().hasClass('CodeMirror'); 1327 if (hasCodeMirror) { 1328 jQuery(txtarea).first().next().get(0).CodeMirror.toTextArea(); 1329 if (addRestoreClass) jQuery(txtarea).addClass('fc_hadCodeMirror'); 1330
1331 // Remove codemirror container in case that removing it failed 1332 if (jQuery(txtarea).first().next('.CodeMirror').length) jQuery(txtarea).first().next('.CodeMirror').remove(); 1333 } 1334 }); 1335 } 1336 1337 1338 /* Restore known textarea editors to textareas with respective class */ 1339 function fc_restoreAreaEditors(txtareas) 1340 { 1341 fc_attachTinyMCE( txtareas.filter('.fc_hadTinyMCE') ); 1342 fc_attachCodeMirror( txtareas.filter('.fc_hadCodeMirror') ); 1343 } 1344 1345 1346 /* Attach tinyMCE with default settings */ 1347 function fc_attachTinyMCE(txtareas, MCEoptions, mceFieldname) 1348 { 1349 // Create a copy of the options, so that we do not modify the original options objet 1350 var _MCEoptions = typeof MCEoptions!=='undefined' ? jQuery.extend({}, MCEoptions) : {}; 1351 mceFieldname = typeof mceFieldname!=='undefined' ? mceFieldname : false; 1352 1353 var theArea, areaID; 1354 txtareas.each(function(i, txtarea) 1355 { 1356 var theArea = jQuery(txtarea); 1357 var areaID = theArea.attr('id'); 1358 1359 // Remove tinymce classes from the textarea 1360 theArea.removeClass('mce_editable'); 1361 1362 // J3.7.0+ (with integrated XTD buttons) is using new setup method 1363 if (typeof mceFieldname!=='undefined' && typeof Joomla.JoomlaTinyMCE != 'undefined' && typeof MCEoptions.joomlaExtButtons != 'undefined') 1364 { 1365 var tinyMCEOptions = {}; 1366 tinyMCEOptions[mceFieldname] = _MCEoptions; 1367 Joomla.JoomlaTinyMCE.setupEditor(jQuery('#' + areaID).get(0), {tinyMCE: tinyMCEOptions}); 1368 } 1369 else if (tinyMCE.majorVersion >= 4) 1370 { 1371 _MCEoptions.selector = '#' + areaID; 1372 tinyMCE.init(_MCEoptions); 1373 //tinyMCE.EditorManager.execCommand('mceAddEditor', true, areaID); //var editor = tinyMCE.get(areaid); //tinyMCE.editors[areaID]; 1374 } 1375 else 1376 { 1377 _MCEoptions.mode = 'exact'; 1378 _MCEoptions.elements = areaID; 1379 tinyMCE.init(_MCEoptions); 1380 //tinyMCE.EditorManager.execCommand('mceAddControl', true, areaID); //var editor = tinymce.EditorManager.get(area_id); // tinyMCE.editors[areaID]; 1381 } 1382 1383 // Some cleanups for proper display 1384 theArea.addClass('mce_editable'); 1385 theArea.parent().children('.mce-container').css('display', ''); // allow editor container to stretch to the full width of its external container 1386 }); 1387 1388 return txtareas.length==1 ? tinyMCE.get(areaID) : true; 1389 } 1390 1391 1392 /* Attach CodeMirror with optional settings */ 1393 function fc_attachCodeMirror(txtareas, CMoptions) 1394 { 1395 CMoptions = typeof CMoptions!=='undefined' ? CMoptions : { 1396 mode: 'application/x-httpd-php', 1397 indentUnit: 2, 1398 lineNumbers: true, 1399 matchBrackets: true, 1400 lineWrapping: true, 1401 onCursorActivity: function(CM) 1402 { 1403 CM.setLineClass(hlLine, null); 1404 hlLine = CM.setLineClass(CM.getCursor().line, 'activeline'); 1405 } 1406 }; 1407 1408 var editor, theArea; 1409 txtareas.each(function(i, txtarea) 1410 { 1411 theArea = jQuery(txtarea); 1412 theArea.removeClass(); // Remove all classes from the textarea 1413 editor = CodeMirror.fromTextArea(theArea.get(0), CMoptions); 1414 editor.refresh(); 1415 }); 1416 1417 return txtareas.length==1 ? editor : true; 1418 } 1419 1420 1421 /* Toggle box via a button and set CSS class to indicate that it is open */ 1422 function fc_toggle_box_via_btn(theBox, btn, btnClass, btnNew, mode, cookieName) 1423 { 1424 var box = typeof theBox=='string' ? jQuery('#'+theBox) : theBox; 1425 1426 if (btnNew) 1427 { 1428 // Show but remove 'display' property to allow CSS classes to take effect (possibly hiding it) 1429 btnNew.show().css('display', ''); 1430 jQuery(btn).hide(); 1431 } 1432 var cookieName = !!cookieName ? (typeof cookieName=='string' ? cookieName : theBox + '-disp') : false; 1433 //window.console.log(cookieName); 1434 1435 if ( 1436 (typeof mode!=='undefined' && parseInt(mode)) || // use the mode provided 1437 (typeof mode==='undefined' && box.is(':hidden')) // if any of the elements collection 'box' is hidden then open them all 1438 ) { 1439 if (cookieName) fclib_setCookie(cookieName, 1, 0); // nDays 0 , aka no expiration date, keep cookie till browser closes 1440 jQuery(btn).data('fc_noeffect') || jQuery(btn).hasClass('fc_noeffect') ? 1441 box.show() : 1442 box.slideDown(400) ; 1443 // Only remove 'data-fc_noeffect' but not the fc_noeffect class 1444 jQuery(btn).addClass(btnClass).data('fc_noeffect', null); 1445 } 1446 else 1447 { 1448 if (cookieName) fclib_setCookie(cookieName, 0, 0); // nDays 0 , aka no expiration date, keep cookie till browser closes 1449 jQuery(btn).data('fc_noeffect') || jQuery(btn).hasClass('fc_noeffect') ? 1450 box.hide() : 1451 box.slideUp(400) ; 1452 // Only remove 'data-fc_noeffect' but not the fc_noeffect class 1453 jQuery(btn).removeClass(btnClass).data('fc_noeffect', null); 1454 } 1455 } 1456 1457 1458 /* Disable/enable a check box group e.g. when 'Use Global' option is toggled */ 1459 function fc_toggle_checkbox_group(containerID, useGlobalElement) 1460 { 1461 var container = jQuery('#'+containerID); 1462 var inputs = container.find('input'); 1463 el = jQuery(useGlobalElement); 1464 if ( el.is(':checked') ) { 1465 inputs.each(function(index){ 1466 jQuery(this).attr('disabled', true); 1467 }); 1468 } else { 1469 inputs.each(function(index){ 1470 jQuery(this).attr('disabled', false); 1471 }); 1472 } 1473 el.attr('disabled', false); 1474 } 1475 1476 1477 /* Auto-resize the currently open dialog vertically or horizontally */ 1478 function fc_dialog_resize_now(boxWsel, boxHsel, contentSel) 1479 { 1480 boxWsel = typeof boxWsel != 'undefined' ? boxWsel : '.ui-dialog.fc-autow-dialog'; 1481 boxHsel = typeof boxHsel != 'undefined' ? boxHsel : '.ui-dialog.fc-autoh-dialog'; 1482 contentSel = typeof contentSel != 'undefined' ? contentSel : '.ui-dialog-content'; 1483 1484 // Resize the modal(s) 1485 var dialogs = jQuery(boxWsel + ' , '+ boxHsel); 1486 dialogs.each(function( index ) 1487 { 1488 var dialog_box = jQuery(this); 1489 var theDialog = dialog_box.data('fc_dialog'); 1490 if (theDialog) 1491 { 1492 var params = theDialog.data('fc_dialog_params'); 1493 var maxwidth = theDialog.data('fc_dialog_maxwidth'); 1494 var maxheight = theDialog.data('fc_dialog_maxheight'); 1495 params = params || {}; 1496 maxwidth = maxwidth || 0; 1497 maxheight = maxheight || 0; 1498 params = fc_getAutoSizePos(maxwidth, maxheight, params); 1499 1500 dialog_box 1501 .css({ 'left': params.winleft+'px', 'width': params.winwidth+'px' }) 1502 .css({ 'top': params.wintop+'px', 'height': params.winheight+'px' }); 1503 } 1504 }); 1505 1506 // Parameters for modal that should take full window 1507 var dialog_box_sbox = jQuery('#sbox-window'); 1508 var dialog_box_jmedia = jQuery('div.field-media-wrapper > div.modal'); 1509 1510 if (dialog_box_sbox.length || dialog_box_jmedia.length) 1511 { 1512 params = fc_getAutoSizePos(0, 0, {}); 1513 1514 // Maximize sbox modal 1515 if (dialog_box_sbox.length) 1516 { 1517 dialog_box_sbox 1518 .css({ 'position': 'fixed' }) 1519 .css({ 'left': params.winleft+'px', 'width': (params.winwidth-40)+'px' }) 1520 .css({ 'top': params.wintop+'px', 'height': (params.winheight-20)+'px' }) 1521 .find('#sbox-content').children('iframe') 1522 .removeAttr('width').removeAttr('height').css({ 'width': '100%', 'height': '100%' }); 1523 } 1524 1525 // Maximize joomla media modal 1526 if (dialog_box_jmedia.length) 1527 { 1528 dialog_box_jmedia.css({ 'top': (params.wintop-30)+'px', 'height': (params.winheight-60)+'px' }); 1529 } 1530 } 1531 1532 // Fix modal's inner container adding unneeded scrollbar 1533 var dialogs = jQuery(boxHsel); 1534 dialogs.each(function( index ) 1535 { 1536 var dialog_box = jQuery(this); 1537 var content_box = dialog_box.find(contentSel); 1538 var h = dialog_box.height() - content_box.prev().outerHeight(true) - content_box.next().outerHeight(true); 1539 content_box.css({ 'height': h+'px', 'margin': '0', 'box-sizing': 'border-box' }); 1540 1541 // Remove unneeded scroll bar inside iframe document, new browser security disallows this ? 1542 //var body = content_box.find('iframe').contents().find('body'); 1543 //body.css({ 'height': 'unset' }); 1544 }); 1545 } 1546 1547 1548 /* Debounced function execution by the given 'wait' time, forcing single function execution within the given 'wait' time */ 1549 function fc_debounce_exec(func, wait, immediate, func_context) 1550 { 1551 var timeout; 1552 return function() { 1553 var context = func_context || this, args = arguments; 1554 var later = function() { 1555 timeout = null;
1556 if (!immediate) func.apply(context, args); 1557 }; 1558 var callNow = immediate && !timeout; 1559 clearTimeout(timeout); 1560 timeout = setTimeout(later, wait); 1561 if (callNow) func.apply(context, args); 1562 }; 1563 } 1564 1565 var fc_dialog_resize = fc_debounce_exec(fc_dialog_resize_now, 200, false, null); 1566 1567 jQuery(window).resize(function() { 1568 fc_dialog_resize(); 1569 }); 1570 1571 1572 /* Apply select2 JS to targeted elements */ 1573 function fc_attachSelect2(sel, s2_elems) 1574 { 1575 sel = typeof sel !== 'undefined' && sel ? sel : 'body'; 1576 var sbox = jQuery(sel); 1577 1578 s2_elems = s2_elems || sbox.find('select.use_select2_lib'); 1579 1580 if (window.skip_select2_js) 1581 { 1582 s2_elems.removeClass('use_select2_lib').addClass('fc_isselect fc_ismobile fc_no_js_attach'); 1583 //s2_elems.filter(function(){return !jQuery(this).attr('multiple');}) 1584 sbox.find('.fc_mobile_label').show(); 1585 return; 1586 } 1587 1588 1589 // Attach select2 to specific to select elements having specific CSS class, for select-multiple show values as togglable checkboxes 1590 s2_elems.each(function() 1591 { 1592 function fc_formatSel2Option(item) 1593 { 1594 var data_title = jQuery(item.element).attr('data-title'); 1595 return !data_title ? item.text : "<div title='" + data_title + "'>" + item.text + "</div>"; 1596 } 1597 1598 var sel_EL = jQuery(this); 1599 1600 var sel2ops = { 1601 minimumResultsForSearch: 10, 1602 formatResult: fc_formatSel2Option 1603 }; 1604 1605 if ( sel_EL.hasClass('fc_select2_noselect') ) 1606 { 1607 sel2ops.formatNoMatches = function() { return ''; }; 1608 sel2ops.dropdownCssClass = 'select2-hidden'; 1609 sel2ops.minimumResultsForSearch = -1; 1610 } 1611 if (sel_EL.attr('multiple') && !sel_EL.hasClass('fc_select2_no_check')) 1612 { 1613 sel2ops.closeOnSelect = false; 1614 } 1615 1616 if (sel_EL.attr('multiple') && !sel_EL.hasClass('fc_select2_no_check')) 1617 { 1618 sel_EL.select2(sel2ops).addClass('select2_fc_checkboxes'); 1619 } else 1620 { 1621 sel_EL.select2(sel2ops); 1622 } 1623 1624 // Set initially selected data (this allows setting order too) 1625 if ( sel_EL.get(0).hasAttribute('data-select2-initdata') ) 1626 { 1627 sel_EL.select2('data', sel_EL.data('select2-initdata')); 1628 } 1629 1630 // Make sortable if requested 1631 if ( sel_EL.hasClass('fc_select2_sortable') ) 1632 { 1633 sel_EL.select2_sortable(); 1634 } 1635 }); 1636 1637 1638 // Customization of SELECT2 JS selectors 1639 sbox.find('div.use_select2_lib').each(function() 1640 { 1641 var el_container = jQuery(this); 1642 var sel_EL = el_container.next('select'); 1643 1644 1645 // MULTI-SELECT2: Initialize internal labels, placing the label so that it overlaps the text filter box 1646 var fc_label_text = sel_EL.attr('data-fc_label_text'); 1647 if (!fc_label_text) fc_label_text = sel_EL.attr('fc_label_text'); 1648 if (fc_label_text) 1649 { 1650 var _label = (fc_label_text.length >= 30) ? fc_label_text.substring(0, 28) + '...' : fc_label_text; 1651 1652 jQuery('<span/>', { 1653 'class': 'fc_has_inner_label fc_has_inner_label_select2', 1654 'text': _label 1655 }).prependTo(el_container.find('.select2-search-field')); 1656 } 1657 1658 1659 // MULTI-SELECT2: Initialize internal prompts, placing the prompt so that it overlaps the text filter box 1660 var fc_prompt_text = sel_EL.attr('data-fc_prompt_text'); 1661 if (!fc_prompt_text) fc_prompt_text = sel_EL.attr('fc_prompt_text'); 1662 if (fc_prompt_text) 1663 { 1664 var _prompt = (fc_prompt_text.length >= 30) ? fc_prompt_text.substring(0, 28) + '...' : fc_prompt_text; 1665 1666 jQuery('<span/>', { 1667 'class': 'fc_has_inner_prompt fc_has_inner_prompt_select2', 1668 'text': _prompt 1669 }).prependTo(el_container.find('.select2-search-field')).hide(); 1670 } 1671 1672 1673 // SINGLE-SELECT2: Highlight selects with an active value 1674 if ( ! sel_EL.attr('multiple') && sel_EL.hasClass('fc_add_highlight') ) 1675 { 1676 var el = el_container.find('.select2-choice'); 1677 var val = sel_EL.val(); 1678 if (val === null) { 1679 //el.addClass('fc_highlight_disabled'); 1680 } else if (!!val && val.length) { 1681 el.addClass('fc_highlight'); 1682 } else { 1683 el.removeClass('fc_highlight'); 1684 } 1685 } 1686 }); 1687 1688 1689 // MULTI-SELECT2: 1690 s2_elems.on('select2-open', function() 1691 { 1692 1693 // Add events to handle focusing the text filter box (hide inner label) 1694 var sel_EL = jQuery(this); 1695 var el = sel_EL.parent().find('.select2-input'); 1696 var el_label = el.prevAll('.fc_has_inner_label'); 1697 if (el_label) el_label.hide(); 1698 var el_prompt = el.prevAll('.fc_has_inner_prompt'); 1699 if (el_prompt) el_prompt.show(); 1700 1701 1702 // Allow listing already selected options WHEN having class 'select2_fc_checkboxes' 1703 if (sel_EL.hasClass('select2_fc_checkboxes')) { 1704 var els = jQuery('#select2-drop').find('.select2-selected'); 1705 els.addClass('select2-selected-visible').removeClass('select2-selected'); 1706
1707 // Suppress the onchange attribute while selector is open 1708 sel_EL.data('onchange', sel_EL.attr('onchange')); 1709 sel_EL.removeAttr('onchange'); 1710 } 1711 1712 1713 }).on('select2-close', function(e) 1714 { 1715 1716 // Add events to handle bluring the text filter box (show inner label) 1717 var sel_EL = jQuery(this); 1718 1719 // Re-open if this was closed while selecting, FOR select2 v4, use 'select2:closing' instead 1720 if ( sel_EL.data('field_being_selected') ) 1721 { 1722 sel_EL.select2('open'); 1723 jQuery('#select2-drop').find('.select2-no-results').remove(); 1724 return; 1725 } 1726 1727 var el = sel_EL.parent().find('.select2-input'); 1728 var el_label = el.prevAll('.fc_has_inner_label'); 1729 if (el_label) el_label.show(); 1730 var el_prompt = el.prevAll('.fc_has_inner_prompt'); 1731 if (el_prompt) el_prompt.hide(); 1732 1733 // Restore already selected options state 1734 if (sel_EL.hasClass('select2_fc_checkboxes')) { 1735 var els = jQuery('#select2-drop').find('.select2-selected-visible'); 1736 els.removeClass('select2-selected-visible').addClass('select2-selected'); 1737 } 1738 1739 1740 // Restore the onchange attribute when selector closes, running the JS if changes were made 1741 if ( sel_EL.data('onchange') ) 1742 { 1743 sel_EL.attr('onchange', sel_EL.data('onchange')); 1744 sel_EL.data('onchange', null); 1745 } 1746 1747 // Trigger change event on close if this was prevented 1748 if ( sel_EL.data('field_being_edited') ) 1749 { 1750 sel_EL.data('field_being_edited', null); 1751 sel_EL.trigger('change'); 1752 // LEGACY browsers ?? 1753 /*if ( sel_EL.attr('onchange') ) 1754 { 1755 eval(sel_EL.attr('onchange')); 1756 }*/ 1757 } 1758 1759 1760 }).on('select2-selecting', function(e) 1761 { 1762 1763 // Handle toggling MULTI-SELECT2 as checkboxes 1764 var sel_EL = jQuery(this); 1765 if ( sel_EL.attr('multiple') && sel_EL.hasClass('select2_fc_checkboxes') ) 1766 { 1767 var vals = sel_EL.val(); 1768 var nVals = new Array(); 1769 var i = 0; 1770 var found = 0; 1771 if (vals && vals.length) 1772 { 1773 for (var n = 0; n < vals.length; ++n) 1774 { 1775 if (vals[n] != e.val) nVals[i++] = vals[n]; 1776 else found = 1; 1777 } 1778 } 1779 1780 if (!found) nVals[i++] = e.val; 1781 sel_EL.data('set_selected_values', nVals); 1782 sel_EL.data('field_being_edited', true); 1783 sel_EL.data('field_being_selected', true); 1784 } 1785 1786 1787 }).on('change', function(e) 1788 { 1789 1790 // SELECT2: Handle change event 1791 var sel_EL = jQuery(this); 1792 1793 // 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' 1794 sel_EL.data('field_being_selected', null); 1795 if (sel_EL.data('field_being_edited')) 1796 { 1797 e.preventDefault(); 1798 e.stopPropagation(); 1799 e.stopImmediatePropagation(); 1800 } 1801 1802 var nVals = sel_EL.data('set_selected_values'); 1803 if (nVals) 1804 { 1805 jQuery('#select2-drop').find('.select2-selected-visible, .select2-selected').removeClass('select2-selected-visible').removeClass('select2-selected'); 1806 jQuery('#select2-drop').find('.select2-selected').removeClass('select2-selected-visible').removeClass('select2-selected'); 1807 1808 // Specific values were requested to be set, but first clear data value, to prevent loop in the change event 1809 sel_EL.data('set_selected_values', null).select2('val', nVals).trigger('change'); 1810 } 1811 1812 1813 // SINGLE-SELECT2: 1814 if ( ! sel_EL.attr('multiple') && sel_EL.hasClass('fc_add_highlight') ) 1815 { 1816 // Handle highlighting selected value 1817 var el = jQuery(this).prev('div').find('.select2-choice'); 1818 var val = sel_EL.val(); 1819 if (!!val && val.length) { 1820 el.addClass('fc_highlight'); 1821 } else { 1822 el.removeClass('fc_highlight'); 1823 } 1824 } 1825 1826 1827 // MULTI-SELECT2: 1828 if ( sel_EL.attr('multiple') ) 1829 { 1830 // Allow listing already selected options WHEN having class 'select2_fc_checkboxes' 1831 if (jQuery(this).hasClass('select2_fc_checkboxes')) { 1832 var els = jQuery('#select2-drop').find('.select2-selected'); 1833 els.addClass('select2-selected-visible').removeClass('select2-selected');//.removeClass('select2-result-selectable'); 1834 } 1835 } 1836 1837 }); 1838 1839 1840 // MULTI-SELECT2: Handle highlighting selected value 1841 sbox.find('div.use_select2_lib.select2-container-multi input').on('keydown', function() 1842 { 1843 var el = jQuery(this); 1844 setTimeout(function() { 1845 var val = el.val(); 1846 if (!!val && val.length) { 1847 var el_prompt = el.prevAll('.fc_has_inner_prompt'); 1848 if (el_prompt) el_prompt.hide(); 1849 } else { 1850 var el_prompt = el.prevAll('.fc_has_inner_prompt'); 1851 if (el_prompt) el_prompt.show(); 1852 } 1853 }, 0); 1854 }); 1855 1856 1857 // SELECT2: scrollbar wrap problem 1858 s2_elems.on('loaded open', function() 1859 { 1860 var ul = jQuery('#select2-drop ul.select2-results'); 1861 var needsScroll= ul.prop('scrollHeight') > ul.prop('clientHeight'); 1862 if (needsScroll) ul.css('overflow-y', 'scroll'); 1863 else ul.css('overflow-y', 'auto'); 1864 }); 1865 } 1866 1867 1868 /* Valid HTML for legacy modals using rel, TODO: add more */ 1869 jQuery(document).ready(function() { 1870 jQuery(".modal").each(function(i, el) { 1871 if (jQuery(el).get(0).hasAttribute("data-rel")) jQuery(el).attr("rel", jQuery(el).attr("data-rel")); 1872 }); 1873 }); 1874 1875 1876 /* Restore the given form fields values into the given form */ 1877 function fc_restore_form_field_values(form, data) 1878 { 1879 if (!data) 1880 { 1881 form[0].reset(); 1882 1883 var elements = Array.from(form[0].elements); 1884 for (var i = 0, l = elements.length; i < l; i++) 1885 { 1886 var el = jQuery(elements[i]); 1887 var tagName = elements[i].tagName; 1888 var inputType = tagName != 'INPUT' ? false : elements[i].type; 1889 if (tagName == 'SELECT' || (inputType && inputType!='BUTTON')) 1890 { 1891 el.trigger('change'); 1892 } 1893 } 1894 1895 return; 1896 } 1897 1898 jQuery.each(data, function(name, val) 1899 { 1900 var el = form.find('[name="'+name+'"]'), 1901 type = el.attr('type'); 1902 1903 switch(type) 1904 { 1905 case 'checkbox': el.attr('checked', 'checked'); break; 1906 case 'radio': el.filter('[value="'+val+'"]').attr('checked', 'checked'); break; 1907 default: el.val(val); 1908 } 1909 el.trigger('change'); 1910 }); 1911 } 1912 1913 1914 if (typeof jQuery.fn.serializeObject == "undefined") 1915 { 1916 jQuery.fn.serializeObject = function() 1917 { 1918 var o = {}; 1919 var a = this.serializeArray(); 1920 jQuery.each(a, function() { 1921 if (o[this.name]) { 1922 if (!o[this.name].push) { 1923 o[this.name] = [o[this.name]]; 1924 } 1925 o[this.name].push(this.value || ''); 1926 } else { 1927 o[this.name] = this.value || ''; 1928 } 1929 }); 1930 return o; 1931 } 1932 } 1933 1934 1935 if (typeof fc_isIE == "undefined") 1936 { 1937 window.fc_ie_version_number = null; 1938 fc_isIE = function() 1939 { 1940 if (window.fc_ie_version_number === null) 1941 { 1942 var userAgent = navigator.userAgent.toLowerCase(); 1943 window.fc_ie_version_number = (userAgent.indexOf('msie') != -1) ? parseInt(userAgent.
1943split('msie')[1]) : false; 1944 } 1945 return window.fc_ie_version_number; 1946 } 1947 } 1948 1949 1950 window.fc_has_flash_addon_enabled = false; 1951 fc_has_flash_addon = function() 1952 { 1953 try { 1954 window.fc_has_flash_addon_enabled = Boolean(new ActiveXObject("ShockwaveFlash.ShockwaveFlash")); 1955 } catch(exception) { 1956 window.fc_has_flash_addon_enabled = ("undefined" != typeof navigator.mimeTypes["application/x-shockwave-flash"]); 1957 } 1958 return window.fc_has_flash_addon_enabled; 1959 } 1960 1961 1962 function fc_remove_non_alphanum_chars(text, allowed_chars) 1963 { 1964 var result = ''; 1965 if (!text) return result; 1966 allowed_chars = typeof allowed == 'undefined' ? '' : allowed_chars; 1967 1968 var num_reg = new RegExp('[0-9]+$'); 1969 var allowed_reg = new RegExp('['+allowed_chars+']+$'); 1970 1971 var lower = text.toLowerCase(); 1972 var upper = text.toUpperCase(); 1973 1974 for (var i = 0; i < lower.length; ++i) 1975 { 1976 if (num_reg.test(text[i]) || (lower[i] != upper[i]) || (lower[i].trim() === '')) 1977 { 1978 result += text[i]; 1979 } 1980 else if (allowed_chars.length && allowed_reg.test(text[i])) 1981 { 1982 result += text[i]; 1983 } 1984 } 1985 return result; 1986 } 1987 1988 1989 function fc_attachSingleSlider(cfg, type) 1990 { 1991 var slider_tag_id = cfg.name + (cfg.sfx || ''); 1992 var slider = document.getElementById(slider_tag_id + '_nouislider'); 1993 //if (jQuery(slider).length) { window.console.log('not found slider ID: ' + slider_tag_id + '_nouislider'); return; } 1994 1995 var selectSL = jQuery('#' + slider_tag_id + '-sel'); 1996 var inputSL = document.getElementById(slider_tag_id + '-val'); 1997 var isSingle = 1; 1998 !!type || (type = 2); // 1: drop-down select , 2: slider (default type) 1999 2000 var IEversion = fc_isIE(); 2001 var is_IE8 = IEversion && IEversion < 9; 2002 var use_select = is_IE8 || type == 1; 2003 if (use_select) 2004 { 2005 if (selectSL.length) 2006 { 2007 var selected; 2008 jQuery.each(cfg.step_values, function(key, value) 2009 { 2010 selectSL.append( 2011 jQuery('<option></option>') 2012 .attr('value', cfg.step_values[key]) 2013 .text(cfg.step_labels[key]) 2014 ); 2015 }); 2016 2017 selectSL 2018 .val(cfg.step_values[cfg.initial_pos]) 2019 .on('change', function(e, data) { 2020 var slider_input = jQuery('#' + slider_tag_id + '-val').get(0); 2021 2022 if (cfg.element_class_list != '') 2023 { 2024 jQuery(cfg.element_selector).removeClass(cfg.element_class_list).addClass(cfg.element_class_prefix + selectSL.val()); 2025 }
2026 if (cfg.elem_container_class != '') 2027 { 2028 jQuery(cfg.elem_container_selector).removeClass(cfg.elem_container_class).addClass(cfg.elem_container_prefix + selectSL.val()); 2029 } 2030 2031 fclib_setCookie(slider_input.name, selectSL.val(), 0); // nDays 0 , aka no expiration date, keep cookie till browser closes 2032 }) 2033 .css('display', ''); // avoid show() it adds display: block 2034 } 2035 return; 2036 } 2037 slider.style.display = ''; 2038 2039 var step_values = cfg.step_values; 2040 var step_labels = cfg.step_labels; 2041 2042 noUiSlider.create(slider, { 2043 start: cfg.initial_pos, 2044 connect: false, 2045 step: 1, 2046 range: {'min': 0, 'max': (cfg.step_values.length - 1)}, 2047 }); 2048 if (!!cfg.start_hidden) jQuery(slider).hide(); 2049 2050 var tipHandles = slider.getElementsByClassName('noUi-handle'), 2051 tooltips = []; 2052 2053 // Add divs to the slider handles. 2054 for ( var i = 0; i < tipHandles.length; i++ ) 2055 { 2056 tooltips[i] = document.createElement('span'); 2057 tipHandles[i].appendChild(tooltips[i]); 2058 2059 tooltips[i].className += 'fc-sliderTooltip fc-bottom'; // Add a class for styling 2060 tooltips[i].innerHTML = '<span></span>'; // Add additional markup 2061 tooltips[i] = tooltips[i].getElementsByTagName('span')[0]; // Replace the tooltip reference with the span we just added 2062 } 2063 2064 // When the slider changes, display the value in the tooltips and set it into the input form elements 2065 slider.noUiSlider.on('update', function( values, handle ) { 2066 var value = parseInt(values[handle]); 2067 var i = value; 2068 2069 if ( handle ) { 2070 alert('This slider does not have a right handler'); 2071 } else { 2072 inputSL.value = typeof step_values[value] !== 'undefined' ? step_values[value] : value; 2073 } 2074 var tooltip_text = typeof step_labels[value] !== 'undefined' ? step_labels[value] : value; 2075 var max_len = 36; 2076 tooltips[handle].innerHTML = '<span class=\"icon-image\"></span> ' + 2077 (tooltip_text.length > max_len+4 ? tooltip_text.substring(0, max_len)+' ...' : tooltip_text); 2078 var left = jQuery(tooltips[handle]).closest('.noUi-origin').position().left; 2079 var width = jQuery(tooltips[handle]).closest('.noUi-base').width(); 2080 2081 //window.console.log ('handle: ' + handle + ', left : ' + left + ', width : ' + width); 2082 if (isSingle) { 2083 left<(50/100)*width ? 2084 jQuery(tooltips[handle]).parent().removeClass('fc-left').addClass('fc-right') : 2085 jQuery(tooltips[handle]).parent().removeClass('fc-right').addClass('fc-left'); 2086 } 2087 else { 2088 alert('This slider only has 1 handle'); 2089 } 2090 }); 2091 2092 // Handle form autosubmit 2093 slider.noUiSlider.on('change', function() { 2094 var slider = jQuery('#' + slider_tag_id + '_nouislider'); 2095 var slider_input = jQuery('#' + slider_tag_id + '-val').get(0); 2096 2097 if (cfg.element_class_list != '') 2098 { 2099 jQuery(cfg.element_selector).removeClass(cfg.element_class_list).addClass(cfg.element_class_prefix + slider_input.value); 2100 }
2101 if (cfg.elem_container_class != '') 2102 { 2103 jQuery(cfg.elem_container_selector).removeClass(cfg.elem_container_class).addClass(cfg.elem_container_prefix + slider_input.value); 2104 } 2105 2106 fclib_setCookie(slider_input.name, slider_input.value, 0); // nDays 0 , aka no expiration date, keep cookie till browser closes 2107 }); 2108 2109 inputSL.addEventListener('change', function(){ 2110 var value = 0; // default is first value = empty 2111 for(var i=1; i<step_values.length-1; i++) 2112 { 2113 if (step_values[i] == this.value) { value=i; break; } 2114 } 2115 slider.noUiSlider.set([value, null]); 2116 }); 2117 } 2118 2119 2120 2121 // Toggle elements of all other views when switching between views (e.g. details / thumbnails views) 2122 function fc_toggle_view_mode(new_btn) 2123 { 2124 var btns = new_btn.parent().children(); 2125 2126 btns.removeClass('active'); 2127 btns.each(function(index, value) 2128 { 2129 var btn = jQuery(value); 2130 jQuery(btn.data('toggle_selector')).hide(); 2131 }); 2132 2133 new_btn.addClass('active'); 2134 jQuery(new_btn.data('toggle_selector')).show().css('display', '').css('visibility', ''); 2135 } 2136 2137 2138 2139 // Create a sanitized filename similar to what server-side code will accept 2140 fc_sanitize_filename = function(text) 2141 { 2142 if (!text) return ''; 2143 2144 var validChars = new RegExp('[A-Za-z0-9\.\_\-]+'); 2145 var result = ''; 2146 2147 for (var i = 0; i < text.length; ++i) 2148 { 2149 if (validChars.test(text[i])) 2150 { 2151 result += text[i]; 2152 } 2153 } 2154 return result; 2155 } 2156 2157 2158 2159 // Submit a form in parent window from a jQuery modal 2160 fc_parent_form_submit = function(container_id, form_id, fields, options) 2161 { 2162 var form = window.parent.document.getElementById(form_id); 2163 var task = typeof options.task !== 'undefined' ? options.task : false; 2164 var is_list = typeof options.is_list !== 'undefined' ? options.is_list : false; 2165 var is_jform = typeof options.is_jform !== 'undefined' ? options.is_jform : false; 2166 2167 for (var field_name in fields) 2168 { 2169 form.elements[field_name].value = fields[field_name]; 2170 } 2171 2172 if (is_list && form.boxchecked.value==0) 2173 { 2174 alert(Joomla.JText._('FLEXI_NO_ITEMS_SELECTED')); 2175 return; 2176 } 2177 2178 // *** 2179 // *** Submit progress bar 2180 // *** 2181 2182 if (typeof form.progressbar_submit_handler_success === 'undefined' || !form.progressbar_submit_handler_success) 2183 { 2184 form.progressbar_submit_handler_success = true; 2185 // Default to doing animation 2186 form.doanimated_submit = typeof form.doanimated_submit === 'undefined' ? 1 : 0; 2187 2188 form.addEventListener('submit', function(e) 2189 { 2190 if ( !form.doanimated_submit ) 2191 { 2192 return true; 2193 } 2194 //form.doanimated_submit = 0; // Clear FLAG until next time Joomla.submitform() is called 2195 2196 var fc_filter_form_blocker = jQuery('#fc_filter_form_blocker'); 2197 2198 if (!fc_filter_form_blocker.length) 2199 { 2200 fc_filter_form_blocker = jQuery( 2201 '<div id="fc_filter_form_blocker">' + 2202 '<div class="fc_blocker_overlay"></div>' + 2203 '<div class="fc_blocker_content">' + 2204 '<div class="fc_blocker_logo></div>' + 2205 '<div class="fc_blocker_mssg>' + Joomla.JText._('FLEXI_LOADING') + '</div>' + 2206 '<div class="fc_blocker_bar"><div></div></div>' + 2207 '</div>' + 2208 '</div>' 2209 ).prependTo(jQuery('body')); 2210 } 2211 2212 if (fc_filter_form_blocker) 2213 { 2214 fc_filter_form_blocker.css("display", "block"); 2215 fc_filter_form_blocker.find('.fc_blocker_mssg').html(Joomla.JText._('FLEXI_LOADING')); 2216 fc_admin_progress(95, jQuery('#fc_filter_form_blocker .fc_blocker_bar')); 2217 } 2218 }); 2219 } 2220 2221 // Close modal to allow click events to work on the parent window 's form 2222 jQuery('#'+container_id).dialog('close'); 2223 2224 // If it is a Joomla form 2225 if (is_jform) 2226 { 2227 window.parent.Joomla.submitbutton(task); 2228 return; 2229 } 2230 2231 // For proper submit, append a hidden submit button to the form and click it, then remove it if submit was prevented 2232 var button = document.createElement('input'); 2233 button.style.display = 'none'; 2234 button.type = 'submit'; 2235 form.appendChild(button).click(); 2236 form.removeChild(button); 2237 } 2238 2239 2240 2241 //******************************* 2242 //*** START OF fc_init*() methods 2243 //******************************* 2244 2245 2246 /* 2247 * Initialize CSS styles and effects 2248 */ 2249 function fc_initDynamicLayoutJsCss(container_id, reAddOnEvents, html) 2250 { 2251 const container_sel = '#' + container_id; 2252 jQuery(container_sel).html(html); 2253 2254 tabberAutomatic(tabberOptions, container_id); 2255 fc_bindFormDependencies(container_sel, 0, ''); 2256 2257 fc_initBootstrap(null, container_sel, reAddOnEvents); 2258 fc_initTooltips(null, container_sel, reAddOnEvents); 2259 fc_initCodeMirror(null, container_sel, reAddOnEvents); 2260 fc_initMinicolors(null, container_sel, reAddOnEvents); 2261 fc_initSubform(null, container_sel); 2262 2263 if (typeof(fcrecord_attach_sortable) == 'function') fcrecord_attach_sortable(container_sel); 2264 if (typeof(fcfield_attach_sortable) == 'function') fcfield_attach_sortable(container_sel); 2265 2266 fc_initSelect2(null, container_sel, reAddOnEvents); 2267 } 2268 2269 2270 /* 2271 * Initialize bootstrap styles and effects 2272 */ 2273 function fc_initBootstrap(event, container_sel, reAddOnEvents) 2274 { 2275 const container_el = jQuery(container_sel); 2276 2277 // Also run method on given "Add" events, e.g. 'subform-row-add'
2278 (reAddOnEvents || []).forEach(element => container_el.on(element, fc_initBootstrap)); 2279 2280 // Add bootstap styless and effects 2281 fc_bootstrapAttach(container_el); 2282 } 2283 2284 2285 /* 2286 * Initialize tooltips and popovers 2287 */ 2288 function fc_initTooltips(event, container_sel, reAddOnEvents) 2289 { 2290 const container_el = jQuery(container_sel); 2291 const elements_set_tooltip = container_el.find('.hasTooltip'); 2292 const elements_set_popover = container_el.find('.hasPopover'); 2293 2294 if (typeof jQuery === undefined || typeof jQuery.tooltip === undefined) 2295 { 2296 elements_set_tooltip.length && !!Joomla.fc_debug ? window.console.log('tooltip() not loaded. Skipping it') : false; 2297 } 2298 if (typeof jQuery === undefined || typeof jQuery.popover === undefined) 2299 { 2300 elements_set_popover.length && !!Joomla.fc_debug ? window.console.log('popover() not loaded. Skipping it') : false; 2301 } 2302 if (typeof jQuery === undefined || (typeof jQuery.tooltip === undefined && typeof jQuery.popover === undefined)) 2303 { 2304 return; 2305 } 2306 2307 // Also run method on given "Add" events, e.g. 'subform-row-add' 2308 (reAddOnEvents || []).forEach(element => container_el.on(element, fc_initTooltips)); 2309 2310 // Add tooltips and popovers 2311 typeof jQuery.tooltip !== undefined ? elements_set_tooltip.tooltip({html: true, container: container_el}) : false; 2312 typeof jQuery.popover !== undefined ? elements_set_popover.popover({html: true, container: container_el, trigger : 'hover focus'}) : false; 2313 } 2314 2315 2316 /* 2317 * Initialize select2 behaviour 2318 */ 2319 function fc_initSelect2(event, container_sel, reAddOnEvents) 2320 { 2321 const container_el = jQuery(container_sel); 2322 const elements_set = container_el.find('select.use_select2_lib'); 2323 2324 if (typeof jQuery === undefined || typeof jQuery.select2 === undefined) 2325 { 2326 elements_set.length && !!Joomla.fc_debug ? window.console.log('subformRepeatable() not loaded. Skipping it') : false; 2327 return; 2328 } 2329 2330 // Also run method on given "Add" events, e.g. 'subform-row-add' 2331 (reAddOnEvents || []).forEach(element => container_el.on(element, fc_initSelect2)); 2332 2333 // Attach select2 2334 fc_attachSelect2(container_el, elements_set); 2335 } 2336 2337 2338 function fc_initCodeMirror(event, container_sel, reAddOnEvents) 2339 { 2340 const container_el = jQuery(container_sel); 2341 const elements_set = container_el.find('textarea.codemirror-source'); 2342 2343 if (typeof Joomla.editors === undefined || typeof CodeMirror === undefined) 2344 { 2345 elements_set.length && !!Joomla.fc_debug ? window.console.log('CodeMirror not loaded. Skipping it') : false; 2346 return; 2347 } 2348 2349 // Also run method on given "Add" events, e.g. 'subform-row-add' 2350 (reAddOnEvents || []).forEach(element => container_el.on(element, fc_initCodeMirror)); 2351 2352 elements_set.each(function () { 2353 var input = jQuery(this).removeClass('codemirror-source'); 2354 var id = input.prop('id'); 2355 2356 Joomla.editors.instances[id] = CodeMirror.fromTextArea(this, input.data('options')); 2357 }); 2358 } 2359 2360 2361 2362 /* 2363 * Initialize subform fields 2364 */ 2365 function fc_initSubform (event, container_sel) 2366 { 2367 const container_el = jQuery(container_sel); 2368 const elements_set = container_el.find('div.subform-repeatable'); 2369 2370 if (typeof jQuery === undefined || typeof jQuery.subformRepeatable) 2371 { 2372 elements_set.length && !!Joomla.fc_debug ? window.console.log('subformRepeatable() not loaded. Skipping it') : false; 2373 return; 2374 } 2375 elements_set.subformRepeatable(); 2376 } 2377 2378 2379 /* 2380 * Initialize any minicolor fields 2381 */ 2382 function fc_initMinicolors(event, container_sel, reAddOnEvents) 2383 { 2384 const container_el = jQuery(container_sel); 2385 const elements_set = container_el.find('.minicolors'); 2386 2387 if (typeof jQuery === undefined || typeof jQuery.minicolors === undefined) 2388 { 2389 elements_set.length && !!Joomla.fc_debug ? window.console.log('minicolors() not loaded. Skipping it') : false; 2390 return; 2391 } 2392 2393 // Also run method on given "Add" events, e.g. 'subform-row-add' 2394 (reAddOnEvents || []).forEach(element => container_el.on(element, fc_initMinicolors)); 2395 2396 elements_set.each(function() { 2397 var $this = jQuery(this); 2398 var format = $this.data('validate') === 'color' ? 'hex' : $this.data('format') || 'hex'; 2399 2400 $this.minicolors({ 2401 control: $this.data('control') || 'hue', 2402 format: format === 'rgba' ? 'rgb' : format, 2403 keywords: $this.data('keywords') || '', 2404 opacity: format === 'rgba', 2405 position: $this.data('position') || 'default', 2406 theme: $this.data('theme') || 'bootstrap', 2407 }); 2408 }); 2409 } 2410 2411 2412 //***************************** 2413 //*** END OF fc_init*() methods 2414 //***************************** 2415 2416 2417 2418 /* 2419 * Allow custom input in date fields having the custom text class 2420 */ 2421 document.addEventListener('DOMContentLoaded', function() 2422 { 2423 if (typeof JoomlaCalendar != 'undefined') 2424 { 2425 var JoomlaCalendar_setAltValue_fc = JoomlaCalendar.prototype.setAltValue; 2426 JoomlaCalendar.prototype.setAltValue = function() 2427 { 2428 if (this.inputField.classList.contains('fc_date_allow_text')) 2429 { 2430 return; 2431 } 2432 return JoomlaCalendar_setAltValue_fc.call(this, arguments); 2433 }; 2434 2435 var JoomlaCalendar_init_fc = JoomlaCalendar.init; 2436 JoomlaCalendar.init = function() 2437 { 2438 var result = JoomlaCalendar_init_fc.apply(null, arguments); 2439 2440 var element = arguments[0]; 2441 var input = element ? element.getElementsByTagName('input')[0] : false;
2442 2443 if (input) 2444 { 2445 if (!!input.id && input.classList.contains('fc_date_allow_text')) 2446 { 2447 input.value = document.getElementById(input.id + '_fc_value').getAttribute('data-fc-value'); 2448 } 2449 } 2450 2451 return result; 2452 } 2453 } 2454 });
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.