/**
 * File customizer_admin.js.
 * Theme Customizer extensions.
 */

(function($) {
	// $(document).on('ready', function() {
	$(function() {
		// init js
		customizer.setup();
	});
})(jQuery);

var customizer = new function() {
	
	this.debug = true;
	this.reload = true;
	
	this.setup = function() {
		// init customizer admin
		this.init();
		this.addBindings();
		this.addDependencies();
	}

	this.init = function() {
		
		// enable Preset Pickers
		this.initPresetPicker();

		$('#customize-info .customize-panel-description').html(customizer_wordings.info_text);

		//
		// custom range control
		$('.customize-control-custom_range').each( function () {
			customizer.setRange($(this).find('input'));
			$(this).find('input').on('input change', function () {
				customizer.setRange(this);
			});
		} );

		//
		// group control
		$('.customize-control-group').each( function() {
			customizer.toggleGroup(this);
			$(this).on('click', function () {
				customizer.toggleGroup(this);
			});
		} );
		// open group on dropshadow activation
		$('input[type="checkbox"][id*="shadow"]').on('change', function(){
			if ( $(this).is(':checked') ) {
				var parent  = $(this).closest('.customize-control');
				var group   = parent.next('.customize-control.customize-control-group');
				if ( group.length > 0 ) {
					if ( !group.next().hasClass('show') ) group.trigger('click');
				}
			}
		});

		//
		// fontfamily control
		$('.customize-control-fontfamily').each( function() {

			customizer.fontfamilyWeights(this);

			$(this).find('select').on('change', function () {
				customizer.fontfamilyChange(this);
			} );
			// weights
			$(this).find('input[type=checkbox]').on('change', function () {
				customizer.fontfamilyChange(this);
			} );
			// actual font
			$(this).find('input[type=hidden]').on('change', function () {
				customizer.fontfamilyChange(this);
			} );
			// custom font
			$(this).find('input[type=button]').on('click', function () {
				if ($(this)[0].id.indexOf('ffdelete') > -1) {
					customizer.fontfamilyDelete(this);
				}
				else if ($(this)[0].id.indexOf('ffedit') > -1) {
					customizer.fontfamilyEdit(this);
				}
				else {
					customizer.fontfamilyChoose(this);
				}
			} );
			$(this).find('input[name=font]').on('change', function () {
				customizer.fontfamilySelect(this);
			} );
			$(this).find('form').submit(function (e) {
				e.preventDefault();
				customizer.fontfamilyUpload(this);
			} );
		} );
		$('.customize-control-ffselect').each( function() {
			$(this).find('select').on('change', function () {
				customizer.ffselectChange(this);
			} );
			customizer.ffselectLog(this);
		} );

		//
		// color control
		var ccs = [ "customize-control-color11", "customize-control-color12", "customize-control-color13",
					"customize-control-color21", "customize-control-color22", "customize-control-color23",
					"customize-control-color31", "customize-control-color32", "customize-control-color33",
					"customize-control-color41", "customize-control-color42", "customize-control-color43",
					"customize-control-color51", "customize-control-color52", "customize-control-color53",
					"customize-control-color61", "customize-control-color62", "customize-control-color63", ];
		for (var i=0; i<ccs.length; i++) {
			$('#'+ccs[i]+' .wp-color-result').on('click', function() { customizer.colselectSetup(this); } );
			$('#'+ccs[i]+' .wp-color-picker').on('change click input', function() { customizer.colselectSetup(this); } );
			$('#'+ccs[i]+' .wp-picker-holder').on('click mouseup', function() { customizer.colselectSetup(this); } );
		}
		$('.customize-control-colselect').each( function() {
			$(this).find('select').on('change', function () {
				customizer.colselectChange(this);
			} );
			$(this).find('.customize-control-colors .col').on('click', function () {
				customizer.colselectSet(this);
			} );
			$(this).find('.customize-control-colors-more').on('click', function () {
				customizer.colselectMore(this);
			} );
			customizer.colselectLog(this);
		} );

		//
		// toggle color concept
		if (wp.customize.control('enable_colorconcept').setting.get()) {
			// hide colors 2.0 toggle
			$('#customize-control-sep_colorconcept').addClass('customize-control-off');
			$('#customize-control-enable_colorconcept').addClass('customize-control-off');
			$('#customize-control-colorconcept_info').addClass('customize-control-off');
		}

		//
		// logging
		$('.customize-control-log').each( function () {
			$(this).on('click', function () {
				$(this).toggleClass('show');
			});
		} );
		
		//
		// reload page on panels
		if (wp.customize.control('enable_pageloader').setting.get()) {
			customizer.reload = true;
			// console.log('page reloader enabled');
		} else {
			customizer.reload = false;
			// console.log('page reloader disabled');
		}
		$('#customize-control-enable_pageloader input').on('change', function () {
			if ($(this).prop('checked')) {
				customizer.reload = true;
				// console.log('page reloader enabled');
			}
			else {
				customizer.reload = false;
				// console.log('page reloader disabled');
			}
		});

		//
		// header 2.0
		//
		// toggle header concept
		if (wp.customize.control('enable_headerconcept').setting.get()) {
			// console.log('header 2.0 enabled');
			// hide header 2.0 toggle
			$('#customize-control-sep_headerconcept').addClass('customize-control-off');
			$('#customize-control-enable_headerconcept').addClass('customize-control-off');
			$('#customize-control-headerconcept_info').addClass('customize-control-off');
			// // hide old sections
			// $('#accordion-section-section_header').addClass('customize-control-off');
			// $('#accordion-section-section_navi').addClass('customize-control-off');
			// $('#accordion-section-section_meta').addClass('customize-control-off');
			// $('#accordion-section-section_footer').addClass('customize-control-off');
			// check offmenu sections
			var navimode = wp.customize.control('navi_header_mode').setting.get();
			var burgermode = wp.customize.control('navi_header_burger_mode').setting.get();
			if (navimode == 'none' || burgermode == 'none')
				$('#accordion-section-section_navi_header_offcanvas').addClass('customize-control-off');
			var metamode = wp.customize.control('navi_header_sec_mode').setting.get();
			var metaburgermode = wp.customize.control('navi_header_sec_burger_mode').setting.get();
			if (metamode == 'none' || metaburgermode == 'none')
				$('#accordion-section-section_navi_header_sec_offcanvas').addClass('customize-control-off');
		}
		else {
			// console.log('header 2.0 disabled');
			// hide new header sections
			$('#accordion-section-section_navi_header').addClass('customize-control-off');
			$('#accordion-section-section_navi_header_offcanvas').addClass('customize-control-off');
			$('#accordion-section-section_navi_header_sec').addClass('customize-control-off');
			$('#accordion-section-section_navi_header_sec_offcanvas').addClass('customize-control-off');
			$('#accordion-section-section_navi_footer').addClass('customize-control-off');
			$('#accordion-section-section_dropdown').addClass('customize-control-off');
		}
		$('#customize-control-enable_headerconcept input').on('change', function () {
			if ($(this).prop('checked')) {
				// console.log('header 2.0 enabled');
				// hide old sections
				$('#accordion-section-section_header').addClass('customize-control-off');
				$('#accordion-section-section_navi').addClass('customize-control-off');
				$('#accordion-section-section_meta').addClass('customize-control-off');
				$('#accordion-section-section_footer').addClass('customize-control-off');
				// show new header sections
				$('#accordion-section-section_navi_header').removeClass('customize-control-off');
				$('#accordion-section-section_navi_header_offcanvas').removeClass('customize-control-off');
				$('#accordion-section-section_navi_header_sec').removeClass('customize-control-off');
				$('#accordion-section-section_navi_header_sec_offcanvas').removeClass('customize-control-off');
				$('#accordion-section-section_navi_footer').removeClass('customize-control-off');
				$('#accordion-section-section_dropdown').removeClass('customize-control-off');
				// check offmenu sections
				var navimode = wp.customize.control('navi_header_mode').setting.get();
				var burgermode = wp.customize.control('navi_header_burger_mode').setting.get();
				if (navimode == 'none' || burgermode == 'none')
					$('#accordion-section-section_navi_header_offcanvas').addClass('customize-control-off');
				var metamode = wp.customize.control('navi_header_sec_mode').setting.get();
				var metaburgermode = wp.customize.control('navi_header_sec_burger_mode').setting.get();
				if (metamode == 'none' || metaburgermode == 'none')
					$('#accordion-section-section_navi_header_sec_offcanvas').addClass('customize-control-off');
			}
			else {
				// console.log('header 2.0 disabled');
				// show old sections
				$('#accordion-section-section_header').removeClass('customize-control-off');
				$('#accordion-section-section_navi').removeClass('customize-control-off');
				$('#accordion-section-section_meta').removeClass('customize-control-off');
				$('#accordion-section-section_footer').removeClass('customize-control-off');
				// hide new header sections
				$('#accordion-section-section_navi_header').addClass('customize-control-off');
				$('#accordion-section-section_navi_header_offcanvas').addClass('customize-control-off');
				$('#accordion-section-section_navi_header_sec').addClass('customize-control-off');
				$('#accordion-section-section_navi_header_sec_offcanvas').addClass('customize-control-off');
				$('#accordion-section-section_navi_footer').addClass('customize-control-off');
				$('#accordion-section-section_dropdown').addClass('customize-control-off');
			}
		} );
		
		$('#customize-control-navi_header_mode select').on('change', function () {
			var navimode = $(this).val();
			// console.log('header 2.0 mode changed to: '+navimode);
			if (navimode == 'none')
				$('#accordion-section-section_navi_header_offcanvas').addClass('customize-control-off');
			else
				$('#accordion-section-section_navi_header_offcanvas').removeClass('customize-control-off');
		} );
		$('#customize-control-navi_header_burger_mode select').on('change', function () {
			var burgermode = $(this).val();
			// console.log('header 2.0 burger mode changed to: '+burgermode);
			if (burgermode == 'none')
				$('#accordion-section-section_navi_header_offcanvas').addClass('customize-control-off');
			else
				$('#accordion-section-section_navi_header_offcanvas').removeClass('customize-control-off');
		} );
		$('#customize-control-navi_header_sec_mode select').on('change', function () {
			var metamode = $(this).val();
			// console.log('header 2.0 sec mode changed to: '+metamode);
			if (metamode == 'none')
				$('#accordion-section-section_navi_header_sec_offcanvas').addClass('customize-control-off');
			else
				$('#accordion-section-section_navi_header_sec_offcanvas').removeClass('customize-control-off');
		} );
		$('#customize-control-navi_header_sec_burger_mode select').on('change', function () {
			var burgermode = $(this).val();
			// console.log('header 2.0 sec burger mode changed to: '+burgermode);
			if (burgermode == 'none')
				$('#accordion-section-section_navi_header_sec_offcanvas').addClass('customize-control-off');
			else
				$('#accordion-section-section_navi_header_sec_offcanvas').removeClass('customize-control-off');
		} );
		
		//
		// module
		// toggle login page
		if (typeof wp.customize.control('custom_login_style') !== 'undefined' &&
			wp.customize.control('custom_login_style').setting.get() === 0) {
			// hide custom login toggle
			$('#customize-control-sep_options').addClass('customize-control-off');
			$('#customize-control-custom_login_style').addClass('customize-control-off');
			$('#customize-control-custom_login_style_info').addClass('customize-control-off');
		}
		
		//
		// buttons control
		$('.customize-control-button input').each( function () {
			var mode = $(this).attr('mode');
			if (typeof(mode) !== 'undefined') {
				// console.log(mode);
				if (mode == 'create_template') {
					$(this).on('click', function () {
						customizer.createTemplate(this);
					} );
					if ($(this).attr('template_id') != "") 
						$(this).parent().children().each(function() { $(this).css('display', 'none') });
				}
				if (mode == 'edit_template') {
					$(this).on('click', function () {
						customizer.editTemplate(this);
					} );
					if ($(this).attr('template_id') == "") 
						$(this).parent().children().each(function() { $(this).css('display', 'none') });
				}
				if (mode == 'edit_menu') {
					$(this).on('click', function () {
						// console.log("link to menu edit");
						customizer.editMenu(this);
					} );
				}
			}
		} );

		//
		// shadow control
		$('.customize-control-shadow').each( function () {
			customizer.setShadow(this);
		} );

		//
		// navi style control
		$('#customize-control-navi_style select').each( function () {
			// setup
			var value = $(this).val();
			// var value = $(this).prop('checked');
			//console.log(input);
			if (value != 'hover') {
				$('#customize-control-group_navi_menu_sub').css('display', 'none');
				$('#customize-control-group_navi_menu_sub_item').css('display', 'none');
				$('#customize-control-group_navi_hamburger').css('display', 'none');
				$('#customize-control-group_navi_hamburger_item').css('display', 'none');
			}
			else {
				$('#customize-control-group_navi_off').css('display', 'none');
				$('#customize-control-group_navi_off_item').css('display', 'none');
			}
			// add event
			$(this).on('change', function () {
				var value = $(this).val();
				// console.log(value);
				if (value != 'hover') {
					$('#customize-control-group_navi_menu_sub').css('display', 'none');
					$('#customize-control-group_navi_menu_sub_item').css('display', 'none');
					$('#customize-control-group_navi_hamburger').css('display', 'none');
					$('#customize-control-group_navi_hamburger_item').css('display', 'none');
					$('#customize-control-group_navi_off').css('display', 'list-item');
					$('#customize-control-group_navi_off_item').css('display', 'list-item');
				}
				else {
					$('#customize-control-group_navi_menu_sub').css('display', 'list-item');
					$('#customize-control-group_navi_menu_sub_item').css('display', 'list-item');
					$('#customize-control-group_navi_hamburger').css('display', 'list-item');
					$('#customize-control-group_navi_hamburger_item').css('display', 'list-item');
					$('#customize-control-group_navi_off').css('display', 'none');
					$('#customize-control-group_navi_off_item').css('display', 'none');
				}
			} );
		} );

	}

	this.createTemplate = function(el) {
		var name = $(el).attr('template');
		// console.log("create template: "+name);
		$.post(
			wizzard_details.ajax_url, {
				'action': 'greyd_ajax',
				'_ajax_nonce': wizzard_details.nonce,
				'mode': 'install_template',
				'data': { name: name }
			}, 
			function(response) {
				if (response.indexOf('error::') > -1) {
					console.warn(response);
					var tmp = response.split('error::');
					alert(tmp[1]);
				}
				else {
					// console.info(response);
					var mode = 'success';
					if (response.indexOf('info::') > -1) mode = 'info';
					var tmp = response.split(mode+'::');
					var post_id = tmp[1].split('(id ');
					post_id = post_id[1].split(')');

					$(el).parent().children().each(function() { $(this).css('display', 'none') });
					$(el).parent().prev().find('.description').css('display', 'block');
					$(el).parent().prev().find('input').css('display', 'block');
					$(el).parent().prev().find('input').attr('template_id', post_id[0]);
					// alert("Template '"+name+"' (id "+post_id[0]+") created!");
					alert(customizer_wordings.template_created.replace('%1s',name).replace('%2s',post_id[0]));
				}
			}
		);
	}
	this.editTemplate = function(el) {
		var id = $(el).attr('template_id');
		var url = window.location.href.split('wp-admin');
		if (id == "")
			window.open(url[0]+"wp-admin/post.php?post_type=dynamic_template", '_blank');
		else
			window.open(url[0]+"wp-admin/post.php?action=edit&post="+id, '_blank');
	}
	this.editMenu = function(el) {
		var id = $(el).attr('menu');
		var url = window.location.href.split('wp-admin');
		if (id == "")
			window.open(url[0]+"wp-admin/nav-menus.php", '_blank');
		else
			window.open(url[0]+"wp-admin/nav-menus.php?action=edit&menu="+id, '_blank');
	}
	
	//
	// customizer bindings
	this.addBindings = function() {
		// panel 'panel_settings'
		wp.customize.panel( 'panel_settings', function(section) { customizer.previewPage( section, '?tp_preview_page=1' ) } );	
		// sections 'section_brand_*'
		wp.customize.section( 'section_brand_logo', function(section) { customizer.previewPage( section, '?tp_preview_page=1', 'top' ) } );
		wp.customize.section( 'section_brand_fonts', function(section) { customizer.previewPage( section, '?tp_preview_page=1', '#anchor_fonts' ) } );
		wp.customize.section( 'section_brand_colors', function(section) { customizer.previewPage( section, '?tp_preview_page=1', '#anchor_colors' ) } );
		// wp.customize.section( 'section_brand_colors', function(section) { customizer.previewPage( section, '?tp_preview_page=1', '#anchor_buttons' ) } );

		// panel 'panel_navigation'
		wp.customize.panel( 'panel_navigation', function(section) { customizer.previewPage( section, '?tp_preview_page=1', 'top' ) } );	
		// sections
		wp.customize.section( 'section_header', function(section) { customizer.previewPage( section, '?tp_preview_page=1', 'top' ) } );
		wp.customize.section( 'section_navi', function(section) { customizer.previewPage( section, '?tp_preview_page=1', 'top' ); customizer.previewAction( section, 'hover' ) } );
		wp.customize.section( 'section_meta', function(section) { customizer.previewPage( section, '?tp_preview_page=1', 'top' ); customizer.previewAction( section, 'hovermeta' ) } );
		wp.customize.section( 'section_footer', function(section) { customizer.previewPage( section, '?tp_preview_page=1', '.footer' ) } );
		// header 2.0
		wp.customize.section( 'section_navi_header', function(section) { customizer.previewPage( section, '?tp_preview_page=1', 'top' ) } );
		wp.customize.section( 'section_navi_header_offcanvas', function(section) { customizer.previewPage( section, '?tp_preview_page=1', 'top' ); customizer.previewAction( section, 'hover' ) } );
		wp.customize.section( 'section_navi_header_sec_offcanvas', function(section) { customizer.previewPage( section, '?tp_preview_page=1', 'top' ); customizer.previewAction( section, 'hovermeta' ) } );
		wp.customize.section( 'section_dropdown', function(section) { customizer.previewPage( section, '?tp_preview_page=1', 'top' ); customizer.previewAction( section, 'hoverdrop' ) } );
		wp.customize.section( 'section_navi_footer', function(section) { customizer.previewPage( section, '?tp_preview_page=1', '#footer' ) } );

		// panel 'panel_elements'
		wp.customize.panel( 'panel_elements', function(section) { customizer.previewPage( section, '?tp_preview_page=1' ) } );	
		// sections
		wp.customize.section( 'section_body', function(section) { customizer.previewPage( section, '?tp_preview_page=1', '#anchor_body' ) } );
		wp.customize.section( 'section_headlines', function(section) { customizer.previewPage( section, '?tp_preview_page=1', '#anchor_headlines' ) } );
		wp.customize.section( 'section_buttons', function(section) { customizer.previewPage( section, '?tp_preview_page=1', '#anchor_buttons' ) } );
		wp.customize.section( 'section_links', function(section) { customizer.previewPage( section, '?tp_preview_page=1', '#anchor_links' ) } );
		wp.customize.section( 'section_forms', function(section) { customizer.previewPage( section, '?tp_preview_page=1', '#anchor_forms' ) } );
		wp.customize.section( 'section_messages', function(section) { customizer.previewPage( section, '?tp_preview_page=1', '#anchor_messages' ) } );
		wp.customize.section( 'section_tables', function(section) { customizer.previewPage( section, '?tp_preview_page=1', '#anchor_tables' ) } );

		// panel 'panel_more'
		wp.customize.panel( 'panel_more', function(section) { customizer.previewPage( section, '' ) } );
		// sections
		wp.customize.section( 'section_grid', function(section) { customizer.previewPage( section, '?tp_preview_page=1', '#anchor_grid' ) } );	

		// dev
		wp.customize.section( 'section_dev', function(section) { customizer.previewPage( section, '?tp_preview_page=1', '#anchor_dev' ) } );	

		// listen to previewer refresh
		wp.customize.previewer.bind('checksection', function(data) {
			// console.log('check for open section ...' );
			if (wp.customize.section('section_navi').expanded()) wp.customize.previewer.send( 'hover', true );
			if (wp.customize.section('section_meta').expanded()) wp.customize.previewer.send( 'hovermeta', true );
			// header 2.0
			if (wp.customize.section('section_navi_header_offcanvas').expanded()) wp.customize.previewer.send( 'hover', true );
			if (wp.customize.section('section_navi_header_sec_offcanvas').expanded()) wp.customize.previewer.send( 'hovermeta', true );
			if (wp.customize.section('section_dropdown').expanded()) wp.customize.previewer.send( 'hoverdrop', true );
		});
	}

	this.previewPage = function(section, page, anchor='top') {
		section.expanded.bind( function( isExpanded ) {
			if (isExpanded) {
				var newurl = wp.customize.settings.url.home+page;
				if (wp.customize.previewer.getFrontendPreviewUrl() != newurl && customizer.reload === true) {
					if (anchor == 'top') wp.customize.previewer.send( 'scroll', 'top' );
					else if (anchor != "") newurl += anchor;
					wp.customize.previewer.previewUrl.set( newurl );
				}
				else if (anchor != "")
					wp.customize.previewer.send( 'scroll', anchor );
			}
		} );
	}
	this.previewAction = function(section, action) {
		section.expanded.bind( function( isExpanded ) {
			wp.customize.previewer.send( action, isExpanded );
		} );
	}

	//
	// dependency control
	this.addDependencies = function() {
		// search dependencies
		var dependencies = shared.getDependencies();
		// console.log(dependencies);
		// wire dependencies
		for (var mod of Object.keys(dependencies)) {
			dependencies[mod]['type'] = shared.getModField(mod, 'type');
			var dependency = dependencies[mod];
			var element = '#customize-control-'+mod;
			var input = this.findInput(element, dependency);
			var event = 'change';
			if (dependencies[mod]['type'] == 'range' || 
				dependencies[mod]['type'] == 'text' || 
				dependencies[mod]['type'] == 'textarea')
				event = 'input change';
			if (input != undefined) {
				$(input).data('dependency', dependency)
				this.setDependencies(input);
				input.on(event, function () {
					customizer.setDependencies(this);
				} );
			}
		}
	}
	this.setDependencies = function(el) {
		var dependencies = $(el).data('dependency');
		var value = customizer.getInputValue(el, dependencies);
		if (value != undefined) {
			for (var i=0; i<dependencies.length; i++) {
				var mod = dependencies[i]['mod'];
				var dependency = dependencies[i]['dependency'];
				var display = customizer.setDependency(value, dependency);

				if (display) display = 'list-item';
				else display = 'none';
				
				var element = '#customize-control-'+mod;
				var oldDisplay = $(element).css('display');

				if (oldDisplay != display) {
					$(element).css('display', display);
					if (shared.getModField(mod, 'transport') == 'refresh')
						wp.customize.previewer.refresh();
				}
			}
		}
	}
	this.setDependency = function(value, dependency) {
		var display = false;
		// old dependency style (single element without value)
		if (typeof dependency === 'string' ) {
			display = shared.calcDependency(value, { 'element': dependency, 'not_value': "" });
		}
		// single dependency
		else if (dependency['element'] != undefined) {
			display = shared.calcDependency(value, dependency);
		}
		// multi dependency
		else {
			var hits = 0;
			var count = 0;
			for (var key of Object.keys(dependency)) {
				if (key != 'operator') {
					var m_dependency = dependency[key];
					if (typeof m_dependency === 'string' ) {
						m_dependency = {
							'element': dependency[key],
							'not_value': "",
							'type': shared.getModField(dependency[key], 'type')
						};
					}
					// console.log(m_dependency);
					// console.log(m_dependency['element']);
					var m_element = '#customize-control-'+m_dependency['element'];
					var m_input = customizer.findInput(m_element, m_dependency);
					var m_value = customizer.getInputValue(m_input, m_dependency);

					var m_display = this.setDependency(m_value, m_dependency);
					if (m_display) hits++;
					count++;
				}
			}
			if (dependency['operator'] == 'and') {
				if (hits == count) display = true;
			}
			else if (dependency['operator'] == 'or') {
				if (hits > 0) display = true;
			}
		}
		return display;	
	}

	this.findInput = function(element, atts) {
		var type = false;
		if (atts['type'] != undefined) type = atts['type'];
		else if (atts['element'] != undefined) type = shared.getModField(atts['element'], 'type');
		// console.log(element+" : "+type);
		var input = undefined;
		if (type == 'checkbox') input = $(element).find('input');
		else if (type == 'select' || type == 'colselect') input = $(element).find('select');
		else if (type == 'radio') input = $(element).find('input');
		else if (type == 'text') input = $(element).find('input');
		else if (type == 'textarea') input = $(element).find('textarea');
		else if (type == 'range') input = $(element).find('input');
		else if (type == 'acolor') input = $(element).find('input.alpha-color-control');
		else if (type == 'fontfamily') input = $(element.replace('#customize-control-', '#input-ffgoogle-'));
		// console.log(input);
		return input;
	}
	this.getInputValue = function(element, atts) {
		var type = false;
		if (atts['type'] != undefined) type = atts['type'];
		else if (atts['element'] != undefined) type = shared.getModField(atts['element'], 'type');
		// console.log(element+" : "+type);
		var value = undefined;
		if (type == 'checkbox') value = $(element).prop('checked');
		else if (type == 'select') value = $(element).val();
		else if (type == 'radio') value = $('input[name="'+$(element).prop('name')+'"]:checked').val();
		else if (type == 'text') value = $(element).val();
		else if (type == 'textarea') value = $(element).val();
		else if (type == 'range') value = $(element).val();
		return value;
	}

	//
	// shadow control
	this.setShadow = function(el) {
		$(el).find('select').on('change', function () {
			customizer.calcShadow(el);
		});
		$(el).find('input[type=range]').each(function(){
			customizer.setShadowRange($(this));
			$(this).on('input change', function () {
				customizer.setShadowRange(this);
				customizer.calcShadow(el);
			});
		});

		$(el).find('.customize-control-colors .col').on('click', function () {
			customizer.colselectSet(this);
		} );
		$(el).find('.customize-control-colors-more').on('click', function () {
			customizer.colselectMore(this);
		} );
		customizer.colselectLog(el);
	}
	this.setShadowRange = function(el) {
		var val = $(el).val();
		var lbl = $(el).prev('.cs-range-value').data('lbl');
		var unit = $(el).prev('.cs-range-value').data('unit');

		val_edit = '<span style="background: #fff;" onclick="customizer.getShadowRange(this,'+val+')">'+val+'</span>';
		$(el).prev('.cs-range-value').html(lbl+' '+val_edit+unit);
		$(el).val(val);
	}
	this.getShadowRange = function(el, val) {
		var modlabel = $(el).closest('.cs-range-value').data('lbl').trim().replace(/:+$/, "");
		var newVal = prompt(customizer_wordings.enter_value.replace('%s', modlabel), val);
		if (newVal != null && !isNaN(newVal)) {
			if (newVal > 100) newVal = 100;
			if (newVal < 0) newVal = 0;
			var input = $(el).parent().next();
			$(input).val(newVal);
			$(input).trigger("change");
		}
	}
	this.calcShadow = function(el) {
		var id = $(el).attr('id').replace('customize-control-', '');
		var sdw = {
			'type': $('#input-sdw-type-'+id).val(),
			'x': $('#input-sdw-x-'+id).val().replace('px', ''),
			'y': $('#input-sdw-y-'+id).val().replace('px', ''),
			'blur': $('#input-sdw-blur-'+id).val().replace('px', ''),
			'spread': $('#input-sdw-spread-'+id).val().replace('px', ''),
			'color': $('#input-sdw-color-'+id).val(),
			'opacity': $('#input-sdw-opacity-'+id).val(),
		};
		var shadow = '';
		if ( (sdw['x'] == '0' && sdw['y'] == '0' && sdw['blur'] == '0' && sdw['spread'] == '0') || sdw['opacity'] == '0' )
			shadow = 'none';
		else {
			if (sdw['type'] != '') shadow = sdw['type']+' ';
			if (sdw['x'] == "") sdw['x'] = 0;
			if (sdw['y'] == "") sdw['y'] = 0;
			if (sdw['blur'] == "") sdw['blur'] = 0;
			if (sdw['spread'] == "") sdw['spread'] = 0;
			shadow += sdw['x']+'px '+sdw['y']+'px '+sdw['blur']+'px '+sdw['spread']+'px '+sdw['color']+' '+sdw['opacity'];
		}
		var input = $('#_customize-input-'+id);
		$(input).val(shadow);
		$(input).trigger("change");
		customizer.colselectLog(el);
	}


	//
	// custom range control
	this.setRange = function(el) {
		var val = $(el).val();
		var lbl = $(el).prev('.cs-range-value').data('lbl');
		var unit = $(el).prev('.cs-range-value').data('unit');

		val_edit = '<span style="background: #fff;" onclick="customizer.getRangeValue(this,'+val+')">'+val+'</span>';
		$(el).prev('.cs-range-value').html(lbl+' '+val_edit+unit);
		$(el).val(val);
	}
	// custom range control manual input
	this.getRangeValue = function(el,val) {
		var setting = $(el).closest('.customize-control')[0];
		var modname = setting.id.replace('customize-control-', '');
		var modlabel = $(el).closest('.cs-range-value').data('lbl').trim().replace(/:+$/, "");
		// console.log(setting.id);

		var newVal = prompt(customizer_wordings.enter_value.replace('%s', modlabel), val);
		if (newVal != null && !isNaN(newVal)) {			
			for (var i=0; i<shared.keys.length; i++) {					
				var k = shared.keys[i];
				var v = shared.mods[k];
				if (v['mod'] == modname) {
					// console.log(newVal);
					// console.log(v);
					if (typeof v['input_attrs'] == 'undefined') {
						if (modname.indexOf('font_size') > -1) {
							if (v['unit'] == 'px') v['input_attrs'] = { 'min': 5, 'max': 40, 'step': 1 };
							else if (v['unit'] == 'em') v['input_attrs'] = { 'min': 0.5, 'max': 10, 'step': 0.1 };
							else if (v['unit'] == '%') v['input_attrs'] = { 'min': 50, 'max': 1000, 'step': 10 };
						}
						else if (modname.indexOf('font_weight') > -1) v['input_attrs'] = { 'min': 100, 'max': 900, 'step': 100 };
						else if (modname.indexOf('line_height') > -1) v['input_attrs'] = { 'min': 50, 'max': 300, 'step': 10 };
						else if (modname.indexOf('letter_spacing') > -1)  v['input_attrs'] = { 'min': -5, 'max': 20, 'step': 0.1 };
						else if (modname.indexOf('word_spacing') > -1) v['input_attrs'] = { 'min': -5, 'max': 20, 'step': 0.1 };
						else if (modname.indexOf('border_width') > -1) v['input_attrs'] = { 'min': 0, 'max': 10, 'step': 1 };
						else if (modname.indexOf('border_radius') > -1)  v['input_attrs'] = { 'min': 0, 'max': 50, 'step': 1 };
						else  v['input_attrs'] = { 'min': 0, 'max': 100, 'step': 1 };
					}
					if (newVal > v['input_attrs']['max']) newVal = v['input_attrs']['max'];
					if (newVal < v['input_attrs']['min']) newVal = v['input_attrs']['min'];
					break;
				}
			}
			wp.customize.control( modname ).setting.set( newVal );
			customizer.setRange($(el).parent().next());
		}
	}

	//
	// group control
	this.toggleGroup = function(el) {
		var btn = $(el).find('.button');
		var state = $(btn).data('state');
		var txt = "<span>"+ $(btn).data('head') +"</span>";
		
		// inserted description
		var descr = '';
		if ($(btn).data('description') !== undefined && $(btn).data('description') !== '' )
			descr = "<span>"+ $(btn).data('description') +"</span>";
		//console.log("click on group " + $(btn).html());
		
		var newstate = 'on'
		var newtxt = txt + descr + '<span>▴</span>'
		if (state == 'on') {
			newstate = 'off';
			newtxt = txt + descr + '<span>▾</span>'
			$(btn).removeClass('active'); // wp-secondary button class
		} 
		else
			$(btn).addClass('active');
		
		$(btn).data('state', newstate);
		$(btn).html(newtxt);
		var children = $(btn).data('children');
		var current = el;
		for (var i = 0; i < children; i++) {
			current = $(current).next();
			if (!$(current).hasClass('customize-control-groupitem')) {
				$(current).addClass('customize-control-groupitem');
				if (i == children - 1)
					$(current).addClass('last');
				if (i == 0)
					$(current).addClass('first'); // highlight the first element
			} else {
				$(current).toggleClass('show');
			}
		}
	}

	//
	// fontfamily control
	this.fontfamilyChange = function(el) {
		// select fontfamily
		var id = $(el)[0].id;
		var val = $(el).val();
		// console.log(val);
		
		if (id.indexOf('ffsource') > -1) {
			// change source
			$(el).parent().next().css('display','none');
			$(el).parent().next().next().css('display','none');
			$(el).parent().next().next().next().css('display','none');
			if (val == "") {
				var pid = id.replace('input-ffsource', '#_customize-input');
				$(pid).val(val);
				$(pid).trigger("change");
			}
			else if (val == "websafe") {
				$(el).parent().next().css('display','block');
				$(el).parent().next().find('select').trigger("change");
			}
			else if (val == "google") {
				$(el).parent().next().next().css('display','block');
				$(el).parent().next().next().find('select').trigger("change");
			}
			else if (val == "custom") {
				$(el).parent().next().next().next().css('display','block');
				$(el).parent().next().next().next().find('select').trigger("change");
			}
		}
		else if (id.indexOf('ffwebsafe') > -1) {
			// change websafe font
			var pid = id.replace('input-ffwebsafe', '#_customize-input');
			$(pid).val(val);
			$(pid).trigger("change");
		}
		else if (id.indexOf('ffgoogle-weight') > -1) {
			var nid = id.split('-');
			nid.pop();
			nid = nid.join('-');
			// get google font
			var gid = nid.replace('input-ffgoogle-weight', '#input-ffgoogle');
			var gval = $(gid).val();
			var newval = gval;
			var weights = [];
			$(el).parent().parent().find('input').each(function() {
				if ($(this).prop('checked')) {
					var weight = $(this).attr('name');
					if (weight == "regular") weight = "400";
					if (weight == "italic") weight = "400italic";
					weights.push(weight);
				}
			});
			if (weights.length > 0)
				newval += ':'+weights.join(',');
			var wid = nid.replace('input-', '#warning-');
			if (weights.length > 2) $(wid).css('display', 'block');
			else $(wid).css('display', 'none');
			// set new font
			var pid = nid.replace('input-ffgoogle-weight', '#_customize-input');
			$(pid).val(newval);
			$(pid).trigger("change");
			
		}
		else if (id.indexOf('ffgoogle') > -1) {
			// change google font
			var pid = id.replace('input-ffgoogle', '#_customize-input');
			$(pid).val(val);
			$(pid).trigger("change");
			if ($(el).val() == "") $(el).next().css('display', 'none');
			else {
				$(el).next().css('display', 'block');
				customizer.fontfamilyWeights($(el).closest('.customize-control-fontfamily'));
			}
		}
		else if (id.indexOf('ffcustom') > -1) {
			// change custom font
			$(el).next().css('display','none');
			$(el).next().next().css('display','none');
			if (val == "load") {
				// show custom upload
				customizer.fontfamilySelectReset($(el).next().find('form'));
				$(el).next().css('display','block');
				val = "";
			}
			else if (val != "") {
				// show edit/delete
				customizer.fontfamilyEditSet($(el).next().next());
				$(el).next().next().css('display','block');
			}
			var pid = id.replace('input-ffcustom', '#_customize-input');
			$(pid).val(val);
			$(pid).trigger("change");
		}
		else if (id.indexOf('_customize-input') > -1) {	
			// change actual font and update all ffselect controls	
			customizer.ffselectSet(el);
		}
	}
	this.fontfamilyWeights = function(el) {

		var id = $(el).attr('id');
		var pid = id.replace('customize-control', '#_customize-input');
		var tmp = $(pid).val().split(':');
		var val = tmp[0];
		if (val != "" && gfonts[val]) {
			var font = gfonts[val];
			var weights = [];
			if (tmp.length > 1) weights = tmp[1].split(',');
			// console.log(font);
			var wid = id.replace('customize-control', '#description-ffgoogle-weights');
			$(wid).find('input').each(function() {
				// get individual weight
				var id = $(this).attr('id');
				var weight = id.split('-');
				weight = weight[weight.length-1];
				// console.log(weight);
				// adjust weight display
				$(this).parent().css('display', 'block');
				if (font.variants.includes(weight)) {
					$(this).prop("disabled", false);
				}
				else {
					$(this).prop("disabled", true);
					// $(this).parent().css('display', 'none');
				}
				if (weight == 'regular') weight = '400';
				if (weight == 'italic') weight = '400italic';
				// check weight
				$(this).prop('checked', false);
				if (weights.length > 0 && weights.includes(weight) ||
					weights.length == 0 && weight == '400')  {
					$(this).prop('checked', true); 
				}
			});
		}

	}
	// custom font
	this.fontfamilyChoose = function(el) {
		// console.log("Choose font archive");
		$(el).parent().find('input[name=font]').trigger("click");
	}
	this.fontfamilySelect = function(el) {
		// console.log("Select font archive");
		var fileToUpload = $(el).prop('files')[0];
		// console.log(fileToUpload.name);
		if (fileToUpload.type == "application/zip" ||
			fileToUpload.type == "application/x-zip-compressed") {
			customizer.fontfamilySelectSet($(el).parent(), fileToUpload.name);
		}
		else {
			customizer.fontfamilySelectReset($(el).parent());
		}
	}

	/**
	 * Upload font family via JS ajax.
	 * @param {DOMelement} el Font family input that is changed
	 * @returns void
	 */
	this.fontfamilyUpload = function(el) {
		
		const form = $(el);
		const input = form.find('input[name=font]');
		const fileToUpload = input.prop('files')[0];

		if ( !fileToUpload ) {
			// console.log("Nothing selected...");
			customizer.fontfamilySelectReset(el);
			return;
		}
		else if ( customizer.xhr != undefined ) {
			alert(customizer_wordings.custom_font.busy);
			return;
		}
		
		const name_full   = form.find('input[name=name_full]').val();
		const uploadpath = form.find('input[name=uploadpath]').val();
		const url        = form.attr('action');
		const action     = form.find('input[name=ajax_action]').val();
		const nonce      = form.find('input[name=_wpnonce]').val();

		const formData = new FormData();
		formData.append('file', fileToUpload);
		formData.append('name_full', name_full);
		formData.append('uploadpath', uploadpath);
		formData.append('mode', 'upload');
		formData.append('action', action);
		formData.append('_wpnonce', nonce);

		customizer.xhr = new XMLHttpRequest();

		// on progress
		customizer.xhr.onprogress = (event) => {
			if ( event.lengthComputable ) {
				// console.log(event.total);
				var percentComplete = event.loaded / event.total;
				percentComplete = parseInt(percentComplete * 100);
				// console.log(percentComplete);
				customizer.fontfamilySelectSet(el, fileToUpload.name+" ... "+percentComplete+"%", 'orange', percentComplete+"%");
				if (percentComplete === 100) {
					// console.log("Upload sucessful!");
					customizer.fontfamilySelectSet(el, fileToUpload.name+" ... "+percentComplete+"%", 'green', percentComplete+"%");
				}
			}
		}

		// on successfull request
		customizer.xhr.onload = (event) => {
			if (customizer.xhr.status >= 200 && customizer.xhr.status < 300 && customizer.xhr.responseText.indexOf('success::') > -1) {
				
				console.info( customizer.xhr.responseText );

				customizer.fontfamilySelectReset(el, customizer_wordings.custom_font.success_install.replace('%s', name_full), 'green', '100%');
				
				// add font to selection and enqueue
				$('.customize-control-fontfamily').each( function() {
					var id = $(this)[0].id;
					var pid = id.replace('customize-control', '#input-ffcustom');
					$('option[value=load]', pid).before($('<option>', {
						value: name_full,
						text: name_full
					}));
					var pid = id.replace('customize-control', '#_customize-input');
					$(pid).append($('<option>', {
						value: name_full,
						text: name_full
					}));
				} );

				const select = form.closest('.customize-control-ff-select').children('select').first();
				select.val(name_full);
				select.trigger('change');
				wp.customize.previewer.refresh();
			}
			else {
				console.error( customizer.xhr.responseText );
				let response = customizer.xhr.responseText;
				if ( response.indexOf('err::') > -1 ) {
					var msg = response.split('::');
					response = customizer_wordings.custom_font[msg[1]] ? customizer_wordings.custom_font[msg[1]] : response;
					if (msg.length == 3) {
						response = response.replace('%s', msg[2]);
					}
				}
				customizer.fontfamilySelectReset(el, response, 'red', '100%');
			}
			customizer.xhr_stop();
		};

		// on error
		const onError = ( event ) => {
			console.error( event );
			customizer.fontfamilySelectReset(el, customizer_wordings.custom_font.failed, 'red');
			customizer.xhr_stop();
		}
		customizer.xhr.onabort = onError;
		customizer.xhr.onerror = onError;

		// send the request
		customizer.xhr.open( 'POST', url, true );
		customizer.xhr.send( formData );
	}

	this.fontfamilySelectReset = function(el, msg="", col="#555d66", progress="0%") {
		if (msg == "" ) msg = customizer_wordings.custom_font.nothing;
		$(el).find('input[name=font]').val('');
		$(el).find('input[name=name_full]').val('');
		customizer.fontfamilySelectSet(el, msg, col, progress);
	}

	this.fontfamilySelectSet = function(el, msg="", col="#555d66", progress="0%") {
		if (msg == "" ) msg = customizer_wordings.custom_font.nothing;
		$(el).find('.info-ffupload').html(msg);
		$(el).find('.info-ffupload').css('color', col);
		$(el).find('.progress-ffupload').css('background', col);
		$(el).find('.progress-ffupload').css("width", progress);
	}

	/**
	 * Edit font family via JS ajax.
	 * @param {DOMelement} el Font family input that is changed
	 * @returns void
	 */
	this.fontfamilyEdit = function(el) {

		// ajax request active?
		if ( customizer.xhr != undefined ) {
			alert(customizer_wordings.custom_font.busy);
			return;
		}
		
		const input    = $(el);
		const name_full = input.closest('.customize-control-ff-select').children('select').first().val();

		// insert the value
		const name_full_new = prompt(customizer_wordings.custom_font.enter_name, name_full);
		if ( !name_full_new || name_full_new.length == 0 ) return;
		
		const form       = input.closest('.customize-control-ff-select').find('form');
		const uploadpath = form.find('input[name=uploadpath]').val();
		const url        = form.attr('action');
		const action     = form.find('input[name=ajax_action]').val();
		const nonce      = form.find('input[name=_wpnonce]').val();

		const formData = new FormData();
		formData.append('name_full', name_full);
		formData.append('name_full_new', name_full_new);
		formData.append('uploadpath', uploadpath);
		formData.append('mode', 'mod');
		formData.append('action', action);
		formData.append('_wpnonce', nonce);

		customizer.xhr = new XMLHttpRequest();

		// on successfull request
		customizer.xhr.onload = (event) => {
			if (customizer.xhr.status >= 200 && customizer.xhr.status < 300 && customizer.xhr.responseText.indexOf('success::') > -1) {
				
				console.info( customizer.xhr.responseText );

				// rename font and refresh fontfamily controls
				$('.customize-control-fontfamily').each( function() {
					let _id = $(this)[0].id;
					let _pid = _id.replace('customize-control', '#input-ffcustom');
					let _val = $(_pid).val();
					if (_val == name_full) {
						$(_pid).val('');
					}
					_pid = _id.replace('customize-control', '#_customize-input');
					$('option[value="'+name_full+'"]', _pid).html(name_full_new);
					$('option[value="'+name_full+'"]', _pid).val(name_full_new);
					_pid = _id.replace('customize-control', '#input-ffcustom');
					$('option[value="'+name_full+'"]', _pid).html(name_full_new);
					$('option[value="'+name_full+'"]', _pid).val(name_full_new);
					if (_val == name_full) {
						$(_pid).val(name_full_new);
						$(_pid).trigger("change");
					}
				} );
				customizer.fontfamilyEditSet(input.parent(), customizer_wordings.custom_font.success_edit.replace('%s', name_full_new), 'green');
				customizer.ffselectSet(input.parent());
				// wp.customize.previewer.refresh();
			}
			else {
				console.error( customizer.xhr.responseText );
			}
			customizer.xhr_stop();
		};

		// on error
		const onError = ( event ) => {
			console.error( event );
			customizer.fontfamilyEditSet(input.parent(), customizer_wordings.custom_font.failed, 'red');
			customizer.xhr_stop();
		}
		customizer.xhr.onabort = onError;
		customizer.xhr.onerror = onError;

		// send the request
		customizer.xhr.open( 'POST', url, true );
		customizer.xhr.send( formData );
	}

	/**
	 * Delete a font family via JS ajax.
	 * @param {DOMelement} el Font family input that is changed
	 * @returns void
	 */
	this.fontfamilyDelete = function(el) {

		// ajax request active?
		if ( customizer.xhr != undefined ) {
			alert(customizer_wordings.custom_font.busy);
			return;
		}
		
		const input    = $(el);
		const name_full = input.closest('.customize-control-ff-select').children('select').first().val();

		// confirm the change
		const result = confirm(
			customizer_wordings.custom_font.confirm_delete.replace( '%s', name_full )
		);
		if ( !result || name_full.length == 0 ) return;
		
		const form       = input.closest('.customize-control-ff-select').find('form');
		const uploadpath = form.find('input[name=uploadpath]').val();
		const url        = form.attr('action');
		const action     = form.find('input[name=ajax_action]').val();
		const nonce      = form.find('input[name=_wpnonce]').val();

		const formData = new FormData();
		formData.append('name_full', name_full);
		formData.append('uploadpath', uploadpath);
		formData.append('mode', 'delete');
		formData.append('action', action);
		formData.append('_wpnonce', nonce);

		customizer.xhr = new XMLHttpRequest();

		// on successfull request
		customizer.xhr.onload = (event) => {
			if (customizer.xhr.status >= 200 && customizer.xhr.status < 300 && customizer.xhr.responseText.indexOf('success::') > -1) {
				
				console.info( customizer.xhr.responseText );

				// delete font and reset all fontfamily controls
				$('.customize-control-fontfamily').each( function() {
					let _id = $(this)[0].id;
					let _pid = _id.replace('customize-control', '#input-ffcustom');
					if ($(_pid).val() == name_full) {
						$(_pid).val("");
						$(_pid).trigger("change");
					}
					$('option[value="'+name_full+'"]', _pid).remove();
					_pid = _id.replace('customize-control', '#_customize-input');
					$('option[value="'+name_full+'"]', _pid).remove();
				} );
				customizer.fontfamilyEditSet(input.parent(), customizer_wordings.custom_font.success_delete.replace('%s', name_full), 'green');
				customizer.ffselectSet(input.parent());
				// wp.customize.previewer.refresh();
			}
			else {
				console.error( customizer.xhr.responseText );
			}
			customizer.xhr_stop();
		};

		// on error
		const onError = ( event ) => {
			console.error( event );
			customizer.fontfamilyEditSet(input.parent(), customizer_wordings.custom_font.failed, 'red');
			customizer.xhr_stop();
		}
		customizer.xhr.onabort = onError;
		customizer.xhr.onerror = onError;

		// send the request
		customizer.xhr.open( 'POST', url, true );
		customizer.xhr.send( formData );
	}

	this.fontfamilyEditSet = function(el, msg="", col="#555d66") {
		$(el).find('.info-ffedit').html(msg);
		$(el).find('.info-ffedit').css('color', col);
	}
	
	this.xhr;
	this.xhr_stop = function() {
		customizer.xhr.abort();
		customizer.xhr = undefined;
	}

	//
	// fontfamily select control
	this.ffselectSet = function(el) {
		// console.log($(el)[0].id);
		var elid = $(el)[0].id;
		// update all ffselect controls	
		$('.customize-control-ffselect').each( function() {
			var id = $(this)[0].id;
			var pid = id.replace('customize-control', '#_customize-input');
			$('option[value="fontFamily1"]', pid).html(customizer_wordings.font+' 1 - '+$('#_customize-input-fontFamily1').val());
			$('option[value="fontFamily2"]', pid).html(customizer_wordings.font+' 2 - '+$('#_customize-input-fontFamily2').val());
			$('option[value="fontFamily3"]', pid).html(customizer_wordings.font+' 3 - '+$('#_customize-input-fontFamily3').val());
		} );
	}
	this.ffselectChange = function(el) {
		// select defined fontfamily
		var id = $(el)[0].id;
		var val = $(el).val();
		// console.log(val);
		customizer.ffselectLog($(el).parent());
	}
	this.ffselectLog = function(el) {
		var elements = [ 'fontFamily1', 'fontFamily2', 'fontFamily3' ];
		customizer.selectLog(el, elements);
	}

	//
	// color select control
	this.colselectSetup = function(el) {
		// console.log($(el)[0].id);
		// var elid = $(el)[0].id;
		// update all ffselect controls	

		// get all colors
		var colors = {};
		for (var i=1; i<=6; i++) {
			for (var j=1; j<=3; j++) {
				var col = 'color'+i+j;
				colors[col] = {
					// 'label': shared.mods['--'+col]['label'], 
					// 'description': shared.mods['--'+col]['description'], 
					'title': customizer_wordings.colors[col],
					'color': $('#customize-control-'+col+' .wp-color-picker').val() 
				}
			}
		}
		// console.log(colors);
		$('.customize-control-colors').each( function() {
			// update all colors
			for (var i=1; i<=6; i++) {
				for (var j=1; j<=3; j++) {
					var col = 'color'+i+j;
					$(this).find('.'+col+' span').css('background-color', colors[col]['color']);
					$(this).find('.'+col+' span').attr('title', colors[col]['title']+" - "+colors[col]['color']);
				}
			}
		} );
	}
	this.colselectSet = function(el, trigger=true) {
		// console.log(el);
		var control = $(el).closest('.customize-control');
		//console.log(control);
		$(control).find('.col').removeClass('selected');
		$(el).addClass('selected');
		if (trigger) {
			$(control).find('.customize-control-colorselect').val($(el).data("value"));
			$(control).find('.customize-control-colorselect').trigger("change");
		}
	}
	
	this.colselectMore = function(el) {
		if ($(el).hasClass('more')) {
			$(el).parent().children().each( function() {
				$(this).css('display', 'inline-block');
				if ($(this).hasClass('more')) $(this).css('display', 'none');
				if ($(this).hasClass('less')) $(this).css('display', 'block');
			} );
		}
		else if ($(el).hasClass('less')) {
			$(el).parent().children().each( function() {
				$(this).css('display', 'none');
				if ($(this).hasClass('more')) $(this).css('display', 'block');
			} );
		}
	}

	this.colselectChange = function(el) {
		var id = $(el)[0].id;
		var val = $(el).val();
		// console.log(val);
		customizer.colselectLog($(el).parent());
	}

	this.colselectLog = function(el) {
		var elements = [ 'color11', 'color12', 'color13',
						'color21', 'color22', 'color23',
						'color31', 'color32', 'color33',
						'color41', 'color42', 'color43',
						'color51', 'color52', 'color53',
						'color61', 'color62', 'color63' ];
		customizer.selectLog(el, elements);
	}

	//
	// select logging
	this.selectLog = function(el, elements) {
		var id = $(el)[0].id.replace("customize-control-", "");
		var val = $(el).find('select').val();
		// console.log(id+": "+val);
		
		// remove id from all elements
		customizer.selectLogRemove(elements, id);
		// add id to current
		var data = $('#customize-control-'+val).data('usedby');
		if (!data) data = [];
		data.push(id);
		$('#customize-control-'+val).data('usedby', data);
		// update all elements
		customizer.selectLogUpdate(elements);
	}
	this.selectLogRemove = function(elements, id) {
		for (var i=0; i<elements.length; i++) {
			var data = $('#customize-control-'+elements[i]).data('usedby');
			if (!data) data = [];
			var index = data.indexOf(id);
			if (index !== -1) data.splice(index, 1);
			$('#customize-control-'+elements[i]).data('usedby', data);
		}
	}
	this.selectLogUpdate = function(elements) {
		for (var i=0; i<elements.length; i++) {
			var data = $('#customize-control-'+elements[i]).data('usedby');
			if (!data) data = [];
			var log = customizer_wordings.used_by.replace('%s', data.length);
			for (var j=0; j<data.length; j++)
				log += "- <span>"+data[j].replace('_color2', '')+"</span><br>";
			$('#customize-control-'+elements[i]+' > .customize-control-log').html(log);
		}
	}
	
	//
	// preset picker control
	
	// store all triggers in object
	this.presetTrigger = {};
	
	// gets called on init
	this.initPresetPicker = function () {
		
		// init
		$('.preset-picker').each(function() {
			var picker = $(this),
				select = $(this).children('.preset-select'),
				val = select.val(),
				options = $(this).children('.options'),
				selected = options.children('.option.selected').length ? options.children('.option.selected') : options.children('.option').first(),
				offset = selected.position().top;
			
			// set options offset
			options.css({ top: '-'+offset+'px' });
			
			// toggle info boxes
			if (val === 'custom') picker.siblings('.greyd_info_box.info').hide(); 
			else picker.siblings('.greyd_info_box.warning').hide(); 
			
			// init reset triggers
			if (val !== 'custom') customizer.presetSelectChanged(select, false);
		});
		
		// add events
		
		// open the picker
		$('.preset-picker .selected_option').on("click", function(e){
			e.stopPropagation();
			
			var picker = $(this).parent();
			var options = $(this).siblings('.options');
			var selected = options.children('.option.selected').length ? options.children('.option.selected') : options.children('.option').first();
			
			selected.addClass('hover'); // instant hover fix
			picker.addClass('open');
		});
		
		// option hover
		$('.preset-picker .options .option').hover(function(){
			$(this).parent().children('.hover').removeClass('hover');
		});
		
		// option clicked
		$('.preset-picker .options .option').on("click", function(){
			customizer.optionClicked($(this));
		});
		
		// clicked somewhere else
		$(document).on("click", function(){
			$('.preset-picker').removeClass('open');
		});
		
		// if preset-picker gets changed
		$('.preset-select').on("change", function(){
			customizer.presetSelectChanged($(this));
		});
	}
	
	// option is clicked
	this.optionClicked = function (option) {
		var picker = option.closest('.preset-picker');
		var select_div = picker.children('.selected_option');
		var select = select_div.siblings('select');
		var value = option.data('value');
		var offset = Math.min(option.position().top, 160); // max value to not extend out of the container
		
		// toggle class 'selected'
		option.siblings('.selected').removeClass('selected');
		option.addClass('selected');
		
		// display option as selected
		select_div.removeClass('custom');
		select_div.children().remove();
		option.clone().appendTo(select_div).removeClass('selected hover');
		option.parent().css({ top: '-'+offset+'px' });
		
		// change select
		select.val(value);
		select.trigger('change');
		
		// toggle info boxes
		// picker.siblings('.greyd_info_box.warning').hide();
		// picker.siblings('.greyd_info_box.info').show();
	}
	
	// on select change
	this.presetSelectChanged = function (select, change=true) {
		var id = select.attr('id');
		var val = select.val();
		var option = select.children('option[value="'+val+'"]');
		var mods = option.data('mods');

		// reset picker
		customizer.removeTrigger(id);

		// if mods are defined
		if (typeof mods !== "undefined") {
			$.each(mods, function(mod, value){
				// if (customizer.debug) console.log( "option: " +mod+ ", value: " +value );

				// vars
				var type = shared.getModField(mod, 'type');
				var atts = {'type': shared.getModField(mod, 'type')};
				var element = '#customize-control-'+mod;
				var input = customizer.findInput(element, atts);
				
				if (!type || typeof input === "undefined") {
					// console.log(mod);
					// console.log(type);
					// console.log(atts);
					// console.log(element);
				}
				else {
					// link all inputs to picker
					if (typeof value !== 'object') customizer.presetTrigger[id].push(input);
					
					// change input values and trigger the change-event
					if (change) {
						var current_val = input.val();
						var new_val = undefined;
						
						// values restrictions
						if (typeof value === 'object') {
							
							// min (numeric)
							if ($.isNumeric(value['min']) && current_val < value['min']) new_val = value['min'];
							
							// max (numeric)
							if ($.isNumeric(value['max']) && current_val > value['max']) new_val = value['max'];
							
							// either (set of possible values)
							if (typeof value['either'] === 'object') {
								$.map(value['either'], function(val, key) { return val; }); // returns ['val1', 'val2']
								var _default = value['default'].length ? value['default'] : value[0];
								if (!value['either'].includes(current_val)) new_val = _default;
							}
							
						}
						// normal values
						else {
							if (current_val !== value) new_val = value;
						}
						
						// if value needs to be changed
						if (new_val !== undefined) {
							input.val(new_val);
							input.trigger('change');
							if (type === 'colselect') {
								var col = $( element + ' .col[data-value="' + new_val + '"]' );
								customizer.colselectSet( col, false);
							}
							if (type === 'fontfamily') {
								var font = $('#input-ffsource-'+mod);
								font.val('google');
								font.trigger('change');
							}
						}
					}
					
					// add reset triggers
					if (typeof value !== 'object') {
						setTimeout(function() {
							// trigger reset-event on change
							input.one('change', function(){
								input.trigger('removeTrigger');
							});

							// add reset-event
							input.one('removeTrigger', function(){
								customizer.setPresetPickerToCustom(select, id);
							});
						}, 50);
					}
				}
			});
			// if (customizer.debug) console.log(customizer.presetTrigger);

		}
	}
	
	this.setPresetPickerToCustom = function (select, id) {
		if (typeof id === "undefined") id = select.attr('id');
		
		// change select to custom
		customizer.removeTrigger(id);
		select.val('custom');
		select.trigger('change');
		
		// toggle info box
		var picker = select.closest('.preset-picker');
		picker.siblings('.greyd_info_box.info').hide();
		picker.siblings('.greyd_info_box.warning').show();
		
		// modify selected div
		var select_div = picker.children('.selected_option');
		select_div.addClass('custom');
		select_div.find('.option .txt').text(select_div.data('custom'));
		
		// modify options
		var options = picker.children('.options');
		options.children('.selected').removeClass('selected');
		options.css({ top: 0 })
		
		if (customizer.debug) console.log("reset preset-select „"+id+"“ to custom.");
	}
	
	// reset all triggers for a picker by id
	this.removeTrigger = function (id) {
			
		// remove trigger from linked inputs
		if (typeof customizer.presetTrigger[id] !== "undefined" && customizer.presetTrigger[id].length > 0) {
			$.each(customizer.presetTrigger[id], function(i, input) {
				input.off('removeTrigger');
		   });
		}
		// reset linked inputs
		customizer.presetTrigger[id] = [];
		// if (customizer.debug) console.log("removed all triggers for preset-select„"+id+"“.");
	}

};

(function() { 
	// search for customizer theme preview
	var items = location.search.substr(1).split("&");
	var search = [];
	for (var index = 0; index < items.length; index++) {
		var tmp = items[index].split("=");
		search[tmp[0]] = decodeURIComponent(tmp[1]);
	}
	// console.log(search);
	if (typeof search.theme !== 'undefined' &&
		typeof search.return !== 'undefined') {
		// Overriding XMLHttpRequest to hook publish success event
		var oldXHR = window.XMLHttpRequest;
		var count = 0;
		function newXHR() {
			var realXHR = new oldXHR();
			realXHR.addEventListener("readystatechange", function(e) { 
				if (typeof e !== 'undefined' && e != null && e.target.response != "") {
					var msg = JSON.parse(e.target.response);
					if (msg.success && msg.data.changeset_status == 'publish') {
						// console.log("published preview!");
						count++;
						if (count == 2) {
							$(window).off( 'beforeunload.customize-confirm');
							window.location = search.return;
						}
					}
				}
			}, false);
			return realXHR;
		}
		window.XMLHttpRequest = newXHR;
	}
})();
