

jQuery(document).ready(function($) {
	"use strict";

	/*** Internal Links ***/
	$('a[data-cust-linksection]').on('click', function (e) {
		var targetSectionId = $(this).data('cust-linksection');
		if (wp && wp.customize && wp.customize.section(targetSectionId)) {
			e.preventDefault();
			wp.customize.section(targetSectionId).expand();
		}
	} );


	/*** Helpers - boxdivi ***/
	$('.hoot-nonextdivstd').closest('.customize-control').next('.customize-control').addClass('hoot-nodivstd');


	/*** Helpers - BeTooltip ***/

	setTimeout( () => {
		$('.hoot-betooltip-box').each(function(){
			var $tbox = $(this),
				varsSet = false;
			$tbox.on('mouseenter', function(){
				if ( ! varsSet ) {
					varsSet = true;
					var controlWidth = $tbox.closest( 'li.customize-control' ).outerWidth(),
						boxLeft = $tbox.position().left;
					$tbox.css( { '--betippos': boxLeft + 'px', '--betipmax': controlWidth + 'px' } );
				}
			});
		});
		$('.hoot-bedesctip').each(function(){
			var $desctip = $(this),
				$dscrptn = $desctip.closest( '.hoot-betterlabels' ).find('.customize-control-description');
			var varsSet = false;
			if ( ! $dscrptn.length ) {
				$desctip.hide();
			} else {
				$dscrptn.hide();
				$desctip.on('click', function(){
					if ( ! varsSet ) {
						varsSet = true;
						var boxLeft = $desctip.position().left,
							controlWidth = $desctip.closest( 'li.customize-control' ).outerWidth();
						$dscrptn.addClass('hoot-bedescription').css( { '--betippos': boxLeft + 'px', '--betipmax': controlWidth + 'px' } );
					}
					$dscrptn.slideToggle('fast');
					$(this).toggleClass('hootactive');
				});
			}
		});
	}, 3000 );


	/*** Sortlist Control ***/

	$('ul.hoot-control-sortlist').each(function(){

		/** Prepare Sortlist **/

		var $self = $(this),
			openstate = $self.data('openstate'),
			accordian = $self.data('accordian'),
			$listItems = $self.children('li'),
			$listItemHeads = $listItems.children('.hoot-sortlistitem-head'),
			$listItemVisibility = $listItemHeads.children('.sortlistitem-display'),
			$listItemFlypanel = $listItemHeads.children('.sortlistitem-flypanel'),
			$listItemExpand = $listItemHeads.children('.sortlistitem-expand'),
			$listItemOptions = $listItems.children('.hoot-sortlistitem-options');

		$listItemHeads.on('click', function(e){
			if ( $listItemExpand.length ) {
				if ( accordian == 'one' ) {
					$self.find('.sortlistitem-expand').removeClass('options-open');
					$self.find('.hoot-sortlistitem-options').slideUp('fast');
				}
				$(this).children('.sortlistitem-expand').toggleClass('options-open');
				$(this).siblings('.hoot-sortlistitem-options').slideToggle('fast');
			} else if ( $listItemFlypanel.length ) {
				$listItems.removeClass('hootactive');
				e.stopPropagation();
				var parentItem = $(this).closest('li.hoot-control-sortlistitem');
				var fpbutton = $('.hoot-control-id-frontpage_sectionbg_' + parentItem.data('choiceid') + ' .hoot-flypanel-button');
				if ( fpbutton.length ) {
					fpbutton.trigger('click');
					parentItem.addClass('hootactive');
				}
			}
		});
		$listItemFlypanel.on('click', function(e){
				$listItems.removeClass('hootactive');
				e.stopPropagation();
				var parentItem = $(this).closest('li.hoot-control-sortlistitem');
				var fpbutton = $('.hoot-control-id-frontpage_sectionbg_' + parentItem.data('choiceid') + ' .hoot-flypanel-button');
				if ( fpbutton.length ) {
					fpbutton.trigger('click');
					parentItem.addClass('hootactive');
				}
		});

		if ( openstate ) {
			if ( openstate != 'all' ) {
				$listItemOptions.hide();
				$listItems.filter('[data-choiceid="' + openstate + '"]').children('.hoot-sortlistitem-head').click();
			}
		} else $listItemOptions.hide();

		$listItemVisibility.on('click', function(e){
			e.stopPropagation();
			var $liContainer = $(this).closest('li.hoot-control-sortlistitem');
			$liContainer.toggleClass('deactivated');
			var hideValue = ( $liContainer.is('.deactivated') ) ? '1' : '0';
			$(this).siblings('input.hoot-control-sortlistitem-hide').val(hideValue).trigger('change');
		});

		/** Sortlist Control **/

		function hootArrayToNestedObject(serializedArray) {
			var nestedObject = {};
			serializedArray.forEach(({ name, value }) => {
				var keys = name.split(/\[|\]\[|\]/).filter(Boolean);
				var currentLevel = nestedObject; // reference assignment
				keys.forEach((key, index) => {
					if (index === keys.length - 1) {
						currentLevel[key] = value;
					} else {
						currentLevel[key] = currentLevel[key] || {};
						currentLevel = currentLevel[key]; // reference assignment
					}
				});
			});
			return nestedObject;
		}
		var $optionsform = $self.find('input:not([data-displayonly]), textarea, select'),
			$input = $self.siblings('input.hoot-customize-control-sortlist'),
			hootUpdateSortable = function(){
				$optionsform = $self.find('input:not([data-displayonly]), textarea, select'); // Get updated list item order
				// Moved to singular approach of using [JSON.stringify( $optionsform.serializeArray() ) + PHP json_decode()]
				var nestedObject  = {};
				// serializeArray does not create a multidimensional array. It simpy creates array with name/value pairs
				var serializedArray = $optionsform.serializeArray();
				// create mutlidimensional array from serializeArray
				var nestedObject = hootArrayToNestedObject(serializedArray);
				// store as json encoded string
				$input.val( JSON.stringify(nestedObject) ).trigger('change');
			};

		$optionsform.on('change', hootUpdateSortable);

		if ( $self.is('.sortable') ) {
			$self.sortable({
				handle: ".sortlistitem-sort",
				placeholder: "hoot-control-sortlistitem-placeholder",
				update: function(event, ui) {
					hootUpdateSortable();
				},
				forcePlaceholderSize: true,
			});
		}

	});


	/*** Radioimage Control ***/

	$('.customize-control-radioimage, .hoot-sortlistitem-option-radioimage').each(function(){

		var $radios = $(this).find('input'),
			$labels = $(this).find('.hoot-customize-radioimage');

		$radios.on('change',function(){
			$labels.removeClass('radiocheck');
			$(this).parent('.hoot-customize-radioimage').addClass('radiocheck');
		});

	});


	/*** Bettertoggle Control ***/

	$('.hoot-toggle-ctrlbox .bettertoggle, .hoot-toggle-ctrlbox .bettertoggle-invert').click( function(e){
		$(this).siblings('input[type=checkbox]').click();
	});


	/*** Bettercolor Control ***/
	$('.bettercolor-clone').each(function(){
		var $cpicker = $(this).find('.hoot-color-picker');
		if ( $cpicker.length ) {
			var cloneof = $cpicker.data('cloneof'),
				clonedby = $cpicker.data('hoot-setting-link');
			$('.hoot-color-picker[data-hoot-setting-link="'+cloneof+'"]').data('clonedby', clonedby);
		}
	});
	var colorCloneSyncing = false;
	$('.hoot-color-picker').each(function () {
		var $input = $(this),
			settingId = $input.data('hoot-setting-link'),
			skipUpdateCustomize = $input.data('skip-update-customize'),
			defaultColor = $input.data('default-color'),
			palettes = typeof hoot_customize_data != 'undefined' && typeof hoot_customize_data.color_palettes === 'object' ? hoot_customize_data.color_palettes : [];
		var clonedbyId = $input.data('clonedby'),
			cloneofId = $input.data('cloneof'),
			$clonedby = clonedbyId ? $('#customize-control-'+clonedbyId).find('.hoot-color-picker') : null,
			$cloneof = cloneofId ? $('.hoot-color-picker[data-hoot-setting-link="'+cloneofId+'"]') : null;

		$input.wpColorPicker({
			defaultColor: defaultColor,
			change: function (event, ui) {
				var format = ui.color._alpha === 1 ? 'hex' : 'octohex';
				var color = ui.color.to_s(format);
				if ( $cloneof && $cloneof.length ) {
					// <1> This is a clone.
					if ( ! colorCloneSyncing ) {
						colorCloneSyncing = true; // trigger change letting it know its a sync
						$cloneof.val( color ).trigger( 'change' );
					} else {
						colorCloneSyncing = false; // sync done. reset
					}
				} else {
					// <2> This is an original control.
					// Tell the Customizer directly - skip it for betterfont which uses its own js to update values
					if ( ! skipUpdateCustomize ) wp.customize(settingId, function (setting) { setting.set(color); });
					// <3> It is also cloned by someone
					if ( $clonedby && $clonedby.length ) {
						if ( ! colorCloneSyncing ) {
							colorCloneSyncing = true; // trigger change letting it know its a sync
							$clonedby.val( color ).trigger( 'change' );
						} else {
							colorCloneSyncing = false; // sync done. reset
						}
					}
				}
				$(this).trigger('hootevchange.color', color);
			},
			clear: function () {
				if ( $cloneof && $cloneof.length ) {
					colorCloneSyncing = true; // trigger change letting it know its a sync
					$cloneof.val( color ).trigger( 'change' );
				} else {
					// Tell the Customizer directly - skip it for betterfont which uses its own js to update values
					if ( ! skipUpdateCustomize ) wp.customize(settingId, function (setting) { setting.set(''); });
					if ( $clonedby && $clonedby.length ) {
						colorCloneSyncing = true; // trigger change letting it know its a sync
						$clonedby.val( color ).trigger( 'change' );
					}
				}
				$(this).trigger('hootevchange.color', '');
			},
			palettes: palettes.length ? palettes : true,
			width: 255, // using 255 as basis in customize.scss
		});
	});
	setTimeout( () => {
		$('.hoot-cpicker-circle').each(function () {
			var $cbox = $(this),
				$toggler = $cbox.find('.wp-color-result'),
				displayinline = $cbox.is('.bettercolor-inline');
			if ( ! $toggler.length ) return;
			$toggler.on('click', function () {
				if ( !displayinline && $(this).hasClass('wp-picker-open') ) {
					var $ul = $cbox.closest('.wp-full-overlay-sidebar-content');
					if ( $cbox.length && $ul.length ) {
						var cboxOffset = $cbox.offset(),
							ulOffset = $ul.offset(),
							ulHeight   = $ul.outerHeight(),
							cpickerHeight = 260;
						var ulBottom = ulOffset.top + ulHeight;
						if ( ( cboxOffset.top + cpickerHeight + 32 ) < ulBottom ) {
							$cbox.removeClass('hoot-cpicker-circle-top hoot-cpicker-circle-inline');
						} else {
							if ( cboxOffset.top - ulOffset.top > cpickerHeight )
								$cbox.addClass('hoot-cpicker-circle-top').removeClass('hoot-cpicker-circle-inline');
							else
								$cbox.addClass('hoot-cpicker-circle-inline').removeClass('hoot-cpicker-circle-top');
						}
					}
				} else {
				}
			});
		});
	}, 1000 );


	/*** Betterfont Control ***/
	$('.customize-control-betterfont').each(function () {
		var $control = $(this),
			ctrlID = $control.attr('id'),
			$btn = $control.find('.hoot-betterfont-btn'),
			$popup = $control.find('.hoot-betterfont-popup'),
			$input = $control.find('input.betterfont-input');
		var $resetall = $popup.find('.hoot-betterfont-resetall'),
			$colors = $popup.find('.hoot-color-picker').filter(function () {
				var cloneofId = $(this).data('cloneof'),
					$cloneof = cloneofId ? $('.hoot-color-picker[data-hoot-setting-link="' + cloneofId + '"]') : null;
				return !($cloneof && $cloneof.length);
			}),
			$faces = $popup.find('.betterfont-face-input'),
			$category = $popup.find('.betterfont-category-input'),
			$subsets = $popup.find('.betterfont-subsets-input'),
			$weights = $popup.find('.betterfont-weight-input'),
			$ranges = $popup.find('.betterfont-range-input'),
			$selects = $popup.find('.betterfont-select-input');

		// Button - Popup - Autoclose
		var hootOpenPopup = function() {
				$btn.addClass('hootactive');
				$popup.show();
				$popup.find('select.betterfont-face-input').each(function () {
					if ( $(this).data('select-initialized') ) return;
					$(this).select2({dropdownParent:$('#customize-controls')}).data('select-initialized', true);
				});
				$popup.find('select.betterfont-subsets-input').each(function () {
					if ( $(this).data('select-initialized') ) return;
					$(this).select2({dropdownParent:$('#customize-controls')}).data('select-initialized', true);
				});
				$( 'body' ).on( 'mousedown', hootAutoclose );
			},
			hootClosePopup = function() {
				$btn.removeClass('hootactive').addClass('hootlosefocus');
				setTimeout(function() { $btn.removeClass('hootlosefocus'); }, 1500);
				$popup.hide();
				$( 'body' ).off( 'mousedown', hootAutoclose );
			},
			hootAutoclose = function( e ) {
				if (
					! $( e.target ).closest( '#'+ctrlID ).length &&
					! $( e.target ).closest( '.select2-container' ).length
				) {
					hootClosePopup();
				}
			};
		$btn.click( function(){
			var isactive = $btn.is('.hootactive');
			if ( isactive ) {
				hootClosePopup();
			} else {
				// close any other open betterfont controls and remove their body click function before opening this one
				$( ".hoot-betterfont-btn.hootactive" ).trigger('click');
				hootOpenPopup();
			}
		});

		function hootUpdateInput( color=false ) {
			var val = {} ;
			$faces.each(function () {
				var ctrlid = $(this).data('ctrlid'),
					ctrlval = $(this).val();
				val[ctrlid] = ctrlval;
			});
			$category.each(function () {
				var ctrlid = $(this).data('ctrlid'),
					ctrlval = $(this).val();
				val[ctrlid] = ctrlval;
			});
			$colors.each(function () {
				var ctrlid = $(this).data('ctrlid'),
					ctrlval = color ? color : $(this).val();
				val[ctrlid] = ctrlval;
			});
			$ranges.each(function () {
				var ctrlid = $(this).data('ctrlid'),
					ctrlval = $(this).val();
				val[ctrlid] = JSON.parse(ctrlval);
			});
			$selects.each(function () {
				var ctrlid = $(this).data('ctrlid'),
					ctrlval = $(this).val();
				val[ctrlid] = ctrlval;
			});
			$weights.each(function () {
				var ctrlid = $(this).data('ctrlid'),
					ctrlval = $(this).val();
				val[ctrlid] = ctrlval;
			});
			$subsets.each(function () {
				var ctrlid = $(this).data('ctrlid'),
					ctrlval = $(this).val();
				val[ctrlid] = ctrlval;
			});
			val = JSON.stringify(val);
			$input.val(val).trigger('change');
		}

		// resetall
		// maybe todo - Reset ALL even if it does not exist in resetVal (set it to empty perhaps?) - For now we rely on defaults for all to exist in PHP customizer options
		$resetall.on('click', function () {
			var resetVal = $(this).data('resetval');
			for ( var key in resetVal ) { if ( resetVal.hasOwnProperty(key) ) {
				var ctrlVal = resetVal[key];
				if ( key === 'subsets' ) { // multiple select expects an array
					if (Array.isArray(resetVal[key])) {
						ctrlVal = resetVal[key]; // this is the case normally if everything is fine
					} else if (typeof resetVal[key] === 'string') {
						try { ctrlVal = JSON.parse(resetVal[key]); }
						catch { ctrlVal = resetVal[key] ? resetVal[key].split(',') : []; }
					} else {
						ctrlVal = [];
					}
				} else { // else convert to string
					ctrlVal = typeof resetVal[key] === 'object' ? JSON.stringify(resetVal[key]) : resetVal[key] ;
				}

				if ( key === 'face' ) {
					$control.find( 'select[data-ctrlid="' + key + '"]' ).html( '<option value="' + ctrlVal + '" selected="selected">' + ctrlVal + '</option>' ).val( ctrlVal ).trigger('hootevchange.face', ctrlVal).trigger('change.select2');
				} else if ( key === 'subsets' ) {
					$control.find( 'select[data-ctrlid="' + key + '"]' ).val( ctrlVal ).trigger('change.select2');
				} else if ( key === 'size' || key === 'lheight' || key === 'lspace' ) {
					$control.find( 'input[data-ctrlid="' + key + '"]' ).val( ctrlVal ).trigger('hootevchange.range');
				} else if ( key === 'weight' ) {
					$control.find( 'select[data-ctrlid="' + key + '"]' ).val( ctrlVal );
				} else if ( key === 'style' || key === 'trans' || key === 'deco' ) {
					$control.find( 'select[data-ctrlid="' + key + '"]' ).val( ctrlVal );
				} else if ( key === 'color' ) {
					$control.find( 'input[data-ctrlid="' + key + '"]' ).val( ctrlVal ).trigger('change');
				}
			} }
			hootUpdateInput();
		});

		// 1. 'style', 'trans', 'deco' selects
		$ranges.on('input change', function () {
			hootUpdateInput();
		});

		// 2. 'size', 'lheight', 'lspace' ranges
		$selects.on('change', function () {
			hootUpdateInput();
		});

		// 3. color
		$colors.on( 'hootevchange.color', function ( event, color ) {
			hootUpdateInput( color );
		});

		// 4. subsets
		$subsets.on('change', function () {
			hootUpdateInput();
		});

		// 5. weight
		$weights.on('change', function () {
			hootUpdateInput();
		});

		// 6. faces
		$faces.on('change', function () {
			$(this).trigger('hootevchange.face');
			hootUpdateInput();
		});
		$faces.closest('.hoot-ctrlbox').find('.better-reset').on('click', function () {
			// same as in resetall
			var resetval = $(this).data('resetval');
			$faces.html( '<option value="' + resetval + '" selected="selected">' + resetval + '</option>' ).val( resetval ).trigger('change');
		});
		var haveHootFonts = typeof hoot_customize_data != 'undefined' && typeof hoot_customize_data.fonts === 'object',
			gfontsPreview  = !! ( typeof hoot_customize_data != 'undefined' && hoot_customize_data.gfontspreview ),
			gfontsNote  = typeof hoot_customize_data != 'undefined' && typeof hoot_customize_data.gfontsnote === 'string' ? hoot_customize_data.gfontsnote : '';
		$faces.each(function () {
			var $input = $(this);
			if ( haveHootFonts ) {
				// fix search if gfonts preview is on
				if ( gfontsPreview ) {
					$input.on( 'select2:open', function() {
						var $dropdown = $('.select2-container--open .select2-dropdown'),
							$searchInput = $dropdown.find('.select2-search__field');
						$dropdown.removeClass('hoot-select2-issearch');
						$searchInput.on('input', function () {
							var term = $(this).val().trim();
							if (term === '') {
								$dropdown.removeClass('hoot-select2-issearch');
							} else {
								$dropdown.addClass('hoot-select2-issearch');
							}
						});
						if ( gfontsNote && $dropdown.find('.hoot-select2-footernote').length === 0 ) {
							$dropdown.append( '<div class="hoot-select2-footernote">'+gfontsNote+'</div>' );
						}
					});
				}
				// Populate options when dropdown opens
				$input.on( 'select2:opening', function() {
					var selected = $input.val(),
						selectOptions = '';
					$.each( hoot_customize_data.fonts, function( id, data ) {
						if ( typeof data === 'string' ) {
							selectOptions += '<option value="' + id + '"' + ( id === selected ? ' selected="selected"' : '' ) + '>' + data + '</option>';
						} else if ( typeof data === 'object' ) {
							var grouplabel = data.label ? data.label : id ;
							selectOptions += '<optgroup label="' + grouplabel + '">';
							if ( typeof data.fonts === 'object' ) {
								$.each( data.fonts, function( fid, fdata ) {
									selectOptions += '<option value="' + fid + '"' + ( fid === selected ? ' selected="selected"' : '' ) + ( fdata === 'disabled' ? ' disabled="disabled"' : '' ) + '>' + fid + '</option>';
								});
							}
							selectOptions += '</optgroup>';
						}
					});
					$input.html( selectOptions );
				});
				// Remove options when dropdown closes
				$input.on( 'select2:close', function(e) {
					var selected = $input.val(),
						label = selected;
					$.each( hoot_customize_data.fonts, function( id, data ) {
						if ( id === selected )
							label = typeof data === 'string' ? data : label; // only needed for 'inherit'
					});
					$input.html( '<option value="' + selected + '" selected="selected">' + label + '</option>' );
				});
			}
			// Update weights and subsets+category when face changes
			var fontweights = typeof hoot_customize_data != 'undefined' && typeof hoot_customize_data.fontweights === 'object' ? hoot_customize_data.fontweights : {};
			fontweights.all      = typeof fontweights.all      === 'object' ? fontweights.all      : {};
			fontweights.defaults = typeof fontweights.defaults === 'object' ? fontweights.defaults : {};
			fontweights.inherit  = typeof fontweights.inherit  === 'object' ? fontweights.inherit  : {};
			$input.on( 'hootevchange.face', function( event, face ) {
				var newFace = $(this).val();
				// 1.2. Update subsets+category
				if ( $subsets.length || $category.length ) {
					var selectOptions = '',
						selectVal = [],
						newCategory = '';
					if ( haveHootFonts ) {
						$.each( hoot_customize_data.fonts, function( id, fontsSet ) {
							if (
								typeof fontsSet === 'object' && typeof fontsSet.fonts === 'object'
								&& typeof fontsSet.fonts[newFace] === 'object'
							) {
								newCategory = fontsSet.fonts[newFace].c ? fontsSet.fonts[newFace].c : '';
								if ( Array.isArray( fontsSet.fonts[newFace].ss ) ) {
									selectVal = fontsSet.fonts[newFace].ss.indexOf('latin') !== -1 ? ['latin'] : [];
									$.each( fontsSet.fonts[newFace].ss, function( ssid, ssdata ) {
										selectOptions += '<option value="' + ssdata + '"' + ( ssdata === 'latin' ? ' selected="selected"' : '' ) + '>' + ssdata + '</option>';
									});
								}
							}
						});
					}
					if ( $category.length ) {
						$category.val( newCategory );
					}
					if ( $subsets.length ) {
						$subsets.html( selectOptions );
						if ( selectOptions )
							$subsets.closest('.hoot-ctrlbox.betterfont-subsets-ctrlbox').removeClass('hoot-disabled');
						else
							$subsets.closest('.hoot-ctrlbox.betterfont-subsets-ctrlbox').addClass('hoot-disabled');
						$subsets.val( selectVal ).trigger('change.select2');
					}
				}
				// 3. Update weights
				if ( $weights.length ) {
					var selectOptions = '',
						foundWeights = false,
						currentValue = $weights.val(),
						foundCurrent = false;
					if ( haveHootFonts ) {
						$.each( hoot_customize_data.fonts, function( id, fontsSet ) {
							if (
								typeof fontsSet === 'object' && typeof fontsSet.fonts === 'object'
								&& typeof fontsSet.fonts[newFace] === 'object'
								&& Array.isArray( fontsSet.fonts[newFace].v )
							) {
								foundWeights = true;
								$.each( fontsSet.fonts[newFace].v, function( vid, vdata ) {
									if ( vdata == currentValue ) foundCurrent = true; // vdata:string | currentValue:number
									selectOptions += '<option value="' + vdata + '"' + ( vdata == currentValue ? ' selected="selected"' : '' ) + '>' + ( typeof fontweights.all[vdata] === 'string' ? fontweights.all[vdata] : vdata ) + '</option>';
								});
							}
						});
					}
					if ( ! foundWeights ) {
						$.each( fontweights.defaults, function( vid, vdata ) {
							if ( vid == currentValue ) foundCurrent = true; // vid:string | currentValue:number
							selectOptions += '<option value="' + vid + '"' + ( vid == currentValue ? ' selected="selected"' : '' ) + '>' + vdata + '</option>';
						});
					}
					var inheritOptions = '';
					$.each( fontweights.inherit, function( vid, vdata ) {
						inheritOptions += '<option value="' + vid + '"' + ( !foundCurrent ? ' selected="selected"' : '' ) + '>' + vdata + '</option>';
					});
					$weights.html( inheritOptions + selectOptions );
				}
			});
		});

	});


	/*** Betterfontgroup Control ***/

	$('.customize-control-betterfontgroup').each(function () {
		var $control = $(this),
			ctrlID = $control.attr('id'),
			$toggle = $control.find('.bettertogglebox input[type="checkbox"]'),
			$popup = $control.find('.hoot-betterfontgroup-popup'),
			$input = $control.find('input.betterfontgroup-input'),
			$ranges = $popup.find('.betterfontgroup-range-input');

		if ( $toggle.length ) {
			if ( ! $toggle.is(':checked') ) {
				$popup.hide();
			}
			$toggle.on('change', function () {
				if ( $toggle.is(':checked') ) {
					$popup.slideDown('fast');
				} else {
					$popup.slideUp('fast');
				}
				hootUpdateInput();
			});
		}

		$ranges.on('input change', function () {
			hootUpdateInput();
		});

		function hootUpdateInput( color=false ) {
			var val = {} ;
			if ( $toggle.length ) {
				val[ $toggle.attr('name') ] = $toggle.is(':checked') ? true : false;
			}
			$ranges.each(function () {
				var opid = $(this).data('opid'),
					ctrlid = $(this).data('ctrlid'),
					ctrlval = $(this).val();
				if ( ! val[opid] ) val[opid] = {};
				val[opid][ctrlid] = JSON.parse(ctrlval);
			});
			val = JSON.stringify(val);
			$input.val(val).trigger('change');
		}
	});


	/*** Media Queries ***/

	var $footer_devices = $( '#customize-footer-actions .devices button' ),
		$overlaybody = $( '.wp-full-overlay' ),
		$hootmediaswitches = $( '.hoot-mediaswitcher i:not(.hoot-mediaquery-alldevices-btn)' ),
		$alldevicesCheckbox = $( '.hoot-mediaquery-alldevices-checkbox' ),
		$mediaboxes = $( '.hoot-mediabox' );

	$footer_devices.on( 'click', function( event ) {
		event.preventDefault();

		var device = $(this).data('device');
		// 1. Customizer Preview
		$overlaybody.removeClass( 'preview-desktop preview-tablet preview-mobile' ).addClass( 'preview-' + device );
		$footer_devices.removeClass( 'active' ).attr( 'aria-pressed', false );
		$footer_devices.filter( '.preview-' + device ).addClass( 'active' ).attr( 'aria-pressed', true );
		// 2. Media Switches
		$hootmediaswitches.filter(function () {
			return $(this).data('alldevices') !== 'on';
		}).removeClass('hootactive').filter('[data-device="' + device + '"]').addClass('hootactive');
		// 3. Controls
		$mediaboxes.filter(function () {
			return $(this).data('alldevices') !== 'on';
		}).hide().filter('[data-device="' + device + '"]').show();
	});

	$hootmediaswitches.on( 'click', function( event ) {
		if ( $(this).is('.hootactive') ) return;

		var device = $(this).data('device');
		// 1. Customizer Preview
		$overlaybody.removeClass( 'preview-desktop preview-tablet preview-mobile' ).addClass( 'preview-' + device );
		$footer_devices.removeClass( 'active' ).attr( 'aria-pressed', false );
		$footer_devices.filter( '.preview-' + device ).addClass( 'active' ).attr( 'aria-pressed', true );
		// 2. Media Switches
		$hootmediaswitches.removeClass('hootactive');
		$hootmediaswitches.filter('[data-device="' + device + '"]').addClass('hootactive');
		// 3. Controls
		$mediaboxes.slideUp('fast');
		$mediaboxes.filter('[data-device="' + device + '"]').slideDown('fast');
	});

	$alldevicesCheckbox.each(function(){
		var $checkbox = $(this),
			$btn = $checkbox.siblings('.hoot-mediaquery-alldevices-btn');
		$btn.on('click', function(e){
			$checkbox.click();
		});
		$checkbox.on('change hootevchange.alldevice', function(){ // @see notes in betterfont's $resetall.on('click',fn) for hootevchange.alldevice
			var $checkbox = $(this),
				isChecked = $checkbox.is(':checked') ? 'on' : 'off',
				loaddevice = isChecked === 'off' ? $footer_devices.filter('.active').data('device') || 'desktop' : 'desktop';
			$checkbox.siblings('i').data('alldevices', isChecked ).filter('[data-device="' + loaddevice + '"]').trigger('click'); // click the desktop sibling whether checkbox is turned on or off
			$checkbox.closest('.hoot-ctrlbox').find('.hoot-mediabox').data('alldevices', isChecked );
			$checkbox.closest('.hoot-mediaswitcher').removeClass('hoot-alldevices-on hoot-alldevices-off').addClass('hoot-alldevices-' + isChecked);
		});
	});


	/*** Betterrange Control ***/

	$('.betterrange-box').each(function () {
		var $rangebox = $(this),
			$input = $rangebox.find('input[type="hidden"].betterrange-input'),
			$ranges = $rangebox.find('.betterrange-range'),
			$alldevicesCheckbox = $rangebox.closest('.hoot-ctrlbox').find('.hoot-mediaquery-alldevices-checkbox');

		// used by betterfont's ranges to update individual range values absed on main input val (when resetall is clicked)
		$input.on( 'hootevchange.range', function () {
			var $self = $(this),
				val = $self.val(),
				isMultiDevice = $ranges.length > 1;
			if ( isMultiDevice ) {
				try { val = JSON.parse(val); } catch(e) { val = {}; }
				$ranges.each(function () {
					var device = $(this).closest('.hoot-mediabox').data('device'),
						deviceval = val[device] !== undefined ? val[device] : '' ;
					$(this).val( deviceval ).siblings('.betterrange-number').val( deviceval );
				});
				if ( val.alldevices !== undefined && $alldevicesCheckbox.length ) {
					var currentChecked = $alldevicesCheckbox.prop( 'checked' );
					if ( ( val.alldevices === 'on' && ! currentChecked ) || ( val.alldevices === 'off' && currentChecked ) ) {
						$alldevicesCheckbox.prop( 'checked', val.alldevices === 'on' ).trigger('hootevchange.alldevice');
					}
				}
			} else {
				$self.closest('.betterrange-box').find('.betterrange-range, .betterrange-number').val( val );
			}
		});
		function hootUpdateInput() {
			var isMultiDevice = $ranges.length > 1;
			var val = isMultiDevice ? {} : '' ;
			$ranges.each(function () {
				var deviceval = $(this).val();
				if ( isMultiDevice ) {
					var device = $(this).closest('.hoot-mediabox').data('device');
					val[device] = deviceval;
					if ( $alldevicesCheckbox.length )
						val.alldevices = $alldevicesCheckbox.is(':checked') ? 'on' : 'off';
				} else {
					val = deviceval;
				}
			});
			if ( isMultiDevice ) val = JSON.stringify(val);
			$input.val(val).trigger('change');
		}

		$alldevicesCheckbox.on('change', function () {
			hootUpdateInput();
		});

		$ranges.each(function () {
			var $range = $(this),
				$number = $(this).siblings('.betterrange-number'),
				$reset = $(this).siblings('.better-reset');
			$range.on('input change', function () {
				var val = $(this).val();
				$number.val(val);
				hootUpdateInput();
			});
			$number.on('input change', function () {
				var val = parseFloat( $(this).val() ),
					min = parseFloat( $range.attr('min') ),
					max = parseFloat( $range.attr('max') );
				if (isNaN(val)){ val = min; }
				if (val < min) { val = min; }
				if (val > max) { val = max; }
				$range.val(val);
				hootUpdateInput();
			});
			$number.on('blur', function () {
				$(this).val( $range.val() );
			});
			if ( $reset.length ) {
				var resetVal = $reset.data('resetval');
				$reset.on('click', function () {
					$range.val(resetVal);
					$number.val(resetVal);
					hootUpdateInput();
				});
			}
		});

	});


	/*** Spacings Control ***/

	$('.spacings-box').each(function () {
		var $spacebox = $(this),
			isMultiDevice = $spacebox.data('multidevicevalues'),
			$input = $spacebox.find('input[type="hidden"].spacings-input'),
			$units = $spacebox.find('.spacings-unit'),
			$links = $spacebox.find('.spacings-linked input'),
			$alldevicesCheckbox = $spacebox.closest('.hoot-ctrlbox').find('.hoot-mediaquery-alldevices-checkbox');

		var combineval = {};
		function hootUpdateInput() {
			combineval = {};
			if ( $alldevicesCheckbox.length )
				combineval.alldevices = $alldevicesCheckbox.is(':checked') ? 'on' : 'off';
			processInputs($units,false);
			processInputs($links,true);
			combineval = JSON.stringify(combineval);
			$input.val(combineval).trigger('change');
		}
		function processInputs($elements,isCheckbox) {
			$elements.each(function () {
				var deviceval = isCheckbox ? $(this).is(':checked') : $(this).val(),
					spaceId = $(this).data('space');
				if ( isMultiDevice ) {
					var device = $(this).closest('.hoot-mediabox').data('device');
					if ( ! combineval[device] ) { combineval[device] = {}; }
					combineval[device][ spaceId ] = deviceval;
				} else {
					combineval[ spaceId ] = deviceval;
				}
			});
		};

		$alldevicesCheckbox.on('change', function () {
			hootUpdateInput();
		});

		$links.on('change', function () {
			var $linkedunits = $(this).closest('.hoot-mcallwrap').find('.spacings-unit');
			if( $(this).is(':checked') ) {
				var val1 = $linkedunits.filter('[data-space="t"]').val(),
					val2 = $linkedunits.filter('[data-space="r"]').val();
				$linkedunits.filter('[data-space="b"]').val( val1 );
				$linkedunits.filter('[data-space="l"]').val( val2 );
			}
			$linkedunits.data( 'unitlinked', $(this).is(':checked') );
			hootUpdateInput();
		});
		$links.each(function () {
			$(this).closest('.hoot-mcallwrap').find('.spacings-unit').data( 'unitlinked', $(this).is(':checked') )
		});

		$spacebox.find('.better-reset').on('click', function () {
			var datareset = $(this).data('resetval'),
				$unitgroup = $(this).closest('.hoot-mcallwrap');
			if ( typeof datareset === 'string' ) { datareset = JSON.parse( datareset ); }
			if ( datareset && typeof datareset === 'object' ) {
				for ( var key in datareset ) { if ( datareset.hasOwnProperty(key) ) {
					if ( key === 'linked' ) {
						$unitgroup.find('[data-space="linked"]').click(); // click instead of prop to trigger change event and setting of data('unitlinked', true/false)
					} else {
						$unitgroup.find('[data-space="' + key + '"]').val( datareset[key] );
					}
				} }
				hootUpdateInput();
			}
		});
		$units.each(function () {
			var $self = $(this);
			$self.on('input change', function () {
				if( $self.data( 'unitlinked' ) ) {
					var linkkey = $self.data('linkspace');
					if ( linkkey ) {
						$self.closest('.hoot-mcallwrap').find('.spacings-unit[data-space="' + linkkey + '"]').val( $self.val() );
					}
				}
				hootUpdateInput();
			});
			$self.on('focus', function () {
				if( $self.data( 'unitlinked' ) ) {
					var linkkey = $self.data('linkspace');
					if ( linkkey ) {
						$self.closest('.hoot-mcallwrap').find('.spacings-unit[data-space="' + linkkey + '"]').addClass('spacings-unitfocus');
					}
				}
			});
			$self.on("blur", function () {
				var val = parseInt( $self.val() ),
					allowneg = $self.data('allowneg');
				val = allowneg ? val : Math.max(0, val);
				$self.val( val ); // on blur, we add parseInt'ed value to convert to number (removes leading zeros, etc)
				if( $self.data( 'unitlinked' ) ) {
					var linkkey = $self.data('linkspace');
					if ( linkkey ) {
						$self.closest('.hoot-mcallwrap').find('.spacings-unit[data-space="' + linkkey + '"]').val( val ).removeClass('spacings-unitfocus'); // if !allowneg, we need to assign updated val for linked units also
					}
				}
			});
		});

	});


	/*** Betterbackground Control ***/

	$('.hoot-customize-control-betterbackgroundstart').each(function( index ){

		var $blocks = $(this).nextUntil( '.hoot-customize-control-betterbackgroundend', "li" ),
			$bbButtons = $blocks.filter('.hoot-customize-control-betterbackgroundbutton'),
			$buttons = $bbButtons.find('.hoot-betterbackground-button'),
			$typeInput = $bbButtons.find('input.hoot-customize-control-betterbackground'),
			$customs = $blocks.filter('.customize-control-image, .customize-control-select, .customize-control-betterselect'),
			$predefineds = $blocks.filter('.hoot-customize-control-groupstart'),
			hootShowBlocks = function(control){
				if ( control == 'predefined' ) {
					$customs.hide();
					$predefineds.show();
				}
				if ( control == 'custom' ) {
					$predefineds.hide();
					$customs.show();
				}
			};

		$blocks.addClass('hoot-customize-control-background-blocks');//.attr('data-controlbackground', id);

		// If we have both custom image and pattern options
		if ( $bbButtons.length ) {
			hootShowBlocks( $typeInput.val() );

			$buttons.on('click',function(){
				var value = $(this).data('value');

				$buttons.removeClass('selected').addClass('deactive');
				$(this).removeClass('deactive').addClass('selected');

				$typeInput.val(value).trigger('change');

				hootShowBlocks(value);
			});

		}

		/* Patterns */

		var $pattPreview = $blocks.find('.hoot-betterbackground-button-pattern'),
			$patterns = $blocks.find('.hoot-customize-radioimage');

		if ( $pattPreview.length ) {
			$pattPreview.html('').append( $patterns.filter('.radiocheck').children('img').clone() );

			$patterns.on('click',function(){
				$pattPreview.html('').append( $(this).children('img').clone() );
			});
		}

	});


	/*** Icon Control ***/

	if ( (typeof hoot_customize_data != 'undefined') && (typeof hoot_customize_data.iconslist != 'undefined') ) {

		/** Fly Icon **/

		var $body = $('body'),
			$flyicon = $('#hoot-flyicon-content');

		$body.on( "openflypanel", function() {
			var $flypanelbutton = $body.data('flypanelbutton');
			if( $flypanelbutton && $flypanelbutton.data('flypaneltype')=='icon' && $flypanelbutton.data('flypanel')=='open' ) {

				$flyicon.html( hoot_customize_data.iconslist ).data('controlgroup', $flypanelbutton);

				var $flyiconIcons = $flyicon.find('i'),
					$input = $flypanelbutton.siblings('input.hoot-customize-control-icon'),
					selected = $input.val(),
					$icondisplay = $flypanelbutton.children('i');

				$flypanelbutton.addClass('flygroup-open');

				if(selected)
					$flyicon.find('i.'+selected.replace(' ', '.')).addClass('selected');

				$flyiconIcons.click( function(event){
					var iconvalue = $(this).data('value');
					$flyiconIcons.removeClass('selected');
					$(this).addClass('selected');
					$input.val( iconvalue ).trigger('change');
					$icondisplay.removeClass().addClass(iconvalue );
					$('.hoot-flypanel-back').trigger('click');
				});

				$body.addClass('hoot-displaying-flyicon');
				$body.data('flypaneltype','icon');
			}
		});

		$body.on( "closeflypanel", function() {
			$body.removeClass('hoot-displaying-flyicon');
			var controlGroup = $flyicon.data('controlgroup');
			if (controlGroup)
				$(controlGroup).removeClass('flygroup-open');
			if($body.data('flypaneltype')=='icon') {
				$body.data('flypaneltype','');
			}
		});

		$('.hoot-customize-control-icon-remove').click( function(event){
			var input = $(this).siblings('input.hoot-customize-control-icon'),
				icondisplay = $(this).siblings('.hoot-customize-control-icon-picked').children('i');
			input.val('').trigger('change');
			icondisplay.removeClass();
			// $('.hoot-flypanel-back').trigger('click'); // redundant
		});

	}

	/*** Tabs Control ***/

	/** Prepare Tabs **/

	$( ".hoot-tabs-control" ).each( function( index ) {
		var $li = $(this).closest('li'),
			liID = $li.attr('id'),
			$tabs = $(this).children('.hoot-tab-control'),
			isHeading = $(this).is('.hoot-tabs-heading'),
			disablejstoggle = $(this).data('disablejstoggle') ? true : false,
			tcount = 1;

		if ( $li.length && $tabs.length ) {
			$tabs.each( function( index ) {
				var tslug = $(this).data('tab');
				var $tabstart = $( '#' + liID + '-' + tslug ),
					$tabend   = $( '#' + liID + '-' + tslug + '-end' );
				var $tabunits = $tabstart.nextUntil($tabend).add($tabstart).add($tabend);

				if ( ! isHeading ) $tabunits.addClass('hoot-tab-unit');
				else               $tabunits.addClass('hoot-tab-fullunit');
				$tabstart.addClass('hoot-tab-start');
				$tabend.addClass('hoot-tab-end');
				if ( tcount === 1 ) {
					$(this).addClass('hootactive');
				} else {
					if ( disablejstoggle ) {
						$tabunits.addClass('hootdeactive');
					} else {
						$tabunits.hide();
					}
				}
				$tabunits.attr('data-controlgroup', liID);

				$(this).on('click', function(){
					$tabs.removeClass('hootactive');
					$(this).addClass('hootactive');
					if ( disablejstoggle ) {
						$('li[data-controlgroup="' + liID + '"]').addClass('hootdeactive');
						$tabunits.removeClass('hootdeactive');
					} else {
						$('li[data-controlgroup="' + liID + '"]').slideUp();
						var $unitsToSlide = $tabunits; // Clone $tabunits to apply exclusions
								var $select1 = $tabunits.filter('#customize-control-sidebar1_width');
								if ($select1.length) {
									var s1val = $select1.find('select').val();
									if (s1val === 'auto') {
										$unitsToSlide = $unitsToSlide.not('#customize-control-sidebar1_width_px,#customize-control-sidebar1_width_pcnt');
									} else if (s1val === 'px') {
										$unitsToSlide = $unitsToSlide.not('#customize-control-sidebar1_width_pcnt');
									} else if (s1val === 'pcnt') {
										$unitsToSlide = $unitsToSlide.not('#customize-control-sidebar1_width_px');
									}
									var $select2 = $tabunits.filter('#customize-control-sidebar2_width');
									if ($select2.length) {
										var s2val = $select2.find('select').val();
										if (s2val === 'auto') {
											$unitsToSlide = $unitsToSlide.not('#customize-control-sidebar2_width_px,#customize-control-sidebar2_width_pcnt');
										} else if (s2val === 'px') {
											$unitsToSlide = $unitsToSlide.not('#customize-control-sidebar2_width_pcnt');
										} else if (s2val === 'pcnt') {
											$unitsToSlide = $unitsToSlide.not('#customize-control-sidebar2_width_px');
										}
									}
								}
						$unitsToSlide.slideDown();
					}
				} );
				tcount++;
			} );
		}
	} );


	/*** Group Control ***/

	/** Prepare Groups **/

	$( ".hoot-customize-control-groupstart" ).each( function( index ) {
		var id = $(this).attr('id'),
			moveBlocks = $(this).nextUntil( '.hoot-customize-control-groupend', "li" );
		moveBlocks.addClass('hoot-customize-control-group-blocks').attr('data-controlgroup', id);
	});


	/** Fly Groups **/

	var $body = $('body');

	$body.on( "openflypanel", function() {
		var $flypanelbutton = $body.data('flypanelbutton');
		if( $flypanelbutton && $flypanelbutton.data('flypaneltype')=='group' && $flypanelbutton.data('flypanel')=='open' ) {
			var $groupstart = $flypanelbutton.closest('.hoot-customize-control-groupstart');
			$groupstart.addClass('flygroup-open');
			var moveBlocks = $groupstart.nextUntil( '.hoot-customize-control-groupend', "li" );
			$('#hoot-flygroup-content ul').css('display','none').html('').append(moveBlocks).fadeIn();
			$body.addClass('hoot-displaying-flygroup');
			$body.data('flypaneltype','group');
		}
	});

	$body.on( "closeflypanel", function() {
		$body.removeClass('hoot-displaying-flygroup');
		if($body.data('flypaneltype')=='group') {
			var itemsToMove = $('#hoot-flygroup-content > ul > li');
			if ( itemsToMove.length ) {
				var controlgroup = $(itemsToMove[0]).data('controlgroup'); // all li's in flygroup have same controlgroup
				itemsToMove.insertBefore('#' + controlgroup + '-end');
				$('#' + controlgroup).removeClass('flygroup-open');
			}
			$body.data('flypaneltype','');
		}
	});


	/*** Multi Check Boxes ***/

	$('.customize-control-bettercheckbox .bettercheckbox-multi').each(function(){

		var $control = $(this),
			$multi = $control.find('input[type="checkbox"]'),
			$input = $control.find('input[type="hidden"]');

		$multi.on('change', function(){
			var multiValues = $multi.filter(':checked').map(function(){
				return this.value;
			}).get().join(',');
			$input.val(multiValues).trigger('change');
		});

	});


	/*** Fly Panels - generic ***/
	// This code doesnt 'do' anything. It just acts as framework for other flypanel types.

	var $body = $("body"),
		$flypanelButtons = $('.hoot-flypanel-button'),
		hootInitFly = function() {
			$flypanelButtons.click( function(event){
				if( $body.data('flypanel')=='open' && $(this).data('flypanel')=='open' ) {
					hootCloseFly();
				} else {
					hootCloseFly();
					hootOpenFly($(this));
				}
				event.stopPropagation();
			});
			$('.hoot-flypanel-back, .hoot-flypanel-close').click( function(event){
				hootCloseFly();
				event.stopPropagation();
			});
			$('.hoot-flypanel').click( function(event){
				event.stopPropagation();
			});
			$body.click( function(event){
				if ( ! $(event.target).closest('.media-modal').length )
					hootCloseFly();
			});
			var $obstarget = $('#hoot-flygroup-content ul');
			if ($obstarget.length) {
				var obstarget = $obstarget[0];
				var grpobserver = new MutationObserver(function(mutations) {
					mutations.forEach(function(mutation) {
						if ($(obstarget).children().length === 0) {
							hootCloseFly(true);
						}
					});
				});
				var config = {
					childList: true, // Observe direct child additions/removals
					subtree: false   // Do not observe deeper descendants
				};
				grpobserver.observe(obstarget, config);
			}
		},
		hootCloseFly = function(force=false){
			if( $body.data('flypanel')=='open' ) {
				$body.data('flypanel','close');
				$body.data('flypanelbutton','');
				$flypanelButtons.data('flypanel','close');
				$body.trigger('closeflypanel');
			}
		},
		hootOpenFly = function($flypanelButton){
			$body.data('flypanel','open');
			$body.data('flypanelbutton',$flypanelButton);
			$flypanelButton.data('flypanel','open');
			$body.trigger('openflypanel');
		};

	hootInitFly();


});