403Webshell
Server IP : 103.119.228.120  /  Your IP : 3.133.109.58
Web Server : Apache
System : Linux v8.techscape8.com 3.10.0-1160.119.1.el7.tuxcare.els2.x86_64 #1 SMP Mon Jul 15 12:09:18 UTC 2024 x86_64
User : nobody ( 99)
PHP Version : 5.6.40
Disable Function : shell_exec,symlink,system,exec,proc_get_status,proc_nice,proc_terminate,define_syslog_variables,syslog,openlog,closelog,escapeshellcmd,passthru,ocinum cols,ini_alter,leak,listen,chgrp,apache_note,apache_setenv,debugger_on,debugger_off,ftp_exec,dl,dll,myshellexec,proc_open,socket_bind,proc_close,escapeshellarg,parse_ini_filepopen,fpassthru,exec,passthru,escapeshellarg,escapeshellcmd,proc_close,proc_open,ini_alter,popen,show_source,proc_nice,proc_terminate,proc_get_status,proc_close,pfsockopen,leak,apache_child_terminate,posix_kill,posix_mkfifo,posix_setpgid,posix_setsid,posix_setuid,dl,symlink,shell_exec,system,dl,passthru,escapeshellarg,escapeshellcmd,myshellexec,c99_buff_prepare,c99_sess_put,fpassthru,getdisfunc,fx29exec,fx29exec2,is_windows,disp_freespace,fx29sh_getupdate,fx29_buff_prepare,fx29_sess_put,fx29shexit,fx29fsearch,fx29ftpbrutecheck,fx29sh_tools,fx29sh_about,milw0rm,imagez,sh_name,myshellexec,checkproxyhost,dosyayicek,c99_buff_prepare,c99_sess_put,c99getsource,c99sh_getupdate,c99fsearch,c99shexit,view_perms,posix_getpwuid,posix_getgrgid,posix_kill,parse_perms,parsesort,view_perms_color,set_encoder_input,ls_setcheckboxall,ls_reverse_all,rsg_read,rsg_glob,selfURL,dispsecinfo,unix2DosTime,addFile,system,get_users,view_size,DirFiles,DirFilesWide,DirPrintHTMLHeaders,GetFilesTotal,GetTitles,GetTimeTotal,GetMatchesCount,GetFileMatchesCount,GetResultFiles,fs_copy_dir,fs_copy_obj,fs_move_dir,fs_move_obj,fs_rmdir,SearchText,getmicrotime
MySQL : ON |  cURL : ON |  WGET : ON |  Perl : ON |  Python : ON |  Sudo : ON |  Pkexec : ON
Directory :  /var/softaculous/sitepad/editor/site-data/plugins/pagelayer-pro/js/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /var/softaculous/sitepad/editor/site-data/plugins/pagelayer-pro/js/pagelayer-editor.js
/*
PAGELAYER
http://pagelayer.com/
(c) Pagelayer Team
*/

pagelayer = {
	$: jQuery,
	$$ : function(select){
		return jQuery(select, window.parent.document);
	},
	gDocument : jQuery(window.parent.document).add(document),
	p : this,
	copy_selected: '',
	mouse: {x: -1, y: -1},
	history_action : true,
	global_render : true,
	history_lastTime : new Date(),
	props_ref : {},
	pro_txt : '',
	loaded : 0,
	post_status : '',
	el: {},// All elements data
}

var pagelayer_history_obj = {}, pagelayer_revision_obj = {};
var pagelayer_add_section_data = {};

// Console error manager
window.onerror = function (msg, url, lineNo, columnNo, error) {

	if (typeof pagelayer_doc_width === 'undefined') {	
		var test_giver = -1;
		
		jQuery.ajax({
			url: pagelayer_url+'/js/givejs.php?test=1',
			type: "GET",
			dataType: "text",
			success: function(data){
			
				if(data != 1){
					return;
				}
				
				test_giver = 1;
			},
			complete: function(data){
				jQuery.ajax({
					type: "POST",
					url: pagelayer_ajax_url+"&action=pagelayer_set_jscss_giver",
					data: { 
						pagelayer_nonce: pagelayer_ajax_nonce,
						set : test_giver
					},
					error: function(errorThrown){
						console.log("Error saving giver data");
						console.log(errorThrown);
					}
				});	
			}
		});
	}
	
	var string = msg.toLowerCase();
	var substring = "script error";
	
	if(pagelayer.loaded > 0){
		return;
	}
	
	if (string.indexOf(substring) > -1){
		return;
	}

	if(url.indexOf('pagelayer')=== -1){
		return;
	}

	var message = [
		"Message: " + msg,
		"\r\n<br>URL: " + url,
		"\r\n<br>Line: " + lineNo,
		"\r\n<br>Column: "+ columnNo,
		"\r\n<br>Error object: " + error
	].join('\n');
	//alert("Script Error: See browser console for details");

	pagelayer.$$('.pagelayer-errorBox-content').html(message);
	pagelayer.$$('.pagelayer-errorBox-close').on('click', function(){	
		pagelayer.$$('.pagelayer-errorBox').fadeOut();
	});
	pagelayer.$$('.pagelayer-errorBox').fadeIn();

	return false;
};

// Lets start
jQuery(document).ready(pagelayer_start);

// Function to load the codes
function pagelayer_start(){
	
	pagelayer.loading = 1;
	console.log('['+pagelayer_brand+'] Starting Pagelayer');
	
	// Prevent the click Insite editor
	pagelayer_prevent_click();
	
	// Set the title of the parent window
	try{ pagelayer.$$('head').append(pagelayer.$('title')[0].outerHTML); }catch(e){};
	
	pagelayer.blank_img = pagelayer_url+'/images/default-image.png';

	pagelayer_shortcodes['pl_inner_row'] = JSON.parse(JSON.stringify(pagelayer_shortcodes['pl_row']));
	pagelayer_shortcodes['pl_inner_row']['name'] = 'Inner Row';
	pagelayer_groups['grid'].push('pl_inner_row');

	// Removing post props options
	pagelayer_setting_post_props();
	
	// Make the Topbar
	pagelayer_bottombar();
	
	// Make the Leftbar
	pagelayer_leftbar();
	
	// Make widget list toolbar
	pagelayer_create_widget_tooltip();
	
	// Add widget section
	pagelayer_add_widget();
	
	// Setup the ELPD
	pagelayer_elpd_setup();
	
	// Dump the data we have
	pagelayer_element_dump_data();
	
	// Setup the properties of the elements
	pagelayer_element_setup();
	
	// An image to show for drag
	jQuery('body').append('<img src="'+pagelayer_url+'/images/drag-ghost.png" class="pagelayer-drag-show" />');
	
	// Setup the grid drag
	pagelayer_setup_drag();
	
	// Set left bar draggable
	pagelayer_make_leftbar_movable();
	
	// Set to desktop
	pagelayer_set_screen_mode('desktop');
	
	// Create list of fonts
	pagelayer_fonts = pagelayer_l('pl_fonts_list');
	
	// Set up right click
	pagelayer_left_click();
	pagelayer_right_click();
	
	// Setup pagelayer history handle
	pagelayer_history_obj['action_data'] = [];
	pagelayer_history_setup(true);
	
	// Make a quick access of the props
	pagelayer_make_props_ref();
	
	// Post props exported defaults need to be updated
	pagelayer_set_exported_defaults();
	
	// Do any actions here
	pagelayer_trigger_action('pagelayer_setup_history');
	
	// Editor Tooltips
	pagelayer_tooltip_setup();
	
	// Load Fonts	
	for(var x in pagelayer_loaded_icons){
		var item = pagelayer_loaded_icons[x];
		jQuery.when(
			pagelayer_get_stored_data(pagelayer_url+'/fonts/'+item+'.json', pagelayer_ver)
		).then(function(){
			pagelayer_icons[item] = JSON.parse(pagelayer_get_stored_data(pagelayer_url+'/fonts/'+item+'.json', pagelayer_ver));
		});
	};

	// Set row-option top zero(0) of the first row
	pagelayer_set_row_option_position();
	
	// Just the txt
	pagelayer.pro_txt = pagelayer_pro_txt;
	
	// Open post props on document load
	pagelayer.$$('.pagelayer-settings').click();
	
	// Open post props and Make elements editable to edit post props data 
	pagelayer_setup_props_editable();
  	
	// Make elements editable
	jQuery(pagelayer_editable+' [pagelayer-editable]').attr('contenteditable', 'true');
	
	// Use text widget for search widget
	pagelayer_search_widgets();
	
	// Hide the loader
	pagelayer_loader_hide();
	
}

// Post props attribute
function pagelayer_post_props_atts(prop, val, temp){
	
	val = val || null;
	temp = temp || false;
		
	var proEle = jQuery(pagelayer_editable+' .pagelayer-post_props.pagelayer-ele').first();
	
	if(!pagelayer_empty(temp)){
		if(val === null){
			return pagelayer_get_tmp_att(proEle, prop);
		}
		
		// Set the temp property as well
		pagelayer_set_tmp_atts(proEle, prop, val);
		return true;
	}
	
	if(val === null){
		return pagelayer_get_att(proEle, prop);
	}
	
	// Set the property as well
	pagelayer_set_atts(proEle, prop, val);
	return true;
}

// Open post props and Make elements editable to edit post props data
function pagelayer_setup_props_editable(){
	
	jQuery('[pagelayer-props-editable]').each(function(){
		var jEle = jQuery(this);
		
		// Skip element under the editable area 
		if (jEle.closest(pagelayer_editable).length > 0) {
			return;
		}
		
		var prop = jEle.attr('pagelayer-props-editable');
		
		// Make editable
		jEle.attr('contenteditable', 'true');
		
		// Reverse setup the event
		jEle.on('focus', function(){
			// Set the property as well
			var data = pagelayer_post_props_atts(prop);
			jEle.html(data);
		});
		
		// Reverse setup the event
		jEle.on('input', function(){
			
			var val = pagelayer_trim(jEle.html());
			
			// Set the property as well
			pagelayer_post_props_atts(prop, val);
			
			// Update the property
			var input = pagelayer.$$('[pagelayer-elp-name='+prop+']').find('input,textarea,.trumbowyg-editor');
			//console.log(input);
			
			if(input.length > 0){
				if(input.hasClass('trumbowyg-editor')){
					input.html(val);
				}else{
					input.val(val);
				}
			}
		
		});
		
	});

}

// Prevent the click Insite editor
function pagelayer_prevent_click(){
	jQuery(document).on('submit', function(event){
		var target = jQuery(event.target);
		if (target.closest(pagelayer_editable).length < 1) {
			event.preventDefault();
		}
	});
	
	jQuery(document).on('click', function(event){
		var target = jQuery(event.target);
		if (target.closest('a').length > 0 && target.closest(pagelayer_editable).length < 1) {
			event.preventDefault()
		}
	});
}

// Removing post props options from the editor
function pagelayer_setting_post_props(){
	
	if(pagelayer_empty(pagelayer_post_categories)){
		delete pagelayer_shortcodes.pl_post_props.postCategory;
	}
	
	if(pagelayer_empty(pagelayer_post_tags)){
		delete pagelayer_shortcodes.pl_post_props.postTags;
	}

	if(pagelayer_empty(pagelayer_shortcodes.pl_post_props.pageParent.post_parent.list)){
		delete pagelayer_shortcodes.pl_post_props.pageParent;
	}
	
	if(pagelayer_post.post_type != 'post'){
		delete pagelayer_shortcodes.pl_post_props.params.post_sticky;
	}
	
	if(pagelayer_empty(pagelayer_post_type_features['comments'])){
		delete pagelayer_shortcodes.pl_post_props.postDiscussion.comment_status;
	}
	
	if(pagelayer_empty(pagelayer_post_type_features['trackbacks'])){
		delete pagelayer_shortcodes.pl_post_props.postDiscussion.ping_status;
	}
	
	if(pagelayer_empty(pagelayer_shortcodes.pl_post_props.postDiscussion)){
		delete pagelayer_shortcodes.pl_post_props.postDiscussion;
	}
	
	if(pagelayer_empty(pagelayer_post_type_features['excerpt'])){
		delete pagelayer_shortcodes.pl_post_props.postExcerpt;
	}
	
	if(pagelayer_empty(pagelayer_post_type_features['thumbnail'])){
		delete pagelayer_shortcodes.pl_post_props.postFeaturedImage;
	}
	
	if(pagelayer_empty(pagelayer_post_type_features['author'])){
		delete pagelayer_shortcodes.pl_post_props.params.post_author;
	}
}

// Set the default values of all default exported codes
function pagelayer_set_exported_defaults(){
	
	// Set defaults for the exported variety
	if(pagelayer_empty(pagelayer_default_params)){
		return;
	}
	
	for(var tag in pagelayer_default_params){
		
		for(var x in pagelayer_default_params[tag]){
			
			if(x in pagelayer.props_ref[tag]){
				pagelayer.props_ref[tag][x]['default'] = pagelayer_default_params[tag][x];
			}
			
		}
		
	}

}

// Do pagelayer Dirty
function pagelayer_do_dirty(jEle){
	
	pagelayer_isDirty = true;
	
	if (!window.onbeforeunload) {
		window.onbeforeunload = function(){
			return true;
		};
	}
	
	pagelayer_trigger_action('pagelayer_do_dirty', [jEle]);
}

function pagelayer_do_undirty(){

	pagelayer_isDirty = false;
	
	if (window.onbeforeunload) {
		window.onbeforeunload = null;
	}
	
}

// Executes when pagelayer is fully loaded
function pagelayer_loader_hide(){
	var inner = pagelayer.$$('.pagelayer-percent');
	inner.attr('loaded', 1);
	var w = parseInt(inner.text());
	var t = setInterval(function() {
		w = w + 1;
		inner.html(w +'<sup>%</sup>');
		if (w >= 100){
			clearInterval(t);
			w = 0;
			var loaderWrapper = pagelayer.$$('#pagelayer-loader-wrapper');	
			loaderWrapper.addClass('pagelayer-loaded');
			loaderWrapper.animate({opacity:0}, function(){
				loaderWrapper.remove();
			});
		}
	}, 1);
	pagelayer.loaded = 1;
}

// Set row-option top zero(0) of the first row
function pagelayer_set_row_option_position(){
	try{
		if(jQuery(pagelayer_editable).offset().top < 20){
			jQuery(pagelayer_editable).addClass('pagelayer-row-option-zero');
		}
	}catch(e){
		console.log(pagelayer_editable+" not found and hence Pagelayer wont work on this page !");
	}
}

// The jQuery Object of the ELPD
var pagelayer_elpd;

// Store data values
function pagelayer_get_stored_data(url, version){
	var name = 'pagelayer_'+url;
	var data = {};
	var force = false;
	
	// Try to parse the data
	try{
		data = JSON.parse(localStorage.getItem(name));
		
		if(data['version'] !== version){
			force = true;
		}
		
	}catch(e){
		force = true;
	}
	
	// Force download
	if(force){
		return jQuery.ajax({
			url: url,
			type: 'GET',
			dataType: 'text',
			success:function(newData){
				var data = {};
				data['version'] = version;				
				data['val'] = newData;
				localStorage.setItem(name, JSON.stringify(data));
			}
		});
	}
	
	return data['val'];
	
}

function pagelayer_closest_corner(jEle){
	var corners = [];
	var w = jEle.outerWidth();
	var h = jEle.outerHeight();	
	var topleft = jEle.offset();
	
	// 0 - Top Left
	corners.push(topleft);
	
	// 1 - Top Right
	corners.push({top: topleft.top, left: topleft.left+w});
	
	// 2 - Bottom Right
	corners.push({top: topleft.top+h, left: topleft.left+w});
	
	// 3 - Bottom Left
	corners.push({top: topleft.top+h, left: topleft.left});
	
	//console.log(corners);
	
	// Calculate the closest to the mouse
	var distances = {};
	for(var c in corners){
		var dist = Math.hypot(pagelayer.mouse.x - corners[c].left, pagelayer.mouse.y - corners[c].top);
		distances[c] = dist;
	}	
	//console.log(distances);
	
	var corner = Object.keys(distances).sort(function(a,b){return distances[a]-distances[b]})[0];
	//console.log(corner);
	
	return corner;
	
};

// Make left bar draggable
function pagelayer_make_leftbar_movable(){
	var pl_iframe = pagelayer.$$('.pagelayer-iframe'),
		pl_leftbar = pagelayer.$$('.pagelayer-leftbar-table');

	// On mouse down in pagelayer-topbar-holder
	pagelayer.$$('.pagelayer-topbar-mover').on('mousedown', function(e){
		e = e || window.event;
		e.preventDefault();
		
		// Get leftbar position
		var orig_eleX = pl_leftbar.offset().left;
		var orig_eleY = pl_leftbar.offset().top;
		
		// Get the mouse cursor position at startup:
		var posX = e.clientX;
		var posY = e.clientY;
		
		// The variable needs to be empty.
		var newMethod = '',
		change = true;
		
		var leftbar_mousemove = function(e){
			e = e || window.event;
			
			if(change){
				// Add class to leftbar
				pl_leftbar.addClass('pagelayer-leftbar-moving');
				
				// Add left-right overlay
				pl_iframe.before('<div class="pagelayer-leftbar-move pagelayer-moveto-left"></div>');
				pl_iframe.after('<div class="pagelayer-leftbar-move pagelayer-moveto-right"></div>');
				pagelayer.$$('body').addClass('pagelayer-overflow-hidden');
				change = false;
			}
					
			// calculate the new cursor position and set the element left-top position
			var top = orig_eleY + (e.clientY - posY);
			var left = orig_eleX + (e.clientX - posX);

			// set the element's new position:
			pl_leftbar.css({'top': top +'px','left': left +'px'});
			pagelayer.$$('.pagelayer-leftbar-toggle').hide();
				
			// Make a copy of new method
			var _newMethod = newMethod;
			newMethod = '';
			
			// Get near by corner
			var offleft = pl_iframe.offset().left;
			
			if(offleft + 100 > e.clientX){
				newMethod =  'before';
			}else if(offleft+pl_iframe.outerWidth()- 100 < e.clientX){
				newMethod =  'after';
			}
			
			if(_newMethod != newMethod){
				pagelayer.$$('.pagelayer-leftbar-move').css({'width' :'', 'opacity': '0.33'});
				
				if(newMethod == 'after'){
					pagelayer.$$('.pagelayer-moveto-right').animate({'width' :'60px', 'opacity': '0.66'}, 200);
					pl_leftbar.addClass('pagelayer-rightbar');
				}else if(newMethod == 'before'){
					pagelayer.$$('.pagelayer-moveto-left').animate({'width' : '60px', 'opacity': '0.66'}, 200);
					pl_leftbar.removeClass('pagelayer-rightbar');
				}
			}
		
		};
		
		var leftbar_mouseup = function(e){
			
			// Remove events
			pagelayer.gDocument.off('mousemove', leftbar_mousemove);
			pagelayer.gDocument.off('mouseup', leftbar_mouseup);
			
			// Remove class to leftbar			
			pagelayer.$$('.pagelayer-leftbar-move').remove();
			
			var windowHeight = jQuery(window).height();
			
			if(pl_leftbar.offset().top < 0){
				pl_leftbar.css({'top': '10px'});
			}else if( (windowHeight - e.clientY) < 10){
				pl_leftbar.css({'top': ''+windowHeight - 40+'px'});
			}
			
			if( !pagelayer_empty(newMethod)){
				pl_leftbar.removeClass('pagelayer-leftbar-moving');
				pl_leftbar.removeAttr('style');
				pagelayer.$$('.pagelayer-leftbar-toggle').show();
				pagelayer.$$('body').removeClass('pagelayer-overflow-hidden');
				pl_iframe[newMethod](pl_leftbar);
			}
			
			// make change true
			change = true;
		};
		
		pagelayer.gDocument.on('mouseup', leftbar_mouseup);
		pagelayer.gDocument.on('mousemove', leftbar_mousemove);

	});
	
}

// Make rows and cols draggable
function pagelayer_setup_drag(){
	
	// The object to show as drag
	var shower = jQuery('.pagelayer-drag-show');
	
	// Delete any prospect
	var clear_prospect = function(){
		jQuery('.pagelayer-drag-prospect').remove();
		
		// Shows the wrap as active
		jQuery('.pagelayer-drag-ele-hover').removeClass('pagelayer-drag-ele-hover');
	}
	
	// Reset the complete drag stuff
	var reset_dragging = function(){
		pagelayer.dragging = false;
		pagelayer.drag_is_new = false;
		pagelayer.drag_mouse = {x: 0, y: 0};
		reset_on_drag();
	}
	
	// Reset the element on you were last
	var reset_on_drag = function(){
		pagelayer.drag_closest = false;
		pagelayer.drag_closest_corner = null;
	}
	
	// Scroll by
	var scrollPx = 7;
	var scrollDist = 30;
	
	// If we are too close too the window edge, then scroll
	var handle_scroll = function(e){
		
		var windowHeight = jQuery(window).height();
		var windowWidth = jQuery(window).width();
	
		// Are we to close to the top or bottom
		if(e.clientY < scrollDist){
			window.scrollBy(0, -scrollPx);
		}else if((windowHeight - e.clientY) < scrollDist){
			window.scrollBy(0, scrollPx);
		}		
		
		// Are we to close to the top or bottom
		if(e.clientX < scrollDist){
			window.scrollBy(-scrollPx, 0);
		}else if((windowWidth - e.clientX) < scrollDist){
			window.scrollBy(scrollPx, 0);
		}
		
	}
	
	// SET the values
	reset_dragging();
	
	var ondragover = function(e) {
		//console.log(e);
		
		pagelayer.mouse.x = parseInt(e.pageX);
		pagelayer.mouse.y = parseInt(e.pageY);
		//console.log(pagelayer.mouse);
		
		// Are we dragging ?
		if(pagelayer.dragging){
			
			//console.log(e);
			
			e.preventDefault();			
			//e.stopPropagation();
			
			// The wrap of the element being dragged
			var wrap = pagelayer.dragging;
			
			// New addition
			var is_new = pagelayer.drag_is_new;
			var ele;
			var tag = pagelayer_tag(wrap);
			var id = pagelayer_id(wrap);
			
			// If existing element then add we are dragging
			if(!is_new){
				
				// Start Dragging
				if(!wrap.hasClass('pagelayer-is-dragging')){
					wrap.addClass('pagelayer-is-dragging');
				}
				
				//shower.hide();
			
				ele = document.elementFromPoint(e.clientX, e.clientY);
				//console.log(ele);
				
				// Drag the show object
				//shower.show();
				//var offset = {top: (e.pageY-10)+'px', left: (e.pageX-10)+'px'}
				//shower.css(offset);
				
			}else{
				ele = document.elementFromPoint(e.clientX, e.clientY);
			}
			//console.log(e);
			
			// Have we moved more than 5px;
			var dist = Math.hypot(pagelayer.mouse.x - pagelayer.drag_mouse.x, pagelayer.mouse.y - pagelayer.drag_mouse.y);
			//console.log(dist);
			/*if(dist && dist < 5){
				return false;
			}*/
			
			// Handle the scroll
			handle_scroll(e);
			
			// Find the closest wrap
			var onWrap;
			
			// If we are a column, we can be over another column or row
			if(tag == 'pl_col'){
				
				// Prevent column in inner-row and it's columns, if the draged column have inner-rows
				if(wrap.find('.pagelayer-wrap-inner-row').length > 0){
					onWrap = jQuery(ele).closest('.pagelayer-wrap-col,.pagelayer-wrap-row');
					
					var innerRow = onWrap.closest(pagelayer_editable +' .pagelayer-wrap-inner-row');
					if( onWrap.length < 1 || innerRow.length > 0){
						onWrap = jQuery(innerRow).closest('.pagelayer-wrap-col,.pagelayer-wrap-row');
					}
					
				}else{
					onWrap = jQuery(ele).closest('.pagelayer-wrap-col,.pagelayer-wrap-row,.pagelayer-wrap-inner-row');
				}
				//console.log(pagelayer_id(onWrap));
				
			// If we are a row, we can be over another row or a column
			}else if(tag == 'pl_row'){
				onWrap = jQuery(ele).closest('.pagelayer-wrap-row');
				//console.log(pagelayer_id(onWrap));
			
			// For inner row we restrict to 1 level only
			}else if(tag == 'pl_inner_row'){
				
				var ele_wrap = jQuery(ele).parents('.pagelayer-wrap-col');
				if(
					(ele_wrap.length == 1 && !jQuery(ele).hasClass('pagelayer-wrap-col')) || 
					(ele_wrap.length == 0 && jQuery(ele).hasClass('pagelayer-wrap-col'))
				){
					onWrap = jQuery(ele).closest('.pagelayer-wrap-ele,.pagelayer-wrap-col,.pagelayer-wrap-inner-row');
				}else{
					onWrap = jQuery(ele).closest('.pagelayer-wrap-inner-row');
				}
			// For every other element, we can be over a col or ele
			}else{
				onWrap = jQuery(ele).closest('.pagelayer-wrap-ele,.pagelayer-wrap-col,.pagelayer-wrap-inner-row');
				
				// If we are inside the same widget tag
				// We are allowing for now, hence the following is commented
				/*var sameTag = onWrap.closest(pagelayer_editable +' [pagelayer-tag="'+tag+'"]');
				if(sameTag.length > 0){
					onWrap = sameTag.closest('.pagelayer-wrap-ele');
				}*/
				
				// Is prevent to go inside any widget?
				if('prevent_inside' in pagelayer_shortcodes[tag] && !pagelayer_empty(pagelayer_shortcodes[tag]['prevent_inside'])){
										
					var preTags = pagelayer_shortcodes[tag]['prevent_inside'];
					var prevent_inside = false;
					var preEle = onWrap;
					
					if(typeof preTags === 'string'){
						preTags = [preTags];
					}
					
					for(var toFind in preTags){
						preEle = onWrap.closest(pagelayer_editable +' [pagelayer-tag="'+preTags[toFind]+'"]');
						if (preEle.length > 0) {
							prevent_inside = true;
							break;
						}
					}
					
					// If we find
					if(prevent_inside){
						onWrap = preEle.closest('.pagelayer-wrap-ele');
					}
				}
					
				var widGroup = onWrap.closest('.pagelayer-ele-widget-group');
				
				// If we are inside the group widget
				if(widGroup.length > 0 && widGroup.closest(pagelayer_editable).length > 0){
					
					var wGroupTag = pagelayer_tag(widGroup);
					var use_inside = false;

					// If defined use inside only
					if('use_inside' in pagelayer_shortcodes[tag] && !pagelayer_empty(pagelayer_shortcodes[tag]['use_inside'])){
											
						var inTags = pagelayer_shortcodes[tag]['use_inside'];
						
						if(typeof inTags === 'string'){
							inTags = [inTags];
						}
						
						for(var toFind in inTags){
							if (wGroupTag == inTags[toFind]) {
								use_inside = true;
							}
						}
					}
					
					// If we find nothing
					if(!use_inside){
						onWrap = widGroup.parent('.pagelayer-wrap-ele');
					}
				}
			}
			//console.log(onWrap);
			
			// If we find nothing
			if(pagelayer_empty(onWrap) || onWrap.length < 1){
				clear_prospect();// Clear existing prospects
				reset_on_drag();// Also reset the last on item
				return false;
			}
			
			/*// If the columns more than 12 inside the row then return - As of now not enabled the below code
			if(tag == 'pl_col'){
				var _onTag = pagelayer_tag(onWrap);
				var colEles;
				
				// Is on col
				if(_onTag == 'pl_col'){
					colEles = onWrap.closest('.pagelayer-row-holder').children('.pagelayer-ele-wrap');
				}else{
					colEles = onWrap.find('.pagelayer-row-holder').first().children('.pagelayer-ele-wrap');
				}
				
				// If the columns more than 12
				if(colEles.length >= 12){
					return false;
				}
			}*/
					
			// Get the ID
			var onId = pagelayer_id(onWrap);
			var onEle = pagelayer_ele_by_id(onId);
			
			// Do we have a parent ?
			var have_parent = function(Ele){
				var pOnId = pagelayer_get_parent(Ele);

				if(pagelayer_empty(pOnId) || tag == 'pl_col'){
					return;
				}
				
				onId = pOnId;
				onEle = pagelayer_ele_by_id(pOnId);
				onWrap = pagelayer_wrap_by_id(pOnId);
				have_parent(onEle);
				
			}
			
			// Do we have a parent ?
			have_parent(onEle);
			
			var changed = false;
			
			// Was it the same ID like the one we were on before
			if(pagelayer.drag_closest != onId){
				pagelayer.drag_closest = onId;
				changed = true;
			}
			//console.log(onId+'  '+pagelayer.drag_closest)
			
			var req_corners = {0: 'top', 1: 'top', 2: 'bottom', 3: 'bottom'};
			
			// For columns we redefine the top and bottom
			if(tag == 'pl_col'){
				req_corners[1] = 'bottom';
				req_corners[3] = 'top';
			}
			
			// Determine the previous and next
			var next = wrap.next('.pagelayer-ele-wrap');
			var prev = wrap.prev('.pagelayer-ele-wrap');
			
			if(next.length == 1 && pagelayer_id(next) == onId){
				req_corners = {0: 'bottom', 1: 'bottom', 2: 'bottom', 3: 'bottom'};
			}
			
			if(prev.length == 1 && pagelayer_id(prev) == onId){
				req_corners = {0: 'top', 1: 'top', 2: 'top', 3: 'top'};
			}
			
			// Which corner are we closest to ?
			var corner_num = pagelayer_closest_corner(onWrap);
			var corner = req_corners[corner_num];
			
			//console.log(corner+' != '+pagelayer.drag_closest_corner)
			if(corner != pagelayer.drag_closest_corner){
				pagelayer.drag_closest_corner = corner;
				changed = true;
			}
			
			//console.log(changed);
			
			// If we are on our self then clear return false and we are on hide active widget
			if(onId == id || onWrap.hasClass('pagelayer-hide-active')){
				clear_prospect();// Clear existing prospects
				reset_on_drag();// Also reset the last on item
				return false;
			}
			
			// Then lets start showing
			if(changed){
				
				// Record the mouse points
				pagelayer.drag_mouse.x = parseInt(e.pageX);
				pagelayer.drag_mouse.y = parseInt(e.pageY);
				
				// Clear any existing prospect
				clear_prospect();
				
				// Add new prospect
				var prospect = '<div class="pagelayer-drag-prospect" pagelayer-corner="'+corner+'"></div>';
				
				if(corner == 'bottom'){
					onWrap.append(prospect);
				}else if(corner == 'top'){
					onWrap.prepend(prospect);
				}
				
				prospect = jQuery('.pagelayer-drag-prospect')
				var animate_props = {height: '5px'};
				
				// For column add a special class
				if(tag == 'pl_col'){
					prospect.addClass('pagelayer-drag-prospect-col');
					animate_props['width'] = '5px';
					
					// Adjust the left and right
					var css = {};
					css[(corner == 'bottom' ? 'right' : 'left')] = '0px';
					prospect.css(css);
				}
				
				// Animate the prospect
				prospect.animate(animate_props, 200);
				
				// Highlight the wrap via overlay
				onWrap.children('.pagelayer-ele-overlay').addClass('pagelayer-drag-ele-hover');
				
			}
			
		}
	}
	
	// When mouse is pressed down
	var ondragstart = function(e){
		
		//console.log(e);
		
		// Target
		var tEle = jQuery(e.target);
		var wrap = tEle.closest('.pagelayer-ele-wrap');
		//console.log(jEle[0]);
		
		// Is it an existing element ?		
		if(wrap.length < 1){
			return false;
		}
		
		// Do we have a parent ?
		var id = pagelayer_id(wrap);
		var jEle = pagelayer_ele_by_id(id);
		var pId = pagelayer_get_parent(jEle);
		
		if(pId){
			wrap = pagelayer_wrap_by_id(pId);
		}
		
		//e.preventDefault();
		
		var tag = pagelayer_tag(wrap);
		
		e.originalEvent.dataTransfer.setData('Text', 1);
		var img = document.createElement('img');
		img.src = shower.attr('src');
		e.originalEvent.dataTransfer.setDragImage(img, 32, 32);
		
		pagelayer.dragging = wrap;
		
	}
	
	// When mouse is pressed down
	var ondrop = function(e){
		
		//console.log(e);
		
		// Stop dragging ?
		if(pagelayer.dragging){
			
			e.preventDefault();
			
			var wrap = pagelayer.dragging;
			var tag = pagelayer_tag(wrap);
			var gId = wrap.attr('pagelayer-global-id');
			var fromEl = wrap.parent();
			var id;
			
			// Global ID is there for sure ?
			if(pagelayer_empty(gId) || pagelayer_empty(pagelayer_global_widgets[gId])){
				gId = 0;
			}
			
			wrap.removeClass('pagelayer-is-dragging');
			
			// Find any prospect
			var prospect = jQuery('.pagelayer-drag-prospect');
			//console.log(prospect[0]);
				
			// It should be exactly 1
			if(prospect.length == 1){
				
				var onWrap = prospect.parent();
				var onId = pagelayer_id(onWrap);
				var onTag = pagelayer_tag(onWrap);
				var dropped;	
				var corner = prospect.attr('pagelayer-corner');
				var method = (corner == 'top') ? 'before' : 'after';
				var before_loc; // Location before the drop
				
				// Create the element if it needs to be created
				if(pagelayer.drag_is_new){
					dropped = jQuery('<div pagelayer-tag="'+tag+'"></div>');
					
					// Is there a global ID
					if(!pagelayer_empty(gId)){
						dropped.attr('pagelayer-global-id', gId);
					}
				
				// Move the object
				}else{
					
					// Get near by element before move
					before_loc = pagelayer_near_by_ele(pagelayer_id(wrap), tag);
					
					dropped = wrap;
					dropped.detach();
				}
				
				// If I am a column or row, then I go only before or after my same type !
				if((onTag == 'pl_col' || onTag == 'pl_row') && onTag == tag){
				
				// If I am a column and I am on a row 
				// OR I am a normal element and I am on column
				}else if((tag == 'pl_col' && (onTag == 'pl_row' || onTag == 'pl_inner_row')) || onTag == 'pl_col'){
					// We need to find the holder and add the prospect there
					var holder = pagelayer_shortcodes[onTag]['holder'];
					onWrap = onWrap.children('.pagelayer-ele').children(holder);
					method = (corner == 'top') ? 'prepend' : 'append';
				}
				
				// Attach or shift the element
				onWrap[method](dropped);
				//console.log(dropped);
				
				// Trigger the onadd
				if(pagelayer.drag_is_new){
					id = pagelayer_onadd(dropped);
					
					// Create Column
					if((tag == 'pl_row' || tag == 'pl_inner_row') && pagelayer_empty( dropped.attr('pagelayer-global-id') )){
						var col = jQuery('<div pagelayer-tag="pl_col"></div>');
						jQuery('[pagelayer-id="'+id+'"]').find('.pagelayer-row-holder').append(col);
						var col_id = pagelayer_onadd(col, false);
					}
				
				// Existing elements
				}else{
					id = pagelayer_id(wrap);
					
					// Save in action history
					pagelayer_history_action_push({
						'title' : pagelayer_shortcodes[tag]['name'],
						'action' : 'Moved',
						'pl_id' : id,
						'before_loc' : before_loc,
						'after_loc' : {'method' : method, 'cEle' : onWrap}
					});
					
					pagelayer_do_dirty(pagelayer_ele_by_id(id));
				}
				
				// Defining the variables as needed
				var jEle = pagelayer_ele_by_id(id);
				wrap = pagelayer_wrap_by_id(id);
				var toEl = wrap.parent();
				
				// Column number handle
				if(tag == 'pl_col'){
					
					var row_holder = jEle.parent().closest('.pagelayer-row-holder');
					
					// Renumber the col where you are going
					pagelayer_renumber_col(row_holder);
					
					// Renumber the old columns as well
					if(!pagelayer.drag_is_new){
						var from_row = fromEl.closest('.pagelayer-row-holder');
						pagelayer_renumber_col(from_row);
					}
				}
				
				// Handle the empty col
				if(tag != 'pl_col'){
					
					pagelayer_empty_col(toEl.closest('.pagelayer-col-holder'));
					
					if(!pagelayer.drag_is_new){
						pagelayer_empty_col(fromEl.closest('.pagelayer-col-holder'));
					}
					
				}
				
			}
			
			// Clear prospect
			clear_prospect();
		}
		
		reset_dragging();
		
	}
	
	// Add the events for inner content - as we are using the drag API	
	jQuery(document).on('dragstart', ondragstart);
	jQuery(document).on('dragover', ondragover);
	jQuery(document).on('drop', ondrop);
	
	// For addition of new elements
	pagelayer.$$('.pagelayer-leftbar').on('dragstart', function(e){
		//console.log(e);
		
		var tEle = jQuery(e.target);
		var jEle = tEle.closest('.pagelayer-shortcode-drag');
		var global_id = jEle.attr('pagelayer-global-id');
		
		// Is it an existing element ?
		if(jEle.length < 1){
			return false;
		}
		
		e.originalEvent.dataTransfer.setData('tag', pagelayer_tag(jEle));
		
		if(!pagelayer_empty(global_id)){
			e.originalEvent.dataTransfer.setData( 'global_id', global_id );
		}
		
		pagelayer.dragging = jEle;
		pagelayer.drag_is_new = true;
		
	});
	
	// Handle editable content by removing drag
	var onmousedown = function(e){
		
		var tEle = jQuery(e.originalEvent.explicitOriginalTarget);
		
		if(tEle.closest('[pagelayer-editable]').length > 0){
			//console.log('Is Editable MouseDown');			
			tEle.parents('[draggable]').attr('draggable', 'false');
		}
	
	}
	
	// Handle editable content by adding drag that was removed
	var onmouseup = function(e){
		jQuery(document).find('[draggable=false]').attr('draggable', 'true');
	}
	
	// Handle editable contents by temprarily removing drag
	jQuery(document).on('mousedown', onmousedown);
	jQuery(document).on('mouseup', onmouseup);

};

// Handle empty col
// selector should be col holder
function pagelayer_empty_col(selector){
	
	// Loop through
	jQuery(selector).each(function(){
		
		var jEle = jQuery(this);// jEle is the COL HOLDER
		
		// Are we a col ?
		if(!jEle.hasClass('pagelayer-col-holder')){
			return;
		}
		
		// Column is becoming blank, so show add ele
		if(jEle.children().length < 1){
			//from.addClass('pagelayer-empty-col');
			jEle.append('<div class="pagelayer-add-ele pagelayer-ele-wrap"><i class="fas fa-plus"></i><br /><span>Empty column please Drag Widgets</span></div>');			
			//var h = jEle.parent().parent().children('.pagelayer-ele-overlay').height();
			//jEle.children('.pagelayer-add-ele').height(h);
			
		// Any add ele sign with non-empty columns here ?
		}else if(jEle.children('.pagelayer-add-ele').length > 0 && jEle.children().length > 1){
			jEle.children('.pagelayer-add-ele').remove();
		}
		
		jEle.find('>.pagelayer-add-ele .fas').unbind('click');
		jEle.find('>.pagelayer-add-ele .fas').on('click', function(event){
			event.stopPropagation();
			pagelayer.$$('.pagelayer-elpd-close').click();
			
			pagelayer_show_widget_list(jQuery(this));
		});
		
	});
	
};

// Reset the column widths
// The selector should be a ROW HOLDER
function pagelayer_renumber_col(selector){
	
	var pEle = jQuery(selector);
	var children = pEle.children('.pagelayer-ele-wrap');
	var cols = Math.floor(12 / (children.length));
	var obj = {col: cols};
	
	// Find out the number of cols of other cols
	children.each(function(){
		
		// This is the wrapper
		var jEle = jQuery(this);
		
		// The real element
		var Ele = jEle.find('>.pagelayer-ele');
		
		for(var x=1; x<=12; x++){
			if(jEle.hasClass('pagelayer-col-'+x)){
				jEle.removeClass('pagelayer-col-'+x);
				Ele.removeClass('pagelayer-col-'+x);
				break;
			}
		}
		jEle.addClass('pagelayer-col-'+cols);
		jEle.css({'width': ''});
			
		// Set the att
		pagelayer_set_atts(Ele, obj);
		pagelayer_set_atts(Ele, 'col_width','');
		pagelayer_sc_render(Ele)
	});
}

// Make column resizable handler
function pagelayer_col_make_resizable(wrap){
		
	// Resize handler element
	var rHandler = jQuery('<div class="pagelayer-resize-handler"><div class="pagelayer-resize-icon"></div></div>');
		
	var pResize = wrap.children('.pagelayer-ele-overlay').find('.pagelayer-resize-handler');
	
	if(pResize.length > 0){
		return;
	}
	
	// Append it
	wrap.children('.pagelayer-ele-overlay').append(rHandler);
	
	// Resize start
	rHandler.on('mousedown', function(e) {
		e.preventDefault();
		
		var next_ele = wrap.next();
		var rHolder_width = wrap.closest('.pagelayer-row-holder').width();
		var new_width, nEle_new_width;
		
		// Original width
		var original_width = parseFloat(window.getComputedStyle(wrap[0]).getPropertyValue('width'));
		var next_ele_width = parseFloat(window.getComputedStyle(next_ele[0]).getPropertyValue('width'));
		var original_mouse_x = e.pageX;
		
		var both_width = parseInt(original_width + next_ele_width);
		
		// Add the element width and next element width
		both_width = ((both_width / rHolder_width) *100);
		
		if(both_width > 100){
			return false;
		}
		
		jQuery('body').css({'cursor': 'ew-resize'});
		rHandler.css({'display': 'block'});
		
		var mousemoved = false;
		
		var r_mousemove = function(e){
			mousemoved = true;
			
			var width = original_width + (e.pageX - original_mouse_x);
			
			// Covert width in percentage
			new_width = (width / rHolder_width *100).toFixed(2);
			
			if(both_width > new_width && new_width > 0){
				nEle_new_width = (both_width - new_width).toFixed(2);
				wrap.css({'width': new_width+'%'});
				next_ele.css({'width': nEle_new_width+'%'});
				
				rHandler.attr({'pre-width': new_width+'%', 'next-width': nEle_new_width+'%'}); 
			}
			
		};
		
		var r_mouseup = function(e){
			
			jQuery(document).off('mousemove', r_mousemove);
			jQuery(document).off('mouseup', r_mouseup);
			jQuery('body').css({'cursor': ''});
			rHandler.removeAttr('style pre-width next-width');
			
			// IF mouseMoved
			if(!mousemoved) return;
			
			// find real element and next real element
			var jEle = wrap.find('>.pagelayer-ele');
			var nEle = next_ele.find('>.pagelayer-ele');
			var mode = pagelayer_get_screen_mode();
			var col_width = 'col_width';
			
			// Do we have screen ?
			if(mode != 'desktop'){
				col_width = col_width +'_'+mode;
			}
			
			// Set the element attrs
			pagelayer_set_atts(jEle, col_width, new_width);
			pagelayer_set_atts(jEle, 'col', '');
			pagelayer_set_atts(nEle, col_width, nEle_new_width);
			pagelayer_set_atts(nEle, 'col', '');
			
		};
		
		// Resize start
		jQuery(document).on('mousemove', r_mousemove);
		jQuery(document).on('mouseup', r_mouseup);
	});
}

// Handle addition of elements from the left
// NOTE : At this point the addition is FINALIZED
// The add element cannot be prevented !
function pagelayer_onadd(jEle, toClick){
	
	toClick = arguments.length == 2 ? toClick : true;
	
	//console.log(jEle);
	var id = pagelayer_element_added(jEle);
	var jEle = jQuery("[pagelayer-id="+id+"]");
	
	if(toClick){
		//console.log('here');
		jEle.click();
	}
	
	return id;
	
};

// Add an element into the POST
function pagelayer_element_added(jEle){
	
	var sc = jEle.attr('pagelayer-tag');
	var id, par_id;
	var gId = jEle.attr('pagelayer-global-id');
	gId = gId && !pagelayer_empty(pagelayer_global_widgets[gId]) ? gId : 0;
	
	// Set Pagelayer History FALSE to prevent saving attributes in action history
	pagelayer.history_action = false;
	pagelayer.global_render = false;
	
	// Is this a global widget ?
	if(!pagelayer_empty(gId)){
	
		html = pagelayer_element_unsetup(pagelayer_global_widgets[gId].$);
	
	// Generate the HTML
	}else{
		html = pagelayer_create_sc(sc);
	}
	
	id = pagelayer_assign_id(html);
	par_id = id;
	
	// Insert the HTML
	jEle[0].outerHTML = html[0].outerHTML;
	
	// Setup the properties of the elements
	pagelayer_element_setup("[pagelayer-id="+par_id+"], [pagelayer-id="+par_id+"] .pagelayer-ele", true);
	
	// Is this a global widget ? Then set this as global element
	if(!pagelayer_empty(gId)){
		html = pagelayer_set_ele_global(jQuery('[pagelayer-id="'+par_id+'"]'), gId);
	}
	
	// Any children to add ?
	if(!('widget' in pagelayer_shortcodes[sc])){
	
		// The element props
		var props = pagelayer_shortcodes[sc];
		
		// Do we have to create children ?
		if('has_group' in props){
			
			// Is this not a global widget ?
			if(pagelayer_empty(gId)){
				var has_group = props['has_group'];
				var gProp = props[has_group['section']][has_group['prop']];
				
				for(var i=0; i < gProp['count']; i++){
					var cid = pagelayer_element_add_child(jQuery("[pagelayer-id="+id+"]"), gProp['sc'], gProp);
					//pagelayer_element_setup('[pagelayer-id='+cid+']', true);
					
					var cEle = pagelayer_ele_by_id(cid);
					
					// Set default
					if( 'item_atts' in gProp && i in gProp['item_atts'] && !pagelayer_empty(gProp['item_atts'][i]) ){
						pagelayer_set_atts(cEle, gProp['item_atts'][i]);
						pagelayer_sc_render(cEle);
					}
				}
			}else{
				pagelayer_sc_render(jQuery('[pagelayer-id="'+par_id+'"]'));
			}
		}
	
	}
	
	// Save in action history 
	var cEle = pagelayer_near_by_ele(id, sc);

	pagelayer_history_action_push({
		'title' : pagelayer_shortcodes[sc]['name'],
		'action' : 'Added',
		'pl_id' : id,
		'html' : jQuery("[pagelayer-id="+id+"]")[0].outerHTML,
		'cEle' : cEle
	});
	
	// Set pagelayer history TRUE
	pagelayer.history_action = true;
	pagelayer.global_render = true;
	
	// To update nav item list
	pagelayer_do_dirty(pagelayer_ele_by_id(id));
	
	return id;
	
};

// Add an element
function pagelayer_element_add_child(pEle, sc, gProp){
	
	gProp = gProp || {};
	var child = pagelayer_create_sc(sc);
	var cid = pagelayer_assign_id(child);
	pagelayer_set_parent(child, pagelayer_assign_id(pEle));
	
	// Does the parent have a holder ?
	var tag = pagelayer_tag(pEle);
	
	// There is a holder
	if('holder' in pagelayer_shortcodes[tag]){
		
		pEle.find(pagelayer_shortcodes[tag]['holder']).append(child);
		
	// No holder, just append
	}else{
		pEle.append(child);
	}
	
	pagelayer_element_setup('[pagelayer-id='+cid+']', true);
	
	// Certain element have editable areas which are inner rows. For UX we need to add columns for the users
	if(sc == 'pl_inner_row'){
		
		var rHolder = pagelayer_ele_by_id(cid).find('.pagelayer-row-holder');
		
		if( !pagelayer_empty(gProp) && 'inner_content' in gProp){
			
			var inner_content = gProp['inner_content'];
			
			// Add default element
			if(!pagelayer_empty(inner_content)){
				
				var add_sc = function(hEle, _tag, content){
					
					var dEle = jQuery('<div pagelayer-tag="'+_tag+'"></div>');
					
					if(_tag == 'pl_col'){
						hEle = hEle.closest('.pagelayer-row-holder');
					}else{
						hEle = hEle.find('.pagelayer-col-holder');
					}
					
					hEle.append(dEle);
					var curID = pagelayer_onadd(dEle, false);
					var curEle = pagelayer_ele_by_id(curID);
					
					// Set default
					if('atts' in content[_tag]){
						pagelayer_set_atts(curEle, content[_tag]['atts']);
						pagelayer_sc_render(curEle);
					}
					
					// Set inner content
					if('inner_content' in content[_tag]){
						for( var key in content[_tag]['inner_content'] ){
							for( var _key in content[_tag]['inner_content'][key] ){
								add_sc(curEle, _key, content[_tag]['inner_content'][key]);
							}
						}
					}
					
					if(_tag == 'pl_col'){
						// TODO: unable to set col width
						pagelayer_renumber_col(hEle);
					}else{
						pagelayer_empty_col(hEle);
					}
				};
				
				for( var key in inner_content ){
					for( var tag in inner_content[key] ){
						add_sc(rHolder, tag, inner_content[key]);
					}
				}
			}
			
			pagelayer_empty_col(jQuery('[pagelayer-id="'+cid+'"]').find('.pagelayer-col-holder'));
			
		}else{
			var col = jQuery('<div pagelayer-tag="pl_col"></div>');
			rHolder.append(col);
			pagelayer_onadd(col, false);		
		}
	}
	
	// Do we have to create children ?
	if('has_group' in pagelayer_shortcodes[sc]){
				
		var has_group = pagelayer_shortcodes[sc]['has_group'];		
		var gProp = pagelayer_shortcodes[sc][has_group['section']][has_group['prop']];
		
		for(var i=0; i < gProp['count']; i++){
			var in_cid = pagelayer_element_add_child(jQuery("[pagelayer-id="+cid+"]"), gProp['sc'], gProp);
		}
		
	}
	
	return cid;
};

// Return an element by ID
function pagelayer_ele_by_id(id){
	return jQuery('[pagelayer-id='+id+']');
};

// Return the wrap by ID
function pagelayer_wrap_by_id(id){
	return jQuery('[pagelayer-wrap-id='+id+']');
};

// Give the Pagelayer ID
function pagelayer_id(jEle){
	
	var id = jEle.attr('pagelayer-wrap-id');
	if(id){
		return id;
	}
	
	id = jEle.attr('pagelayer-id');
	
	return id;
	
}

// Remove Pagelayer ID class
function pagelayer_remove_id_class(jEle){
	var id = jEle.attr('pagelayer-id');
	jEle.removeClass('p-'+id);
}

// Assign the jQuery object an ID
function pagelayer_assign_id(jEle){
	
	// Do you have the pagelayer id
	var id = jEle.attr("pagelayer-id");
	if(!id || id.length < 1){
		id = pagelayer_randstr(3)+pagelayer_randInt(9999).toString();
		id = id.toLowerCase();
		jEle.attr("pagelayer-id", id);
	}
	
	return id;
	
}

// Show the edit options
function pagelayer_element_clicked(selector, e){
	
	var jEle = jQuery(selector);
	e = e || false;
	//console.log(e);	
	
	// You must be a element atleast
	if(!jEle.hasClass('pagelayer-ele')){
		return false;
	}
	
	// Get the parent
	var pId = pagelayer_get_parent(jEle);
	
	// If we found a parent
	if(pId){
		jEle = pagelayer_ele_by_id(pId);	
	}
	
	// Make the editable fields active	
	//pagelayer_clear_editable();// First clear
	jEle.find('[pagelayer-editable]').each(function (){
		pagelayer_make_editable(jQuery(this), e);
	});

	// Show left bar
	if(pagelayer_empty(e)){
		pagelayer.$$('.pagelayer-leftbar-table').removeClass('pagelayer-leftbar-hidden pagelayer-leftbar-minimize');
	}
	
	// Lets not rebuild everything to make it faster
	if(pagelayer_is_active(jEle)){
		return false;
	}
	
	pagelayer_trigger_action('pagelayer_element_clicked', [jEle]);
	
	// Set this as the active element
	pagelayer_set_active(jEle);
	
	// Show the properties
	pagelayer_elpd_open(jEle);
	
}

// Use text widget for search widget
function pagelayer_search_widgets(hEle){
	
	hEle = hEle || jQuery(pagelayer_editable +' [pagelayer-tag="pl_text"], '+pagelayer_editable +' [pagelayer-tag="pl_heading"]');
	
	hEle.each(function(){
		
		var jEle = jQuery(this);
		var tEle = jEle.find('[pagelayer-editable="text"]');
		
		var addPlaceholder = function(ele){
			
			var tVal = ele.text();
			
			if(pagelayer_empty(tVal)){
				ele.attr('data-placeholder-text', 'Type / to open widget list');
			}else if(ele.attr('data-placeholder-text')){
				ele.removeAttr('data-placeholder-text');
			}
		}
		
		// Add placeholder text
		addPlaceholder(tEle);
		
		tEle.off('input.search_widgets');
		tEle.on('input.search_widgets', function(){
			
			var val = tEle.text();
			
			// Add placeholder text
			addPlaceholder(tEle);
			
			if(val.charAt(0) == "/"){
				val = val.replace('/', '');
				pagelayer_show_widget_list(tEle, val);
			}else if(pagelayer.$$('.pagelayer-widget-tooltip').is(':visible')){
				// Hide Widget list
				pagelayer.gDocument.trigger('mousedown.pagelayer_wdlist');
			}
			
		});
	
	});
	
}

// The edit option
function pagelayer_edit_element(selector){
	pagelayer_element_clicked(selector);
}

// Dump the data from the el to the elements
function pagelayer_element_dump_data(){
	for(var x in pagelayer.el){
		var jEle = pagelayer_ele_by_id(x);
		if(jEle.length > 0){
			pagelayer_el_dump_data(jEle);
		}
	}
}

// Setup the properties on a single click
function pagelayer_element_setup(selector, render){
	
	var selector = selector || ".pagelayer-ele";
	render = render || false;
	
	// Loop through
	jQuery(pagelayer_editable+' '+selector).each(function(){
		
		var jEle = jQuery(this);
		
		// Assign an ID if not there
		var id = pagelayer_assign_id(jEle);
		var pId = pagelayer_get_parent(jEle) || '';// Options to show on hover
		var selector = '[pagelayer-id='+id+']';
		
		// Get data part
		pagelayer.el[id] = pagelayer_el_get_data(jEle);
		//console.log(jEle[0].outerHTML);
		//console.log(pagelayer.el[id]);
			
		if(render){
			pagelayer_sc_render(jEle);
		}
		
		// Get the tag
		var tag = pagelayer_tag(jEle);
		var props = pagelayer_get_props(jEle);
		
		// Lets check if we are the child of a parent i.e. element of a group
		if(pagelayer_empty(pId)){
		
			// Get the parent
			var pEle = jEle.parent().closest('.pagelayer-ele');
			
			// If we found a parent
			if(pEle.length > 0){

				var pTag = pagelayer_tag(pEle);
				
				// Is the parent a group of this child ?
				if(!pagelayer_empty(pagelayer_shortcodes[pTag]) && pagelayer_is_group(pTag)){
					
					var has_group = pagelayer_shortcodes[pTag]['has_group'];		
					var child_type = pagelayer_shortcodes[pTag][has_group['section']][has_group['prop']]['sc'];
					
					// If the type is the same as jEle
					if(child_type == pagelayer_tag(jEle)){
						pId = pagelayer_assign_id(pEle);
						pagelayer_set_parent(jEle, pId);
					}
				}
			
			}
		
		}
		
		// If is group of widget?
		if('widget_group' in props && !pagelayer_empty(props['widget_group'])){
			pagelayer_set_widget_group(jEle);
		}
		
		// Make the wraps
		jEle.wrap('<div class="pagelayer-ele-wrap" pagelayer-wrap-id="'+id+'"></div>');
		var wrap = jEle.parent();
		
		// For column we have to do some kidas !
		if(tag == 'pl_col'){
			
			var col;
			for(var x=1; x<=12; x++){
				if(jEle.hasClass('pagelayer-col-'+x)){
					col = 'pagelayer-col-'+x;
					break;
				}
			}
	  
			
			wrap.addClass('pagelayer-col '+col);
			//jEle.removeClass('pagelayer-col '+col);
			wrap.addClass('pagelayer-wrap-col');
			
		}else if(tag == 'pl_row'){
			wrap.addClass('pagelayer-wrap-row');
		}else if(tag == 'pl_inner_row'){
			wrap.addClass('pagelayer-wrap-inner-row');
		}else{
			wrap.addClass('pagelayer-wrap-ele');
		}
		
		// Create the overlay
		wrap.prepend('<div class="pagelayer-ele-overlay"></div>');
			
		var overlay = wrap.children('.pagelayer-ele-overlay');
		var html;
		
		if(tag == 'pl_row' || tag == 'pl_inner_row'){
			
			overlay.addClass('pagelayer-row-hover');
			
			if(jEle.hasClass('pagelayer-row-stretch-full')){
				pagelayer_sc_render(jEle);
			}
			
			html = '<div class="pagelayer-row-option" pagelayer-option-edit pagelayer-option-id="'+id+'">'+
				'<i class="fas fa-caret-up pagelayer-eoi pagelayer-move-up" onclick="pagelayer_move_element_up(\''+selector+'\')" ></i>'+
				'<i class="far fa-clone pagelayer-eoi" onclick="pagelayer_copy_element(\''+selector+'\')" ></i>'+
				'<i class="fas fa-trash pagelayer-eoi" onclick="pagelayer_delete_element(\''+selector+'\')" ></i>'+
				'<i class="fas fa-pencil-alt pagelayer-eoi" onclick="pagelayer_edit_element(\''+selector+'\', event)" ></i>'+
				'<i class="fas fa-caret-down pagelayer-eoi pagelayer-move-down" onclick="pagelayer_move_element_down(\''+selector+'\')" ></i>'+
			'</div>';
		
		}else if(tag == 'pl_col'){
			
			overlay.addClass('pagelayer-col-hover');
			
			html = '<div class="pagelayer-col-option" pagelayer-option-edit pagelayer-option-id="'+id+'">'+
				'<i class="fas fa-columns pagelayer-eoi" onclick="pagelayer_edit_element(\''+selector+'\', event)" ></i>'+
			'</div>';
			
			// Is it an empty col ?
			pagelayer_empty_col(jEle.children('.pagelayer-col-holder'));
			
			// Make col resizable
			pagelayer_col_make_resizable(wrap);
		
		}else{
		
			html = '<div class="pagelayer-ele-option" pagelayer-option-edit pagelayer-option-id="'+id+'">'+
				'<i class="fas fa-caret-up pagelayer-eoi pagelayer-move-up" onclick="pagelayer_move_element_up(\''+selector+'\')" ></i>'+
				'<i class="far fa-clone pagelayer-eoi" onclick="pagelayer_copy_element(\''+selector+'\')" ></i>'+
				'<i class="fas fa-trash pagelayer-eoi" onclick="pagelayer_delete_element(\''+selector+'\')" ></i>'+
				'<i class="fas fa-pencil-alt pagelayer-eoi" onclick="pagelayer_edit_element(\''+selector+'\', event)" ></i>'+
				'<i class="fas fa-caret-down pagelayer-eoi pagelayer-move-down" onclick="pagelayer_move_element_down(\''+selector+'\')" ></i>'+
			'</div>';
		
		}
		
		// Append to the child
		overlay.append(html);
		
		// Add shortcode icon
		if(tag != 'pl_row' && tag != 'pl_col'){
			overlay.append('<span class="pagelayer-shortcode-plus" onclick="event.stopPropagation();pagelayer_show_widget_list(this);"><i class="fas fa-plus"></i></span>');
		}
		
		jQuery('[pagelayer-option-id='+id+']').hide();
		
		// Hide active when not supported by tag
		if(!pagelayer_empty(props['hide_active'])){
			wrap.addClass('pagelayer-hide-active');
		}
		
		pagelayer_trigger_action('pagelayer_element_setup', [jEle]);
		
		// Setup the HOVER events ABD create WRAPS IF we dont have a parent
		if(pId.length > 0){
			return;
		}
		
		// Make the wrap draggable, but only of independent or parent elements
		wrap.attr('draggable', 'true');
		
		wrap.hover(function(){
			
			// Is there an element option shower ?
			var opts = jQuery('[pagelayer-option-id='+id+']');
			
			// Give the overlay the hover class
			opts.parent().addClass('pagelayer-ele-hover');
			
			// Show them
			opts.show();
			
		}, function(){
			
			// Is there an element option shower ?
			var opts = jQuery('[pagelayer-option-id='+id+']');
			
			// Remove hover class
			opts.parent().removeClass('pagelayer-ele-hover');
			
			// Hide opts
			opts.hide();
			
		});
		
	});
}

// Unsetup element for restup
function pagelayer_element_unsetup(selector, id){
	
	id = id || false;
	
	var src = jQuery(selector);
	var html = src[0].outerHTML;
	
	var jEle = jQuery(html);
	pagelayer_remove_id_class(jEle);
	jEle.removeAttr('pagelayer-id');
	jEle.removeAttr('pagelayer-active');
	jEle.find('[pagelayer-id]').each(function(){
		pagelayer_remove_id_class(jQuery(this));
		jQuery(this).removeAttr('pagelayer-id');
	});
	jEle.find('[pagelayer-parent]').removeAttr('pagelayer-parent');// Remove the parent attribute as it will be reset during pagelayer_element_setup
	jEle.find('style').remove();
	jEle.find('.pagelayer-ele-overlay').remove();
	
	// Unwrap the wraps
	jEle.find('.pagelayer-ele').each(function (){
		var ele = jQuery(this);
		if(ele.parent().is('.pagelayer-ele-wrap')){
			ele.unwrap();
		}
	});
	
	// Assign id
	if(!pagelayer_empty(id)){
		jEle.attr('pagelayer-id', id);
	}
	
	return jEle;
}

// Left Click
function pagelayer_left_click(){
	
	jQuery(pagelayer_editable).on('click', function(e){
		
		e.preventDefault();// Added by Jivan in Actions / Revisions version
		
		// Hide the context menu
		jQuery('.pagelayer-right-click-options').hide();
		
		// Target
		var tEle = jQuery(e.target);
		
		// If its an edit option click
		if(tEle.hasClass('pagelayer-eoi')){
			return false;
		}
		
		pagelayer_element_clicked(tEle.closest('.pagelayer-ele'), e);
		
		return false;
		
	});
};

// Right Click Menu
function pagelayer_right_click(){
	
	var html = '<div class="pagelayer-right-click-options" style="display:none;">'+
		'<ul>'+
			'<li><a class="pagelayer-right-edit">Edit</a></li>'+
			'<li><a class="pagelayer-right-duplicate"><i class="far fa-clone" ></i> '+pagelayer_l('Duplicate')+'</a></li>'+
			'<li><a class="pagelayer-right-copy"><i class="far fa-copy" ></i> '+pagelayer_l('Copy')+'</a></li>'+
			'<li><a class="pagelayer-right-paste"><i class="far fa-clipboard" ></i> '+pagelayer_l('Paste')+'</a></li>'+
			'<li><a class="pagelayer-right-delete"><i class="far fa-trash-alt" ></i> '+pagelayer_l('Delete')+'</a></li>'+
			'<li><a class="pagelayer-right-save-global-widget" pro="1"><i class="far fa-save" ></i> '+pagelayer_l('save_global')+'</a></li>'+
			'<li><a class="pagelayer-right-save-section" pro="1"><i class="far fa-heart" ></i> '+pagelayer_l('save_as_section')+'</a></li>'+
			'<li><a class="pagelayer-right-save-global-section" pro="1"><i class="fas fa-globe" ></i> '+pagelayer_l('save_as_global_section')+'</a></li>'+
		'</ul>'+
	'</div>';
	
	jQuery('body').append(html);
	
	var $contextMenu = jQuery('.pagelayer-right-click-options');
	
	jQuery(pagelayer_editable).on('contextmenu', function(e){
		
		var tEle = jQuery(e.target);
		var jEle = tEle.closest('.pagelayer-ele-wrap').children('.pagelayer-ele');
		
		// Get the parent
		var pId = pagelayer_get_parent(jEle);
		
		// If we found a parent
		if(pId){
			jEle = pagelayer_ele_by_id(pId);
		}
		
		// The basics
		var id = pagelayer_assign_id(jEle);		
		var tag = pagelayer_tag(jEle);
		
		$contextMenu.find('.pagelayer-right-edit').attr('onclick', 'pagelayer_edit_element("[pagelayer-id='+id+']")').html('<i class="far fa-edit" ></i> Edit '+pagelayer_shortcodes[tag]['name']);
		$contextMenu.find('.pagelayer-right-duplicate').attr('onclick', 'pagelayer_copy_element("[pagelayer-id='+id+']")');
		$contextMenu.find('.pagelayer-right-copy').attr('onclick', 'pagelayer_copy_select("[pagelayer-id='+id+']")');
		$contextMenu.find('.pagelayer-right-paste').attr('onclick', 'pagelayer_paste_element("[pagelayer-id='+id+']")');
		$contextMenu.find('.pagelayer-right-delete').attr('onclick', 'pagelayer_delete_element("[pagelayer-id='+id+']")');
		
		// If is pagelayer pro
		if(!pagelayer_empty(pagelayer_pro)){
			$contextMenu.find('.pagelayer-right-save-global-widget').attr('onclick', 'pagelayer_save_sections("[pagelayer-id='+id+']", "global_widget")');
			$contextMenu.find('.pagelayer-right-save-section').attr('onclick', 'pagelayer_save_sections("[pagelayer-id='+id+']", "section")');
			$contextMenu.find('.pagelayer-right-save-global-section').attr('onclick', 'pagelayer_save_sections("[pagelayer-id='+id+']", "global_section")');
		}else{
			var pro = $contextMenu.find('[pro="1"]');
			
			if(pro.find('.pagelayer-pro-req').length < 1){
				pro.append('<span class="pagelayer-pro-req">Pro</span>');
			}
			
			pro.css({'color': '#a7a7a7'});
			
			// To stopPropagation
			pro.parent().on('click', function(e){
				e.stopPropagation();
			});
		}
		
		// If copy_selected is empty then copy data from localStorage
		if(pagelayer_empty(pagelayer.copy_selected)){
			pagelayer_copy_from_localStorage();
		}
		
		// Are we to hide the paste ?
		if(!pagelayer_empty(pagelayer.copy_selected) && pagelayer_can_copy_to(jEle)){
			//console.log(pagelayer_can_copy_to(jEle));
			$contextMenu.find('.pagelayer-right-paste').parent().show();
		}else{
			$contextMenu.find('.pagelayer-right-paste').parent().hide();
		}
		
		var gId = pagelayer_get_global_id(jEle);
		
		// Are we to hide the global widget ?
		if(!pagelayer_empty(gId) || tag == 'pl_row' || tag == 'pl_inner_row'|| tag == 'pl_col'){
			$contextMenu.find('.pagelayer-right-save-global-widget').parent().hide();
		}else{
			$contextMenu.find('.pagelayer-right-save-global-widget').parent().show();
		}
		
		var sId = pagelayer_get_att(jEle, 'global-section-id');
		
		// Are we to hide the save as global section ?
		if( tag == 'pl_row' &&  pagelayer_empty(sId)){
			$contextMenu.find('.pagelayer-right-save-global-section').parent().show();
		}else{
			$contextMenu.find('.pagelayer-right-save-global-section').parent().hide();
		}
		
		// Are we to hide the save as section ?
		if( tag == 'pl_row' ){
			$contextMenu.find('.pagelayer-right-save-section').parent().show();
		}else{
			$contextMenu.find('.pagelayer-right-save-section').parent().hide();
		}
			
		var hPosition = (e.pageX+$contextMenu.width()>jQuery(window).width()) ? (e.pageX-$contextMenu.width()) : e.pageX;
		var vPosition = (e.pageY+$contextMenu.height()>jQuery(document).scrollTop()+jQuery(window).height()) ? (e.pageY-$contextMenu.height()) : e.pageY;
		
		$contextMenu.css({
			display: "block",
			left: hPosition,
			top: vPosition
		});
		
		return false;
		 
	});
	
	jQuery('html').on('click', function(e){
		$contextMenu.hide();
	});
}

// Set the parent for the group
function pagelayer_set_parent(jEle, id){
	jEle.attr('pagelayer-parent', id);
};

// Set the widget group
function pagelayer_set_widget_group(jEle){
	jEle.addClass('pagelayer-ele-widget-group');
};

// Get the parent for the group
function pagelayer_get_parent(jEle){
	return jEle.attr('pagelayer-parent');
};

// Sets the screen mode
function pagelayer_set_screen_mode(mode){
	var modes = ['desktop', 'tablet', 'mobile'];
	var body = pagelayer.$$('.pagelayer-iframe-holder iframe');
	var current = '';
	
	for(var x in modes){
		
		if(body.hasClass('pagelayer-screen-'+modes[x]) && modes[x] != mode){
			current = modes[x];
			body.removeClass('pagelayer-screen-'+modes[x]);
		}
	}
	
	// Add the class
	body.addClass('pagelayer-screen-'+mode);
	
	// Add the class to the button
	pagelayer.$$('.pagelayer-mode-button').removeClass('pli-'+current).addClass('pli-'+mode);
	
	// Add the class to the button
	pagelayer.$$('.pagelayer-prop-screen').removeClass('pli-'+current).addClass('pli-'+mode);
	
	// Trigger screen change if any
	pagelayer.$$('.pagelayer-elp-screen').trigger('pagelayer-screen-changed');
	
};

// Get the current screen mode
function pagelayer_get_screen_mode(){
	var modes = ['desktop', 'tablet', 'mobile'];
	var body = pagelayer.$$('.pagelayer-iframe-holder iframe');
	
	for(var x in modes){
		if(body.hasClass('pagelayer-screen-'+modes[x])){
			return modes[x];
		}
	}
}

var pagelayer_keydown_data = {};
pagelayer_add_action('pagelayer_do_dirty', function(){
	pagelayer_keydown_data = {};
});

var pagelayer_active_ele_timmer = {};
// Handle widget selecttion and move cursor in editable areas on key press events
jQuery(document).keydown(function(e){
	//alert(String.fromCharCode(e.which));
	
	var tEle = jQuery(e.target);
	var editable = tEle.closest('[contenteditable="true"]');
	var tooltip = pagelayer.$$('.pagelayer-widget-tooltip');
	
	// If ArrowDown and ArrowUp key not pressed
	if(!(e.key == 'ArrowDown' || e.key == 'ArrowUp') || tooltip.is(':visible')){
		pagelayer_keydown_data = {};
		return;
	}
	
	var findEles = jQuery(pagelayer_editable+' .pagelayer-ele,'+pagelayer_editable+' [contenteditable="true"]');
	var activeEle = findEles.first();
	
	if(editable.length > 0){
		activeEle = editable;
	}else if( '$' in pagelayer_keydown_data ){
		activeEle = pagelayer_keydown_data.$;
	}else if( pagelayer_active.el && 'id' in pagelayer_active.el ){
		activeEle = pagelayer_active.el.$;
	}
	
	if(pagelayer_empty(activeEle) || activeEle.length < 1){
		return;
	}
	
	// Make element active
	var makeEleActive = function(index, next){
		
		next = next || false;
		var cursorPos = 0, focusEle;
		
		// We are editable area
		if(editable.length > 0){
			
			var lines = pagelayer_content_line(editable.get(0));
			var cursorPos = pagelayer_getCaretCharacterOffsetWithin(editable.get(0));

			if((next && lines[lines.length - 1].start > cursorPos) || (!next && lines[0].end < cursorPos)){
				return;
			}
			
			e.preventDefault();
						
			var lastLineStart = lines[lines.length - 1]['start'];
			
			// We are on the last line
			if(next && lastLineStart <= cursorPos){
				cursorPos = cursorPos - lastLineStart;
			}
			
		}
		
		// Search for next/previous element
		var searchEle = function(indexEle){
			
			indexEle = next ? ++indexEle : --indexEle;
			var sIndex = findEles.eq(indexEle);
			
			if(sIndex.length < 1){
				return sIndex;
			}
		
			var sEle = sIndex.closest('.pagelayer-ele');
			var tag = pagelayer_tag(sEle);
			
			if(tag == 'pl_row' || tag == 'pl_inner_row' || tag == 'pl_col' || sEle.parent().hasClass('pagelayer-hide-active') || !pagelayer_empty(sIndex.attr('pagelayer-parent'))){
				sIndex = searchEle(indexEle);
			}
			
			return sIndex;
		}
		
		var ele = searchEle(index);
		
		// If ArrowUp and we are come from editable area and previous element is not editable
		if(ele.length > 0 && !next && ele.attr('contenteditable') != 'true'){
			ele = searchEle(findEles.index( ele ));
		}
		
		if(ele.length < 1){
			return;
		}
		
		// Save in global variable
		pagelayer_keydown_data.$ = ele;
		jQuery(':focus').blur();
		
		var jEle = ele.closest('.pagelayer-ele');
		var tag = pagelayer_tag(jEle);
		
		if(ele.attr('contenteditable') == 'true'){
			focusEle = ele;
		}else if(tag != 'pl_row' && tag != 'pl_inner_row' && tag != 'pl_col'){
			
			var focusAble = ele.find('[contenteditable="true"]');
			var isfocusAble = focusAble.closest('.pagelayer-ele').is(jEle);
		
			if(isfocusAble && next){
				focusEle = focusAble.first();
			}else if(isfocusAble){
				focusEle = focusAble.last();
			}
		}
		
		if(!pagelayer_empty(focusEle) && focusEle.length > 0){
			focusEle.focus();
			
			var focusLine = pagelayer_content_line(focusEle.get(0));
			var fLine = next ? focusLine[0] : focusLine[focusLine.length -1];
			
			cursorPos = (fLine['start'] + cursorPos > fLine['end'] ? fLine['end'] : fLine['start'] + cursorPos);
			
			pagelayer_setCaret(focusEle.get(0), cursorPos);
		}
		
		pagelayer_set_active(jEle);
		ele[0].scrollIntoView({behavior: "smooth", block: "nearest"});
		
		clearTimeout(pagelayer_active_ele_timmer);
		pagelayer_active_ele_timmer = setTimeout(function(){
			pagelayer_keydown_data = {};
			ele.closest('.pagelayer-ele').click();
		}, 1000);
	}
	
	// If cursor on first line & up arrow key
	var currentIndex = findEles.index( activeEle );
	pagelayer_keydown_data.$ = activeEle;
	
	// Move active element and cursor arround editor
	if(e.key == 'ArrowDown'){
		makeEleActive(currentIndex, true);
	}
	
	if(e.key == 'ArrowUp'){		
		makeEleActive(currentIndex, false);
	}
});

// Handle key press events
pagelayer.gDocument.keydown(function(event){
	//alert(String.fromCharCode(event.which));
	
	var tEle = jQuery(event.target);
	var editable = tEle.closest('[contenteditable="true"]');
	var tooltip = pagelayer.$$('.pagelayer-widget-tooltip');

	// Enter handle
	if(event.keyCode == 13){
				
		var jEle = tEle.closest('.pagelayer-ele');
		var tag = pagelayer_tag(jEle);
		
		// Add selected widget from widget list
		if(tooltip.is(':visible')){
			tooltip.find('.pagelayer-list-widget-active:visible').click();
			return;
		}
		
		if( pagelayer_empty(pagelayer_active.el) || !('id' in pagelayer_active.el) ){
			return;
		}
		
		var active_el_par = pagelayer_active.el.$.parent();
		
		// Create and add text widget
		var addTitle = function(insertAfter){
			var ele = jQuery('<div pagelayer-tag="pl_text"></div>');
			insertAfter.after(ele);
			return pagelayer_ele_by_id( pagelayer_onadd(ele) );
		}
		
		// If we have an active element then add text widget
		if(!(tEle.is('input, textarea') || editable.length > 0)){
			
			event.preventDefault();
			
			var activeTag = pagelayer_active.el.tag;
			
			// If is row or column ?
			if(activeTag == 'pl_row' || activeTag == 'pl_col'){
				return;
			}
			
			var hEle = addTitle(active_el_par);
			hEle.click();
			hEle.find('[pagelayer-editable]').focus();
			
			// Ensure the column is not empty
			pagelayer_empty_col(hEle.closest('.pagelayer-col-holder'));
			return;
		}
    
		if( (tag != 'pl_text' && tag != 'pl_heading') || editable.length < 1 || event.shiftKey){
			return;
		}
		
		var selection = window.getSelection();
		var range = selection.getRangeAt(0);
			
		// We are within the list tag
		if(jQuery(range.startContainer).closest('[pagelayer-editable] li').length > 0){
			return;
		}
		
		event.preventDefault();
    			
		var lastChild = editable[0].lastChild;
		var startContainer = range.startContainer;
			
		if(startContainer.nodeType == Node.TEXT_NODE && startContainer.parentNode != editable[0]){
			startContainer = startContainer.parentNode;
		}
			
		range.setEndAfter(lastChild);
			
		var val = range.cloneContents();
		var selfEle = jQuery('<div>').append(val);
		var selContent = selfEle.html();
		var selfFC = selfEle[0].firstChild;
		var emptyContent = false;
		
		if(selfFC == null || pagelayer_empty(selContent)){
			selContent = '<p><br></p>';
			emptyContent = true;
		}else if(selfFC.nodeType == Node.TEXT_NODE){			
			selContent = '<p>'+selContent+'</p>';
		}else if(selfEle.text() == '' && selfEle.find('br').length < 1){
			selContent = '<p><br></p>';
			emptyContent = true;
		}else if(selfEle.text().trim() == ''){
			selContent = selContent.replace(/\s+/, "\u00A0");
			emptyContent = true;
		}

		range.deleteContents();
    
		if( jQuery(startContainer).is(':first-child') && jQuery(startContainer).is(':empty') ){
			jQuery(startContainer).html('<br>');
		}else if( jQuery(startContainer).is(':empty') ){
			jQuery(startContainer).remove();
		}
		
		// If editor is empty
		if( editable.is(':empty') ){
			editable.html('<p><br></p>');
		}
		
		editable.trigger('input');
		editable.blur();
		
		// Create and add text widget
		var ele;
		if(emptyContent){
			ele = addTitle(jEle.parent());
		}else{		
			var id = pagelayer_copy_element(jEle);
			ele = pagelayer_ele_by_id(id);
		}
		
		ele.click();
		var editorArea = ele.find('[pagelayer-editable]');
		editorArea.html(selContent);
		editorArea.find('p:empty').remove();
		editorArea.focus().trigger('input');
	}
	
	// ctrl+s handle
	if(event.keyCode == 83 && event.ctrlKey){
		event.preventDefault();
		pagelayer.$$('.pagelayer-bottombar-holder').find('.pagelayer-update-button').click();
	}
	
	// ctrl+d handle
	if(event.keyCode == 68 && event.ctrlKey){
		
		// If we have an active element
		if( pagelayer_active.el && pagelayer_active.el.id ){
			event.preventDefault();
			pagelayer_copy_element('[pagelayer-id='+pagelayer_active.el.id+']');
		}
		
	}
	
	// Delete handler for text widget
	if(event.keyCode == 46 && editable.length > 0){
		var jEle = tEle.closest('.pagelayer-ele-wrap');
		var tag = pagelayer_tag(jEle);
		var next = jEle.next();
		var pTag = pagelayer_tag(next);
		
		var selection = window.getSelection();		
		var orgRange = selection.getRangeAt(0);
		var cloneRange = orgRange.cloneRange();
		
		if((tag != 'pl_text' && tag != 'pl_heading') || next.length < 1 || pTag != tag || !cloneRange.collapsed ){
			return;
		}
		
		var currentOffset = pagelayer_getCaretCharacterOffsetWithin(editable[0]);
		cloneRange.selectNodeContents(editable[0]);
		var caretOffset = cloneRange.toString().length;
		
		if(currentOffset != caretOffset){
			return;
		}
		
		var nextHtml = next.find('[pagelayer-editable="text"]').html();
		editable.append(nextHtml);
		pagelayer_delete_element(next.children('.pagelayer-ele'));
	}
	
	// Backspace handler
	if(event.keyCode == 8 && editable.length > 0){
		var jEle = tEle.closest('.pagelayer-ele-wrap');
		var tag = pagelayer_tag(jEle);
		var prev = jEle.prev();

		if((tag != 'pl_text' && tag != 'pl_heading') || prev.length < 1){
			return;
		}
				
		var pTag = pagelayer_tag(prev);
		var selection = window.getSelection();
		
		if (selection == null || selection.rangeCount <= 0) return null;
		
		var range1 = selection.getRangeAt(0);
		
		if(pTag != tag || range1.startOffset != 0){
			return;
		}
		
		var prevArea = prev.find('[pagelayer-editable="text"]');
		
		if( pagelayer_getCaretCharacterOffsetWithin(editable[0]) != 0 || prevArea.length < 1){
			return;
		}
		
		//event.preventDefault();
		var html = editable.html();
		editable.blur();
		prev.children('.pagelayer-ele').click();
		prevArea.click();
		
		var newSel = window.getSelection();
		var newRange = newSel.getRangeAt(0);
		var lastChild = jQuery(prevArea[0].lastChild);
		
		prevArea.append(html);
		prevArea.trigger('input');
		
		if(lastChild.length > 0){
			if(lastChild[0].nextSibling != null){
				newRange.setStart(lastChild[0].nextSibling, 0);
			}else{
				newRange.setStartAfter(lastChild[0]);
			}
		}
		
		newRange.collapse(true);
		newSel.removeAllRanges();
		newSel.addRange(newRange);
			
		pagelayer_delete_element(jEle.children('.pagelayer-ele'));
		
	}
  	
	if(tooltip.is(':visible')){
		
		// Select previous widget in widget tooltip
		if(event.key == 'ArrowUp' || event.key == 'ArrowLeft' || (event.key == 'Tab' && event.shiftKey)){
			
			event.preventDefault();
			
			var current = tooltip.find('.pagelayer-list-widget-active:visible'),
			prev = current.prevAll('.pagelayer-shortcode-holder:visible');
				
			if(event.key == 'ArrowUp'){
				var _prev = prev,
				cOffset = current.offset();
				findNext = false;
				
				var searchNext = function(nEle){
					
					var nOffset = nEle.offset();
					var nBottom = nOffset.top + nEle.height();
					
					if(nBottom > cOffset.top){
						return true;
					}
					
					prev = nEle;
					findNext = true;
					
					// Current element left set +20 to manager previous scale (css) element on hover
					if(cOffset.left + 20 >= nOffset.left){
						return false;
					}
					
					return true;
				}
				
				_prev.each(function(){
					return searchNext(jQuery(this));
				});
				
				if(!findNext){
					var gNext = current.parent().prevAll('.pagelayer-widget-group:visible').first();
					_prev = gNext.children('.pagelayer-shortcode-holder:visible');
					
					jQuery(_prev.get().reverse()).each(function(){
						return searchNext(jQuery(this));						
					});
				}
				
			}
			
			if(prev.length < 1){
				prev = current.parent().prevAll('.pagelayer-widget-group:visible').first().find('.pagelayer-shortcode-holder:visible').last();
			}
			
			if(prev.length < 1){
				return;
			}
			
			prev.first().trigger('widget_active');
		}
		
		// Select next widget in widget tooltip 
		if(event.key == 'ArrowDown' || event.key == 'ArrowRight' || (event.key == 'Tab' && !event.shiftKey)){

			event.preventDefault();
			
			var current = tooltip.find('.pagelayer-list-widget-active:visible');
			next = current.nextAll('.pagelayer-shortcode-holder:visible');
				
			if(event.key == 'ArrowDown'){
				
				var _next = next,
				cOffset = current.offset(),
				findNext = false;
				
				var searchNext = function(nEle){
					var nOffset = nEle.offset();
					var cBottom = cOffset.top + current.height();
					
					if(cBottom > nOffset.top){
						return true;
					}
					
					next = nEle;
					findNext = true;
					
					// Current element left set -20 to manager next scale (css) element on hover
					if(cOffset.left - 20 <= nOffset.left){
						return false;
					}
					
					return true;
				}
				
				_next.each(function(){
					return searchNext(jQuery(this));
				});
				
				if(!findNext){
					var gNext = current.parent().nextAll('.pagelayer-widget-group:visible').first();
					_next = gNext.children('.pagelayer-shortcode-holder:visible');
					_next.each(function(){
						return searchNext(jQuery(this));						
					});
				}
				
			}
			
			if(next.length < 1){
				next = current.parent().nextAll('.pagelayer-widget-group:visible').first().find('.pagelayer-shortcode-holder:visible');
			}
			
			if(next.length < 1){
				return;
			}
			
			next.first().trigger('widget_active');

		}
	}

	// Is this in the editable area ?
	if (tEle.is('input, textarea') || editable.length > 0) {
		return;
	}
	
	// Delete
	if(event.keyCode == 46){
		pagelayer_delete_element('[pagelayer-active]');
	}
	
	// ctrl+z handle
	if(event.keyCode == 90 && event.ctrlKey){
		pagelayer_do_history('undo');
	}
	
	// ctrl+y handle
	if(event.keyCode == 89 && event.ctrlKey){
		pagelayer_do_history('redo');
	}
	
});

// Handle Copy of content
jQuery(document).on('copy', function(copyEvent){
		
	// Is Selected string?
	var selectedText = "";
	if (window.getSelection){ // all modern browsers and IE9+
		selectedText = window.getSelection().toString();
	}
	
	if(selectedText.length > 0){
		return;
	}
	
	if(pagelayer_active.el && pagelayer_active.el.id){
		
		// Do empty clipbord data 
		(copyEvent.originalEvent || copyEvent).clipboardData.setData('text/plain', '');
		copyEvent.preventDefault();
		
		// Save the active element id
		pagelayer_copy_select("[pagelayer-id='"+pagelayer_active.el.id+"']");
		
	}
	
});

// Handle Paste in the editor
jQuery(document).on('paste', function(pasteEvent){

	var pEle_target = jQuery((pasteEvent.originalEvent || pasteEvent).target);
	var tag = pagelayer_tag(pEle_target.closest('[pagelayer-id]'));
	var clipboardData = (pasteEvent.originalEvent || pasteEvent).clipboardData;
	var items = clipboardData.items;

	var pagelayer_ajax_func = {};
	var contenteditable = false;
	var pasteWidget = false;

	if( pEle_target.closest('[contenteditable="true"]').length > 0 || pEle_target.is('input, textarea') ){
		pEle_target = pEle_target.closest('[contenteditable="true"], input, textarea');
		contenteditable = true;
	}
	
	if( items.length < 1 || (items.length == 1 && pagelayer_empty(clipboardData.getData(items[0].type))) ){
		pasteWidget = true;
	}
	
	// This function for ajax before send call back
	pagelayer_ajax_func['beforeSend'] = function(xhr){
		
		// If target is not content editable
		if( pagelayer_empty(contenteditable) ){
		
			// If we dont have an active element then return false and stop ajax
			if( !(pagelayer_active.el && pagelayer_active.el.id) ){
				pagelayer_show_msg(pagelayer_l('active_ele_paste_msg'));
				return false;
			}
							
			pagelayer.copy_selected = jQuery('<div pagelayer-tag="pl_image"></div>');
				
			// Is it to be pastable
			if(!pagelayer_can_copy_to('[pagelayer-id="'+pagelayer_active.el.id+'"]')){
				pagelayer.copy_selected = '';
				return false;
			}
		}
		
		pEle_target.css({'opacity': '0.33' , 'transition' : '0.1s'});
	}
	
	// This function for ajax success call back
	pagelayer_ajax_func['success'] = function(obj){
		
		// Successfully Uploaded
		if(obj['success']){
			
			// For content editable e.g. Rich Text
			if( !pagelayer_empty(contenteditable) ){
				document.execCommand('insertImage', false, obj['data']['url']);
			
			// For our widgets
			}else{
				
				if(pagelayer_empty(pagelayer_active.el) || pagelayer_empty(pagelayer_active.el.id)){
					pagelayer_show_msg('active_ele_paste_msg');
					return;
				}
				
				var fTo = pagelayer_can_copy_to('[pagelayer-id="'+pagelayer_active.el.id+'"]');
				// We need to empty pagelayer.copy_selected
				pagelayer.copy_selected = '';
				
				var pasteAfter = function(){
					
					// Prevent to add action history
					pagelayer.history_action = false;
					
					// Create image html
					var html = pagelayer_create_sc('pl_image');
					
					pagelayer_set_atts(html, 'id', obj['data']['id']);
					pagelayer_set_tmp_atts(html, 'id-url', obj['data']['url']);
					
					// Allow to add action history
					pagelayer.history_action = true;
		
					// Copy the element
					var id = pagelayer_copy_element(html, fTo);
					jQuery('[pagelayer-id="'+id+'"]').click();
					
				};
				
				var replaceURL = function(){
					
					// Finding widget image setting using id of jEle. Finding image editor setting from all of the other settings.
					var row = pagelayer.$$('[pagelayer-element-id='+pagelayer_active.el.id+']').find('.pagelayer-elp-image').eq(0).parent().parent();
					
					row.find('.pagelayer-elp-image').css('background-image', 'url(\''+obj['data']['url']+'\')');
					
					// To remove past temp attr so that they are not involve in future temp values
					var cname = row.attr('pagelayer-elp-name');
					var old = _pagelayer_img_tmp_atts(row);
					delete old[cname+'-url'];
					
					for(var x in obj['data']['sizes']){
						_pagelayer_set_tmp_atts(row, x+'-url', obj['data']['sizes'][x]['url']);
						delete old[cname+'-'+x+'-url'];
					}
					
					for(var x in old){
						_pagelayer_set_tmp_atts(row, x+'-url', '');
					}
										
					// Save and render
					_pagelayer_set_tmp_atts(row, 'url', obj['data']['url']);
					_pagelayer_set_atts(row, obj['data']['id']);
				};
				
				// Image paste confirmation.
				if(!pagelayer_empty(pagelayer_active.el.tag) && pagelayer_active.el.tag == 'pl_image'){
					
					pagelayer_confirmation_box(pagelayer_l('img_paste_conf'), replaceURL, pasteAfter, pagelayer_l('replace_img'), pagelayer_l('paste_after'));
					
				}else{
					pasteAfter();
				}
			}
		
		// Some error occured	
		}else{
			pagelayer_show_msg(obj['data']['message'], 'error', 10000);						
		}
	}
	
	// This function for ajax complete call back
	pagelayer_ajax_func['complete'] = function(xhr){
		//console.log(xhr);
		pEle_target.css({'opacity': '1' , 'transition' : '0.1s'});
	}
	
	var findImg = pagelayer_editable_paste_handler(pasteEvent, pagelayer_ajax_func);
	
	if(pagelayer_empty(findImg) && pagelayer_empty(contenteditable) || pasteWidget){
		
		// Check the active element
		if(pagelayer_active.el && pagelayer_active.el.id && pagelayer_active.el.tag != 'pl_post_props'){
			
			var jEle = jQuery("[pagelayer-id='"+pagelayer_active.el.id+"']");
									
			// Check if the any element is copied
			pagelayer_paste_element("[pagelayer-id='"+pagelayer_active.el.id+"']");
			
		}else{
			pagelayer_show_msg(pagelayer_l('no_active_ele_paste'));
		}
	}
});

// Delete an element as per the selector
function pagelayer_delete_element(selector){
	var jEle = jQuery(selector);
	var nearBy = jEle;
	
	// Anything found ?
	if(jEle.length > 0){
		
		var id = pagelayer_assign_id(jEle);
		var sc = pagelayer_tag(jEle);
		
		// Is there a wrap
		var wrap = jQuery('[pagelayer-wrap-id="'+id+'"]');
		
		var par = wrap.parent();
		
		// Save this element in history action
		if(pagelayer.history_action){	
			var cEle = pagelayer_near_by_ele(id, sc);
			
			nearBy = jQuery(cEle.cEle);
			
			// To save in history, we need to save only element not the wraps as we call setup if we redo or undo	
			jEle.find('style').remove();
			jEle.find('.pagelayer-ele-overlay').remove();
			
			// Unwrap the wraps
			jEle.find('.pagelayer-ele').each(function (){
				var ele = jQuery(this);
				if(ele.parent().is('.pagelayer-ele-wrap')){
					ele.unwrap();
				}
			});
						
			pagelayer_history_action_push({
				'title' : pagelayer_shortcodes[sc]['name'],
				'action' : 'Deleted',
				'pl_id' : id,
				'html' : jEle[0].outerHTML,
				'cEle' : cEle
			});
		}
		
		wrap.remove();
		
		pagelayer_empty_col(par);
		
		if( (pagelayer_active.el && pagelayer_active.el.id == id) || 
      (pagelayer_active.el && pagelayer_active.el.id && jQuery('[pagelayer-id="'+pagelayer_active.el.id+'"]').length < 1)){
			pagelayer.$$('.pagelayer-elpd-close').click();
		}
		
	}
	
	// Do Pagelayer dirty
	pagelayer_do_dirty(nearBy);
};

// Select an element
function pagelayer_copy_select(selector){
	
	var eHtml = jQuery(selector)[0].outerHTML;
	
	// Copy data on localStorage
	localStorage.setItem("pagelayer_ele", eHtml);
	
	pagelayer.copy_selected = selector;
	
	pagelayer_show_msg( pagelayer_l('copied_msg'));
}

function pagelayer_can_copy_to(to){
	var jEle = jQuery(pagelayer.copy_selected);
	var tEle = jQuery(to);
	
	var eTag = pagelayer_tag(jEle);
	var tTag = pagelayer_tag(tEle);
	//console.log(eTag+' - '+tTag);
	// Final to
	var fTo;
	
	// Selected element is a Row, can go only after a row
	if(eTag == 'pl_row'){
		fTo = tEle.closest('.pagelayer-ele.pagelayer-row');
		if(fTo.length != 1) return false;
		return fTo;
	}
	
	// Selected element is a Column, can go only after a col
	if(eTag == 'pl_col'){
		fTo = tEle.closest('.pagelayer-ele.pagelayer-col');
		if(fTo.length != 1) return false;
		return fTo;
	}
	
	// Is the TARGET a row or column when the selected item is a element
	if(tTag == 'pl_row' || tTag == 'pl_col'){
		return false;
	}
	
	return tEle;
	
}

// Select an element
function pagelayer_paste_element(to){
	
	// Copy data from localStorage
	pagelayer_copy_from_localStorage();
	
	var fTo = pagelayer_can_copy_to(to);
	
	// Is it a valid to
	if(!fTo){
		return false;
	}
	
	if(!pagelayer_empty(pagelayer.copy_selected)){
		pagelayer_copy_element(pagelayer.copy_selected, fTo);
		return true;
	}
	
	pagelayer_show_msg(pagelayer_l('no_copied'));
	
	return false;
	
}

// If copy_selected is empty then copy data from localStorage
function pagelayer_copy_from_localStorage(){
	if(!pagelayer_empty(localStorage.getItem("pagelayer_ele"))){
		// Set copy data from localStorage
		pagelayer.copy_selected = localStorage.getItem("pagelayer_ele");
	}
}

// Copy an element
// Note : insertAfter should always be an pagelayer-ele
function pagelayer_copy_element(selector, insertAfter){
	var src = jQuery(selector);
	var tag = pagelayer_tag(src);
	insertAfter = insertAfter || src;
	insertAfter = insertAfter.parent();
	
	var jEle = pagelayer_element_unsetup(src);
	
	// Give it an ID
	var id = pagelayer_assign_id(jEle);
	
	jQuery(insertAfter).after(jEle);
	
	pagelayer_element_setup('[pagelayer-id='+id+'], [pagelayer-id='+id+'] .pagelayer-ele', true);
	
	if(pagelayer_is_group(tag)){
		pagelayer_sc_render(jEle);
	}
	
	// Save this element in history action
	if(pagelayer.history_action){
		var cEle = pagelayer_near_by_ele(id, tag);
		pagelayer_history_action_push({
			'title' : pagelayer_shortcodes[tag]['name'],
			'action' : 'Copied',
			'pl_id' : id,
			'html' : jEle[0].outerHTML,
			'cEle' : cEle
		});
	}
	
	//If column then renumber columns
	if(tag == 'pl_col'){
		var row = src.parent().closest('.pagelayer-row');
		pagelayer_renumber_col(row);
	}
	
	pagelayer_do_dirty(jEle);
	
	return id;
};

// Traversing up one step an element
function pagelayer_move_element_up(selector){
	
	var src = jQuery(selector);
	var srcParent = src.parent();
	
	var srcParentPrev = srcParent.prev('.pagelayer-wrap-row, .pagelayer-wrap-inner-row, .pagelayer-wrap-ele');

	if(srcParentPrev.length<=0){
		return;
	}
  
	var srcTopValue = srcParent.offset().top;
	
	if(srcParentPrev.hasClass('pagelayer-wrap-ele')){
	
		var animUpCalc = srcTopValue-srcParentPrev.offset().top;
	
		srcParent.animate({top:-animUpCalc}, 200, function(){
			srcParent.css('top', '');
			srcParentPrev.css('top', '');
			srcParentPrev.before(srcParent.detach());
		});	
		
		srcParentPrev.animate({top:(srcParent.height()+srcParentPrev.height())-animUpCalc}, 200, function(){
			srcParentPrev.css('top', '');
		});		
		
		// Traverse window scroll with the element
		jQuery('html, body').animate({scrollTop:('-='+(srcTopValue-(srcParentPrev.offset().top)))},200);
	}else{
		srcParentPrev.before(srcParent.detach());		
		
		// Traverse window scroll with the element
		jQuery('html, body').animate({scrollTop:('-='+(srcTopValue-(src.parent().offset().top)))},200);
	}
	
	pagelayer_do_dirty(src);
}

// Traversing down one step an element
function pagelayer_move_element_down(selector){
	
	var src = jQuery(selector);
	var srcParent = src.parent();
	
	var srcParentNext = srcParent.next('.pagelayer-wrap-row, .pagelayer-wrap-inner-row, .pagelayer-wrap-ele');
	
	if(srcParentNext.length<=0){		
		return;
	}
  
	var srcTopValue = srcParent.offset().top;
	
	if(srcParentNext.hasClass('pagelayer-wrap-ele')){
		
		var animDownCalc = srcParentNext.offset().top-srcTopValue;
	
		srcParent.animate({top:(animDownCalc-(srcParent.height()-srcParentNext.height()))}, 200, function(){
			srcParent.css('top', '');
			srcParentNext.css('top', '');
			srcParentNext.after(srcParent.detach());
		});
		
		srcParentNext.animate({top:-animDownCalc}, 200, function(){
			srcParentNext.css('top', '');
		});
		
		// Traverse window scroll with the element
		jQuery('html, body').animate({scrollTop:('+='+(animDownCalc-(srcParent.height()-srcParentNext.height())))},200);
	}else{
		srcParentNext.after(srcParent.detach());		
		
		// Traverse window scroll with the element
		jQuery('html, body').animate({scrollTop:('+='+((src.parent().offset().top)-srcTopValue))},200);
	}
	
	pagelayer_do_dirty(src);
}

// Save sections as template
function pagelayer_ajax_save_template(data, ajax_call_back = ''){

	if(pagelayer_empty(data)){
		return;
	}
	
	//save global sections and widgets
	jQuery.ajax({
		type: "POST",
		url: pagelayer_ajax_url+'&action=pagelayer_save_templ_content&postID='+pagelayer_postID,
		data: { 
			pagelayer_nonce: pagelayer_ajax_nonce,
			global_widgets : data
		},
		success: function(response, status, xhr){
			//alert(data);
			var obj = jQuery.parseJSON(response);
			if(!pagelayer_empty(ajax_call_back) || typeof ajax_call_back == 'function'){
				ajax_call_back(obj);
			}
		},
		error: function(errorThrown){
			console.log(errorThrown);
		}
	});
	
}

// Get global id of the element
function pagelayer_get_global_id(jEle){
	return pagelayer_get_att(jEle, 'global_id');
}

// Set element as a global widget
function pagelayer_set_ele_global(jEle, post_id){
	
	// Add attribute for global ID
	jEle.attr('pagelayer-global-id', post_id);
	pagelayer.history_action = false;
	pagelayer_set_atts(jEle, 'global_id', post_id);
	pagelayer.history_action = true;
	
	return jEle;
}

// Save widgets as a global widget
function pagelayer_save_sections(sel, section = 'section'){
	
	var jEle = jQuery(sel);
	
	var  pagelayer_ajax_func = {};
	var label = 'Please enter the title';
	var content = pagelayer_generate_sc(jEle, true);
	var data = {};// create array for template data
	data[0] = {};
	
	switch(section){
		
		case 'global_widget' :
			var title = prompt(label, 'Global Widget');
			if (title == null) return;
			
			// Save the widget data in global widget array 
			if(pagelayer_empty(pagelayer_global_widgets)){
				pagelayer_global_widgets = {};
			}
			
			break;
			
		case'global_section' :
			var title = prompt(label, 'Global Section');
			if (title == null) return;
			
			break;
			
		case 'section':
			var title = prompt(label, 'Section');
			if (title == null) return;
			
			break;
			
	}
	
	// Add Data
	data[0]['title'] = title;
	data[0]['post_type'] = 'pagelayer-template';
	data[0]['type'] = section; 
	data[0]['content'] = content.replace(/pagelayer-id="(.*?)"/g, ""); // Need to remove pagelayer id,
	data[0]['content'] = pagelayer_Base64.encode(data[0]['content']);
	
	// This function for ajax success call back of global widget 
	pagelayer_ajax_func['global_widget'] = function(obj){
		
		if(pagelayer_empty(obj['success'])){
			return;
		}
		
		for(var post_id in obj['success']){
			
			pagelayer_set_ele_global(jEle, post_id);
			
			// Add global
			jData = {};
			jData['post_id'] = post_id;
			jData['title'] = title; // TODO : create modal to input title
			jData['$'] = jEle;
			jData['is_dirty'] = true;
			
			// Add the array in global widgets array
			pagelayer_global_widgets[post_id] = jData;
			
			pagelayer.$$('.pagelayer-elpd-close').click();
			pagelayer.$$('.pagelayer-widget-tab').click();
			break;
		}
		
	}
	
	// This function for ajax success call back of global sections
	pagelayer_ajax_func['global_section'] = function(obj){
		// TODO: For global Sections
		//console.log(obj);
	}
	
	// This function for ajax success call back of section s
	pagelayer_ajax_func['section'] = function(obj){
		//console.log(obj);
	}
	
	pagelayer_ajax_save_template(data, pagelayer_ajax_func[section]);
	
}

// Genrate sc for global widgets
function pagelayer_generate_sc_global_widget(){
	
	var global_widgets = {};

	// Create shortcode for all the global widgets
	for(var y in pagelayer_global_widgets){
		var cWidget = pagelayer_global_widgets[y];
		
		// If is_dirty empty then continue the loop
		if(pagelayer_empty(cWidget['is_dirty'])){
			continue;
		}
		
		global_widgets[y] = {};
		global_widgets[y]['title'] = cWidget['title'];
		global_widgets[y]['post_id'] = pagelayer_empty(cWidget['post_id']) ? 0 : cWidget['post_id'];
		global_widgets[y]['post_type'] = 'pagelayer-template';
		global_widgets[y]['type'] = 'global_widget';
		
		var content = pagelayer_generate_sc(jQuery(cWidget.$), true);
		var tag = pagelayer_tag(jQuery(cWidget.$));
		
		// IF is group then need to remove pagelayer id, 
		if(!pagelayer_empty(tag) && pagelayer_is_group(tag)){
			content = content.replace(/pagelayer-id="(.*?)"/g, "");
		}
		
		global_widgets[y]['content'] = pagelayer_Base64.encode(content);
		pagelayer_global_widgets[y]['is_dirty'] = false;
	}
	
	return global_widgets;
}

var pagelayer_set_global_timmer = {};

// If you edit one Global widget it should be copied to other instances of the same global widget
function pagelayer_setup_global_widgets(id, jEle){
	
	if(pagelayer_empty(id) || pagelayer_empty(pagelayer_global_widgets[id])){
		return;
	}
	
	var elData = pagelayer_global_widgets[id];
	
	clearTimeout(pagelayer_set_global_timmer);
	pagelayer_set_global_timmer = setTimeout(function(){
		// Set attrs for all the global widgets  
		jQuery(pagelayer_editable+' [pagelayer-global-id='+ id +']').each(function(){
			
			var cEle = jQuery(this);
			var cEleID = pagelayer_id(cEle);
	
			if( jEle.length > 0 && jEle.is(cEle)){
				return true;
			}
			
			pagelayer.history_action = false;
			pagelayer.global_render = false;
			
			// Get HTML form global array
			var html = pagelayer_element_unsetup(elData.$, cEleID);
									
			if(cEle.parent().is('.pagelayer-ele-wrap')){
				cEle.parent().children('.pagelayer-ele-overlay').remove();
				cEle.unwrap();
			}
			
			cEle[0].outerHTML = html[0].outerHTML;
			
			pagelayer_element_setup('[pagelayer-id='+cEleID+'], [pagelayer-id='+cEleID+'] .pagelayer-ele');
			pagelayer_sc_render(jQuery('[pagelayer-id="'+cEleID+'"]'));
			
			pagelayer.history_action = true;
			pagelayer.global_render = true;
		});
		
	}, 3000);

}

// Language key
function pagelayer_l(k){
	if(k in pagelayer_lang){
		return pagelayer_lang[k];
	}
	return k;
}

// Get props based on the tag
function pagelayer_get_props(jEle){
	var props = pagelayer_shortcodes[pagelayer_tag(jEle)];
	return props;
}

// Get all props based on the tag but in a single structure
function pagelayer_make_props_ref(){
	
	// Loop through pagelayer_shortcodes
	for(var tag in pagelayer_shortcodes){
		
		var all_props = pagelayer_shortcodes[tag];
		pagelayer.props_ref[tag] = {};
	
		// Loop through all props
		for(var i in pagelayer_tabs){
			
			var tab = pagelayer_tabs[i];

			for(var section in all_props[tab]){
				
				var props = section in pagelayer_shortcodes[tag] ? pagelayer_shortcodes[tag][section] : pagelayer_styles[section];
					
				// In case of widgets its possible !
				if(pagelayer_empty(props)){
					continue;
				}
				
				for(var x in props){
					
					// Create an easy REFERENCE for access
					pagelayer.props_ref[tag][x] = props[x];
					
					// Screen option REFERENCE is also needed for lookup
					if('screen' in props[x]){
						pagelayer.props_ref[tag][x+'_tablet'] = props[x];
						pagelayer.props_ref[tag][x+'_mobile'] = props[x];
					}
					
				}
			}
			
		}
		
	}
	
}

// Set the given jELE as active
function pagelayer_set_active(jEle){
	
	// Make all other element as inactive
	jQuery('[pagelayer-active]').each(function(){	
		var $j = jQuery(this);
		$j.removeAttr('pagelayer-active');
	});
	
	jEle.attr('pagelayer-active', 1);
	
	// Add and remove the class
	jQuery('.pagelayer-active').removeClass('pagelayer-active');
	
	jEle.parent().children('.pagelayer-ele-overlay').addClass('pagelayer-active');
	
}

function pagelayer_sc(sc){
	return sc.replace('pl_', '');
};

// Create a HTML dom element of the Short code
// Return the jEle
function pagelayer_create_sc(sc){
	
	var html;
	var _sc = pagelayer_sc(sc);
	var func = window['pagelayer_create_sc_'+sc];
	
	// Generate the HTML
	if(typeof func == 'function'){
		html = window['pagelayer_create_sc_'+sc]();
	}else{
		html = '<div '+pagelayer_sc_atts('pagelayer-'+_sc)+'></div>';
	}
	
	html = jQuery(html);
	
	// Add the tag
	html.attr('pagelayer-tag', sc);
	
	// Give it an ID
	id = pagelayer_assign_id(html);
	
	// Try to set the default values over 5 loops
	pagelayer_set_default_atts(html, 5);
	
	return html;
	
};

// Returns a list of default attributes to set as per the current selection
function pagelayer_set_default_atts(jEle, set){
	
	set = set || 0;
	var hasSet = false;
	
	for(var i = 1; i <= set;i++){
		
		//console.log('[pagelayer_set_default_atts] Loop :'+i);
		//console.log(jEle);
		
		// Get existing data
		var el = pagelayer_data(jEle, true);
		
		// If it is the last loop and we are greater than 1
		if(i > 1 && i == set){
			console.log('[pagelayer_default_atts] Still vars to set. Please check your shortcode params !');
		}
		
		// We are supposed to set !
		if('set' in el && !pagelayer_empty(el.set)){		
			pagelayer_set_atts(jEle, el.set);
			hasSet = true;
		}else{
			break;
		}
	}
	
	return hasSet;
}

// Returns the tag
function pagelayer_tag(jEle){
	
	// It could be the wrap
	if(jEle.hasClass('pagelayer-ele-wrap')){
		return jEle.children('.pagelayer-ele').attr('pagelayer-tag');
	}
	
	// It could be the row or col holder
	if(jEle.hasClass('pagelayer-row-holder') || jEle.hasClass('pagelayer-col-holder')){
		return jEle.parent().attr('pagelayer-tag');
	}
	
	return jEle.attr('pagelayer-tag');
}

function pagelayer_el_data_ref(jEle){
	var id = pagelayer_id(jEle);
	
	if(!(id in pagelayer.el)){
		pagelayer.el[id] = {};
	}
	
	if(typeof pagelayer.el[id] !== 'object'){
		pagelayer.el[id] = {};
	}
	
	if(!('attr' in pagelayer.el[id])){
		pagelayer.el[id]['attr'] = {};
	}
	
	if(Array.isArray(pagelayer.el[id]['attr'])){
		pagelayer.el[id]['attr'] = {};
	}
	
	if(!('tmp' in pagelayer.el[id])){
		pagelayer.el[id]['tmp'] = {};
	}
	
	if(Array.isArray(pagelayer.el[id]['tmp'])){
		pagelayer.el[id]['tmp'] = {};
	}
	
	return pagelayer.el[id];
};

// Gets the data node which can be position 0 or 1
function pagelayer_el_get_data_node(jEle){
	var node = jEle[0].childNodes[0];
	if(node && node.nodeType === 8){
		return node;
	}
	node = jEle[0].childNodes[1];
	if(node && node.nodeType === 8){
		return node;
	}
	return false;
}

// Get the data
function pagelayer_el_get_data(jEle){
	var node = pagelayer_el_get_data_node(jEle);
	if(node){
		return JSON.parse(node.nodeValue);
	}	
	return false;
};

// Add the data back again
function pagelayer_el_dump_data(jEle){
	var node = pagelayer_el_get_data_node(jEle);
	var d = pagelayer_serializeAttributes(pagelayer_el_data_ref(jEle));
	
	if(node){
		node.nodeValue = d;
	}else{
		jEle.prepend('<!-- '+d+' -->');
	}
};

// Gets a single attribute value
function pagelayer_get_att(jEle, att){
	var ref_data = pagelayer_el_data_ref(jEle);
	if(att in ref_data['attr']){
		return ref_data['attr'][att];
	}
	return;
};

// Gets a single attribute value
function pagelayer_get_tmp_att(jEle, att){
	var ref_data = pagelayer_el_data_ref(jEle);
	if(att in ref_data['tmp']){
		return ref_data['tmp'][att];
	}
	return;
};

// This function will just set atts and not do anything else
// Atts can be string or object. If its string, then val is needed
function pagelayer_set_atts(jEle, atts, val){
	
	if(typeof atts == 'string'){
		var tmp = {};
		tmp[atts] = val;
		atts = tmp;
	}
	
	if(typeof atts != 'object'){
		return false;
	}
	
	var tag = pagelayer_tag(jEle);
	var trigger_onchange = 0;
	
	if(pagelayer_empty(tag)){
		console.log('Set atts found no tag');
		console.log(jEle);
		return;
	}
		
	// All props
	var all_props = pagelayer_shortcodes[tag];//console.log(tag);console.log(jEle);
	var trigger_props = {};
	var no_val = {};
	var defaults = {};
	var _props = {};
	
	// Loop through all props
	for(var i in pagelayer_tabs){
		
		var tab = pagelayer_tabs[i];

		for(var section in all_props[tab]){
			
			var props = section in pagelayer_shortcodes[tag] ? pagelayer_shortcodes[tag][section] : pagelayer_styles[section];
			
			for(var x in props){
				
				if('default' in props[x]){
					defaults[x] = 1;
				}
				
				// Create an easy REFERENCE for access
				_props[x] = props[x];
				
				// Screen option REFERENCE is also needed for lookup
				if('screen' in _props[x]){
					_props[x+'_tablet'] = props[x];
					_props[x+'_mobile'] = props[x];
				}
				
				// Dont set any val, but we set temp value
				if('no_val' in props[x]){
					no_val[x] = 1;
				}
				
				if('req' in props[x] || 'show' in props[x]){					
					var show = 'req' in props[x] ? props[x]['req'] : props[x]['show'];
					
					// We have both req and show, so lets just combine the values and then show
					// NOTE : We need to make an array and not just merge the 2 as they are references
					if('req' in props[x] && 'show' in props[x]){
						
						// Add the req values
						show = JSON.parse(JSON.stringify(props[x]['req']));
						
						// Now the show values need to be looped
						for(var t in props[x]['show']){
							show[t] = props[x]['show'][t];
						}
						
					}
					
					for(var showParam in show){
						var val = show[showParam];
						var except = showParam.substr(0, 1) == '!' ? true : false;
						showParam = except ? showParam.substr(1) : showParam;
						trigger_props[showParam] = 1;
					}
					
				}
				
			}
			
		}
		
	}
	
	var ref_data = pagelayer_el_data_ref(jEle);
	
	for(var x in atts){
		
		// Are we to trigger change
		if(x in trigger_props){
			trigger_onchange = 1;
		}
		
		//console.log(x+'-'+atts[x]);
		
		// Is this a pro feature and we are not pro ? Then we dont do anything and continue !
		if(!pagelayer_empty(_props[x]) && 'pro' in _props[x] && pagelayer_empty(pagelayer_pro)){
			continue;
		}
		
		if(x in no_val){
			pagelayer_set_tmp_atts(jEle, x, atts[x]);
			continue;
		}
		
		// Record History
		if(pagelayer.history_action){				
			var old_val = pagelayer_get_att(jEle, x) || '';
			var label = x;
			
			if(x in _props && 'label' in _props[x]){
				label = _props[x]['label'];
			}
			
			pagelayer_history_action_push({
				'title' : all_props['name'],
				'subTitle' : label,
				'action' : 'Edited',
				'attrType' : 'a_attr',
				'pl_id' : pagelayer_id(jEle),
				'atts' : x,
				'oldVal' : old_val,
				'newVal' : atts[x]
			});
		}
		
		// Remove the attribute if its BLANK and there is no default for it
		// If there is a default, we set it to blank to keep record of the current val
		if(pagelayer_length(atts[x]) < 1){
			
			// Remove values which are not defaults
			if(!(x in defaults)){
				delete ref_data['attr'][x];
			// Otherwise keep value set for avoiding resetting
			}else{
				ref_data['attr'][x] = atts[x];
			}
			
			// Remove the tmp atts anyway
			pagelayer_clear_tmp_atts(jEle, x);
		
		// Set the value
		}else{
			ref_data['attr'][x] = pagelayer_trim(atts[x]);
		}
		
		// Are you the active element
		if(pagelayer_is_active(jEle)){
			
			// TODO : Record Undo and Redo
			
		}
		
	}
	
	pagelayer_el_dump_data(jEle);
	
	// Trigger the change of the parameter and show the required properties
	if(trigger_onchange){
		pagelayer_elpd_show_rows();
	}
	
	pagelayer_do_dirty(jEle);
  
};

// This function will just set atts and not do anything else
// Atts can be string or object. If its string, then val is needed
function pagelayer_set_tmp_atts(jEle, atts, val){
	
	if(typeof atts == 'string'){
		var tmp = {};
		tmp[atts] = val;
		atts = tmp;
	}
	
	if(typeof atts != 'object'){
		return false;
	}
	
	var ref_data = pagelayer_el_data_ref(jEle);
	
	for(var x in atts){
		
		// Record history
		if(pagelayer.history_action){
				
			var old_val = pagelayer_get_tmp_att(jEle, x) || '';
			pagelayer_history_action_push({
				'title' : pagelayer_shortcodes[pagelayer_tag(jEle)]['name'],
				'subTitle' : x,
				'action' : 'Edited',
				'attrType' : 'tmp_attr',
				'pl_id' : pagelayer_id(jEle),
				'atts' : x,
				'oldVal' : old_val,
				'newVal' : atts[x]
			});
			
		}
		
		ref_data['tmp'][x] = atts[x];
		
	}
	
	pagelayer_el_dump_data(jEle);
	
};

// This function removes the temporary attributes of an ele
function pagelayer_clear_tmp_atts(jEle, attr){
	
	var to_del = new Array();
	var regexp = new RegExp('^'+attr+'\-', 'gi');
	var ref_data = pagelayer_el_data_ref(jEle);
	
	//console.log(to_del);
	for(var n in ref_data['tmp']){
		if(n.match(regexp)){
			delete ref_data['tmp'][n];
		}
	}
}

// This function removes the temporary attributes of an ele
function pagelayer_img_tmp_atts(jEle, attr){
	
	var found = {};
	var regexp = new RegExp('^'+attr+'\-', 'gi');
	var ref_data = pagelayer_el_data_ref(jEle);
	
	for(var n in ref_data['tmp']){
		if(n.match(regexp)){
			found[n] = 1;
		}
	}
	
	return found;
}

// Set the att and classes of an HTML which is not yet created
function pagelayer_sc_atts(classes){	
	var r = new Array();	
	return 'class="'+classes+' pagelayer-ele" '+r.join(' ');
}

// Is the jEle the active element ?
function pagelayer_is_active(jEle){
	
	// Is this the active Element ?
	if(pagelayer_empty(pagelayer_active.el) || jEle.attr('pagelayer-id') != pagelayer_active.el.id){
		return false;
	}
	
	return true;
	
};

// Removes {{}} from the variable name
function pagelayer_var(val){
	return val.substring(2, (val.length - 2));
}

// Take care of the CSS
function pagelayer_css_render(css, val, seperator){
	//console.log('CSS '+css+' | '+val);
	
	// Seperator
	seperator = seperator || ',';
	
	var replaceCss = function(rule, value, toreplace){
		
		value = pagelayer_hex8_to_rgba(value);
		
		// If value has css var then we remove units
		if(value.match(/var\(/)){
			var toreplace = toreplace.replace(/[-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
			toreplace  = new RegExp( toreplace+'?[^\\s|;]+', 'ig');
		}
		
		return rule.split(toreplace).join(value);
	}
	
	// Replace the val
	css = replaceCss(css, val, '{{val}}');
	
	// If there is an array
	if(css.match(/val\[\d/)){
		
		if(typeof val != 'object' || val === null){
			val = String(val).split(seperator);
		}
		
		for(var i in val){
			css = replaceCss(css, val[i], '{{val['+i+']}}');
		}
	}
	
	//console.log('Final CSS '+css);
	
	return css;
	
};

// Handle hexa to rgba and also remove alpha which is ff
function pagelayer_hex8_to_rgba(val){
	
	val = String(val);
	
	// If opacity is ff then discard ff
	if(val.match(/^#([a-f0-9]{6})ff$/)){
		return val.substr(0,7);
	}
	
	// Lets handle the RGB+opacity
	if(val.match(/^#([a-f0-9]{8})$/)){
		var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(val);
		val = 'rgba('+parseInt(result[1], 16)+', '+parseInt(result[2], 16)+', '+parseInt(result[3], 16)+', '+(parseInt(result[4], 16)/255).toFixed(2)+')';
	}
	
	return val;
	
};

// Replace the variables
function pagelayer_parse_el_vars(str, el){
	
	str = str.split('{{element}}').join(el.CSS.cssSel);
	str = str.split('{{wrap}}').join(el.CSS.wrap);
	str = str.split('{{ele_id}}').join(el.id);
	
	return str;

}

// Replace the variables
function pagelayer_parse_vars(str, el){
	
	for(var x in el.tmp){
		str = str.split('{{{'+x+'}}}').join(el.tmp[x]);
	}
	
	for(var x in el.atts){
		str = str.split('{{'+x+'}}').join(el.atts[x]);
	}
	
	return str;
};

// Render the Element
function pagelayer_sc_render(jEle){
	
	// We render only the active element
	if(!pagelayer_is_active(jEle)){
		//return false;
	}
	
	//console.log('Rendering');
	
	// Handle the CSS part
	// Get the id, tag, atts, data, etc
	var el = pagelayer_data(jEle, true);
	var all_props = pagelayer_shortcodes[el.tag];
	var elCSS = {
		classes: [],
		remove_classes: [],
		attr: [],
		remove_attr: [],
		css: [],
		edit: [],
		cssSel: '.p-'+el.id,
		sel: '[pagelayer-id="'+el.id+'"]',
		wrap: '[pagelayer-wrap-id="'+el.id+'"]'
	};
	
	// Create a reference
	el.CSS = elCSS;
  
	// Make sure if we have the class selector
	el.$.addClass('p-'+el.id);
	
	//console.log(el.atts);
	
	for(var i in pagelayer_tabs){
		var tab = pagelayer_tabs[i];
		for(var section in all_props[tab]){	//console.log(tab+' '+section);
	
			var props = section in pagelayer_shortcodes[el.tag] ? pagelayer_shortcodes[el.tag][section] : pagelayer_styles[section];//console.log(props);
	
			// Loop the props
			for(var x in props){
				
				// pagelayer_data will return attributes even if they are BLANK e.g. attr=""
				// Render doesnt consider BLANK values as values, and we are unsetting them now
				// If in any situation you need to consider blank values, please handle in the JS / PHP function of the Shortcode
				if(x in el.atts && pagelayer_length(el.atts[x]) < 1){
						delete el.atts[x];
				}
				
				// Any editor ?
				if('edit' in props[x]){
					elCSS.edit.push({prop: x, sel: props[x]['edit']});
				}
				
				// Load permalink values
				if(props[x]['type'] == 'link'){

					if('selector' in props[x] && typeof el.atts[x] == 'object'){
						var tmp = {};
						
						// Link is required for check IF and IF-EXT in html
						if(pagelayer_length(el.atts[x]['link'])  < 1){
							delete el.atts[x];
							continue;
						}
						
						if( 'target' in el.atts[x] && !pagelayer_empty(el.atts[x]['target']) ){
							tmp = {'sel': props[x]['selector'], 'val': 'target="_blank"'};
							elCSS['attr'].push(tmp);
						}
						
						if( 'rel' in el.atts[x] && !pagelayer_empty(el.atts[x]['rel']) ){
							tmp = {'sel': props[x]['selector'], 'val': 'rel="nofollow"'};
							elCSS['attr'].push(tmp);
						}

						if( 'attrs' in el.atts[x] && !pagelayer_empty(el.atts[x]['attrs']) ){

							var attrsVal = pagelayer_trim(el.atts[x]['attrs'].split(';'));
			
							attrsVal.forEach(function(item, index){
                  
								var splitValue = item.split(/=(.*)/);
								var attKey = pagelayer_trim(splitValue[0]);
								var setAtt = '';
									
								// Validate the attrs name 
								if(attKey.length < 1 || pagelayer_empty(attKey.match(/^[a-z_]+[\w:.-]*$/i))){
									return;
								}
									
								if(splitValue.length < 2){
									setAtt = attKey+'=""';
								}else{
									setAtt = attKey+'="'+splitValue[1]+'"';
								}
									
								tmp = {'sel': props[x]['selector'], 'val': setAtt};
								elCSS['attr'].push(tmp);
									
							});
						}
					}
				}
				
				// Do we have a addClass ?
				// We are checking before the element has a value so that we can add or remove the class
				if('addClass' in props[x]){
					
					var addClasses;
					
					// Convert the string to an array
					if(typeof props[x]['addClass'] === 'string'){
						addClasses = [props[x]['addClass']];
					}else{
						addClasses = props[x]['addClass'];
					}
					
					for(var c in addClasses){
							
						// The selector
						var tSel = jQuery.isNumeric(c) ? '' : c;
						
						// If there is a VAL
						// NOTE : Only val is allowed when there is a list
						if(addClasses[c].match(/\{\{val\}\}/) && 'list' in props[x]){
							
							for(var l in props[x]['list']){
								
								var tmp = {'sel': tSel, 'val': addClasses[c].replace('{{val}}', l)};
								
								if(el.atts[x] == l){
									elCSS['classes'].push(tmp);
								}else{
									elCSS['remove_classes'].push(tmp);
								}
								
							}
							
						}else{
							
							var tmp = {'sel': tSel, 'val': addClasses[c].replace('{{val}}', el.atts[x])};
							
							// If the value is there
							if(x in el.atts){
								elCSS['classes'].push(tmp);
							}else{
								elCSS['remove_classes'].push(tmp);
							}
						
						}
					}
				}
				
				// Do we have a addAttr ? 
				// We are checking before the element has a value so that we can add or remove the attr
				if('addAttr' in props[x]){
					
					var addAttr;
					
					// Convert the string to an array
					if(typeof props[x]['addAttr'] === 'string'){
						addAttr = [props[x]['addAttr']];
					}else{
						addAttr = props[x]['addAttr'];
					}
					
					for(var c in addAttr){
							
						// The selector
						var tSel = jQuery.isNumeric(c) ? '' : c;
						var tmp = {'sel': tSel, 'val': addAttr[c]};
						
						// If the value is there
						if(x in el.atts){
							elCSS['attr'].push(tmp);
						}else{
							elCSS['remove_attr'].push(tmp);
						}
					}
				}
				
				// Do we have a CSS ? 
				if('css' in props[x]){
					
					var css;
	
					// Convert the string to an array
					if(typeof props[x]['css'] === 'string'){
						css = [props[x]['css']];
					}else{
						css = props[x]['css'];
					}
					
					// Screen modes
					var modes = {desktop: '', tablet: '_tablet', mobile: '_mobile'};
					var desk_global = (props[x]['type'] == 'typography') ? pagelayer_is_global_typo(el.atts[x]) : '';
					
					for(var m in modes){
						
						var xm = x+modes[m];
						
						// If the value is there
						if(!(xm in el.atts) && pagelayer_empty(desk_global)){
							continue;
						}
						
						var xm_val = el.atts[xm];
						
						// If is global color
						if(props[x]['type'] == 'color'){
							xm_val = pagelayer_parse_color(el.atts[xm]);
						}
						
						// If is global font
						if(props[x]['type'] == 'typography'){
							xm_val = pagelayer_parse_typo(xm_val, false, desk_global, m);
						}
						
						// If there is global gradient color
						if(props[x]['type'] == 'gradient'){
							
							if(pagelayer_is_string(xm_val)){
								xm_val = xm_val.split(',');
							}
							
							for(key in xm_val){								
								xm_val[key] = pagelayer_parse_color(xm_val[key]);
							}
							
						}
						
						for(var c in css){
								
							// The selector
							var tSel = jQuery.isNumeric(c) ? '{{element}}' : c;
							var tmp = {
								sel: tSel, 
								val: pagelayer_css_render(css[c], xm_val, (props[x].sep || ',')),
							};
							
							// Is this a tablet
							if(m == 'tablet'){
								tmp.sel = '@media (max-width: '+ pagelayer_settings['tablet_breakpoint'] +'px) and (min-width: '+ (pagelayer_settings['mobile_breakpoint'] +1) +'px){'+tmp.sel;
								tmp.val = tmp.val+'}';
							}
							
							// Is this a mobile mode ?
							if(m == 'mobile'){
								tmp.sel = '@media (max-width: '+ pagelayer_settings['mobile_breakpoint'] +'px){'+tmp.sel;
								tmp.val = tmp.val+'}';
							}
							
							// Push to store
							elCSS.css.push(tmp);
						}
					
					}
					
				}
				
			}
			
		}
		
	}
	
	// If there is an HTML, then process it
	if('html' in pagelayer_shortcodes[el.tag]){
	
		// Is there a function to render ?
		var fn = window['pagelayer_render_'+jEle.attr('pagelayer-tag')];
		
		if(typeof fn == 'function'){
			fn(el);
		}
		
		el.iHTML = jQuery('<div>'+pagelayer_shortcodes[el.tag]['html']+'</div>');
		
		// Lets process the 'if-ext'
		el.iHTML.find('[if-ext]').each(function (){
			var $j = jQuery(this);
			var reqvar = pagelayer_var($j.attr('if-ext'));
			$j.removeAttr('if-ext');
			
			// Is the element there ?
			if(!(reqvar in el.atts && !pagelayer_empty(el.atts[reqvar]))){
				//console.log('HERE');
				$j[0].outerHTML = $j.html();
			}
			
		});
		
		// Lets process the 'if'
		el.iHTML.find('[if]').each(function (){
			var $j = jQuery(this);
			var reqvar = pagelayer_var($j.attr('if'));
			$j.removeAttr('if');
			
			// Is the element there ?
			if(!(reqvar in el.atts && !pagelayer_empty(el.atts[reqvar]))){
				//console.log('HERE');
				$j.remove();
			}
			
		});
		
		//console.log(el.atts);
		
		// Parse the variables
		var new_html = pagelayer_parse_vars(el.iHTML.html(), el);
		el.iHTML.html(new_html);
		
		// Do we have to wrap the innerHTML ?
		if('holder' in pagelayer_shortcodes[el.tag]){
			
			var hSel = pagelayer_shortcodes[el.tag]['holder'];
			var holder = jEle.find(hSel).first();
			
			// Detach the holder
			holder.detach();
			
			// Add the new HTML
			el.$.html(el.iHTML.html());
			
			// reAttach the children only
			el.$.find(hSel).html(holder.children());
		
		// No holder
		}else{
		
			//console.log(el.iHTML.html());
			el.$.html(el.iHTML.html());
		
		}
		
	// Rows, Cols and Groups
	}else{
	
		// Is there a function to render ?
		var fn = window['pagelayer_sc_render_'+jEle.attr('pagelayer-tag')];
		
		if(typeof fn == 'function'){
			fn(el);
		}
		
	}
	
	// Is there a function to render after HTML insertion but before CSS and attr ?
	var post = window['pagelayer_render_html_'+jEle.attr('pagelayer-tag')];
	
	if(typeof post == 'function'){
		post(el);
	}
	
	////////////////////////////
	// Are there any edit fields ?
	////////////////////////////
	
	if(elCSS.edit.length > 0){
		
		for(var c in elCSS.edit){
			var prop = elCSS.edit[c]['prop'];
			var tSel = elCSS.edit[c]['sel'];
			var node = tSel.length < 1 ? jEle : jEle.find(tSel);
			node.attr({'pagelayer-editable': prop, 'contenteditable' : 'true'});
		}
		
	}
	
	////////////////////////////
	// Are there any addClass ?
	////////////////////////////
	
	// If we have any classes to add
	if(elCSS.classes.length > 0){
		//console.log(elCSS.classes);
		
		for(var c in elCSS.classes){
			var tSel = elCSS.classes[c]['sel'].replace('{{element}}', '');
			var node = tSel.length < 1 ? jEle : jEle.find(tSel);
			if(!node.hasClass(elCSS.classes[c]['val'])){
				node.addClass(elCSS.classes[c]['val']);
			}
		}
	}
	
	// If we have any classes to remove
	if(elCSS.remove_classes.length > 0){
		//console.log(elCSS.remove_classes);
		
		for(var c in elCSS.remove_classes){
			var tSel = elCSS.remove_classes[c]['sel'].replace('{{element}}', '');
			var node = tSel.length < 1 ? jEle : jEle.find(tSel);
			if(node.hasClass(elCSS.remove_classes[c]['val'])){
				node.removeClass(elCSS.remove_classes[c]['val']);
			}
		}
	}
	
	////////////////////////////
	// Are there any addAttr ?
	////////////////////////////
	
	// If we have any attributes to add
	if(elCSS.attr.length > 0){
		//console.log(elCSS.attr);
		
		for(var c in elCSS.attr){
			var tSel = elCSS.attr[c]['sel'].replace('{{element}}', '');
			var node = tSel.length < 1 ? jEle : jEle.find(tSel);
			var att = elCSS.attr[c]['val'].split(/=(.*)/);
			att[1] = pagelayer_parse_vars(att[1], el);
			att[1] = pagelayer_trim(att[1], '"');
			
			// Is it the same val ?
			if(!node.attr(att[0]) !== att[1]){
				node.attr(att[0], att[1]);
			}
		}
	}
	
	// If we have any attributes to add
	if(elCSS.remove_attr.length > 0){
		//console.log(elCSS.remove_attr);
		
		for(var c in elCSS.remove_attr){
			var tSel = elCSS.remove_attr[c]['sel'].replace('{{element}}', '');
			var node = tSel.length < 1 ? jEle : jEle.find(tSel);
			var att = elCSS.remove_attr[c]['val'].split('=');
			
			if(node.is('['+att[0]+']')){
				node.removeAttr(att[0]);
			}
		}
	}
	
	// The style element
	var style = pagelayer.$('[pagelayer-style-id='+el.id+']');
	
	// If we have any RULES CSS, then handle it
	if(elCSS.css.length > 0){
		
		// Did we find it ?
		if(style.length < 1){
			jEle.prepend('<style pagelayer-style-id="'+el.id+'"></style>');
		}
		
		// Get it again
		style = pagelayer.$('[pagelayer-style-id='+el.id+']');
		
		// Make the rules
		var rules = [];
		
		// Loop
		for(var c in elCSS.css){
			var tSel = pagelayer_parse_el_vars(elCSS.css[c]['sel'], el);
			var rule = elCSS.css[c]['val'];
			if(tSel.length > 0){
				rules.push(tSel+'{'+rule+'}');
			}else{
				rules.push(pagelayer_parse_el_vars(rule, el));
			}
		}
	
		// CSS Selector overide
		if(!pagelayer_empty(all_props['overide_css_selector'])){
			for(var r in rules){
				var overide_css_selector = pagelayer_parse_el_vars(all_props['overide_css_selector'], el);
				rules[r] = rules[r].split(el.CSS.cssSel).join(overide_css_selector);
				rules[r] = rules[r].split(el.CSS.wrap).join(overide_css_selector);
			}
		}
		
		// Set the style
		style.html(pagelayer_parse_vars(rules.join("\n"), el));
		//console.log(style);
	}else{
		style.remove();
	}
	
	// Is there a function to render at the end ?
	var end = window['pagelayer_render_end_'+jEle.attr('pagelayer-tag')];
	
	if(typeof end == 'function'){
		end(el);
	}
	
	// If the element have any parent
	var par = pagelayer_get_parent(jEle);
	var eleId = el.id;

	if(par){
		eleId = par;
		pagelayer_sc_render(pagelayer_ele_by_id(par));
	}
	
	// Render End trigger
	pagelayer_trigger_action('pagelayer_sc_render_end', [el]);
		
	var gEle = pagelayer_ele_by_id(eleId);
	var gId = pagelayer_get_global_id(gEle);
		
	pagelayer_el_dump_data(jEle);

	// If global id exist then update the global array and restup the all global element
	if(!pagelayer_empty(gId) && !pagelayer_empty(pagelayer.global_render)){
		if(!pagelayer_empty(pagelayer_global_widgets[gId])){
			pagelayer_global_widgets[gId].$ = gEle[0].outerHTML;
			pagelayer_global_widgets[gId]['is_dirty'] = true;
			pagelayer_setup_global_widgets(gId, pagelayer_ele_by_id(eleId), true);
		}else{
			pagelayer_set_atts(gEle, 'global_id', '');
		}
	};
		
};

// Is the given global color
function pagelayer_is_global_color(color){
	
	var color_key = color.substr(0, 1) == '$' ? color.substr(1) : '';
	
	// If global color not exist
	if(!pagelayer_empty(color_key)){
		
		if(!(color_key in pagelayer_global_colors)){
			color_key = 'primary';
		}
		
		return color_key;
	}
	
	return false;
	
}

// Is the given global color
function pagelayer_is_global_typo(value){
	
	var typo_key = '';
	
	// Backward compatibility
	if(pagelayer_is_string(value) && value.substr(0, 1) == '$'){
		typo_key = value.substr(1);
	}
	
	if(typeof value == 'object' && 'global-font' in value){
		typo_key = value['global-font'];
	}
		
	// If global color not exist
	if(!pagelayer_empty(typo_key) && !(typo_key in pagelayer_global_fonts)){
		typo_key = 'primary';
	}
	
	return typo_key;
	
}

// Parse typography and handle Backward compatibility
function pagelayer_parse_typo(value, noglobal, desk_global, mode){
	
	noglobal = noglobal || false;
	mode = mode || 'desktop';
	desk_global = desk_global || '';
	
	if(pagelayer_empty(value)){
		value = {};
	}
	
	// Backward compatibility for comma seperated val
	if(pagelayer_is_string(value) && value.substr(0, 1) != '$'){
		return value.split(',');
	}
	
	var val = ['','','','','','','','','','',''];
	var typos = ['font-family', 'font-size', 'font-style', 'font-weight', 'font-variant', 'text-decoration-line', 'text-decoration-style', 'line-height', 'text-transform', 'letter-spacing', 'word-spacing'];
	
	var global_typo = pagelayer_is_global_typo(value);
	var _desk_global = false;
	
	if(pagelayer_empty(global_typo)){
		global_typo = desk_global;
		_desk_global = true;
	}
	
	// Apply global typo
	for(var typo in typos){
		
		var typoKey = typos[typo];
		
		// Backspace compatibility for normal array
		if(typeof value == 'object' && !pagelayer_empty(value[typo])){
			val[typo] = value[typo];
		}
		
		if(!pagelayer_empty(value[typoKey])){
			val[typo] = value[typoKey];
		}
		
		if(pagelayer_empty(global_typo) || !pagelayer_empty(val[typo]) || noglobal){
			continue;
		}
		
		var globalVal = pagelayer_global_fonts[global_typo]['value'];
		
		if( !(typoKey in globalVal) || pagelayer_empty(globalVal[typoKey]) || (typeof globalVal[typoKey] == 'object' && pagelayer_empty(globalVal[typoKey][mode])) || (typeof globalVal[typoKey] != 'object' && !pagelayer_empty(_desk_global) && mode != 'desktop') ){
			continue;
		}
		
		val[typo] = 'var(--pagelayer-font-'+global_typo+'-'+typoKey+')';
	}
	
	return val;
}

// Parse color for global color
function pagelayer_parse_color(value, glob_var = true){
		
	var is_global = pagelayer_is_global_color(value);
	if(pagelayer_empty(is_global)){
		return value;
	}
	
	if(pagelayer_empty(glob_var)){
		return pagelayer_global_colors[is_global]['value'];
	}
	
	return 'var(--pagelayer-color-'+is_global+')';
}

// Is the given tag a group
function pagelayer_is_group(tag){
	
	if('has_group' in pagelayer_shortcodes[tag] && !pagelayer_empty(pagelayer_shortcodes[tag]['has_group'])){
		return true;
	}
	
	return false;
	
}

// Do action / event
function pagelayer_trigger_action(act, param = []){
	jQuery(document).trigger(act, param);
}

// Perform a function on an action / event
function pagelayer_add_action(act, func){
	jQuery(document).on(act, func);
}

// Create array of the contact from template params 
function pagelayer_get_contact_templates(){
	
	var contacts = jQuery(pagelayer_editable+' [pagelayer-tag=pl_contact]');
	var contacts_props = {};
	if(contacts.length > 0){
		
		contacts.each(function(){
			
			var tmp = pagelayer_data(jQuery(this));
			var con_allowed = ['to_email', 'from_email', 'cont_subject', 'cont_header', 'cont_body', 'cont_use_html'];
			
			if(pagelayer_empty(tmp.atts['contact_custom_templ'])) return true;
			
			// Define blank array
			contacts_props[tmp.id] = {};
			
			for(var x in con_allowed){
				var key = con_allowed[x];
				if(!pagelayer_empty(tmp.atts[key])){
					contacts_props[tmp.id][key] = tmp.atts[key];
				}
			}
			
		});
	}
	
	return contacts_props;
}

// Save data or meta of the post
function pagelayer_update_post_data(){
	
	var tag = 'pl_post_props';
	var jEle = jQuery(pagelayer_editable+' [pagelayer-tag="'+tag+'"]');
  
	if(jEle.length < 1){
		return;
	}

	var tmp = pagelayer_data(jEle, true);
	var all_props = pagelayer_shortcodes[tag];
	
	// Loop through all props
	for(var i in pagelayer_tabs){
		
		var tab = pagelayer_tabs[i];

		for(var section in all_props[tab]){
			
			var props = section in pagelayer_shortcodes[tag] ? pagelayer_shortcodes[tag][section] : pagelayer_styles[section];
			
			for(var x in props){
				//Set pagelayer POST data to send with save ajax
				if(x in tmp['atts']){
					pagelayer_ajax_post_data[x] = tmp['atts'][x];  
				}else if(x in pagelayer_ajax_post_data){
					delete pagelayer_ajax_post_data[x];
				}
			}
		}
	}
}

// Get the nav menu updated data 
function pagelayer_get_nav_items(jEle, _content){
	
	_content = _content || false;
	
	var pagelayer_nav_items = {};
	
	jEle.find('[pagelayer-tag="pl_nav_menu_item"]').each(function(){
		var cEle = jQuery(this),
		postID = pagelayer_get_att(cEle, 'ID');		
		
		if(!(postID in pagelayer_menus_items_ref)){
			return;
		}
		
		var ref_data = pagelayer_menus_items_ref[postID];
		
		if(!('pagelayer_content' in ref_data) && pagelayer_empty(ref_data['pagelayer_content'])){
			ref_data['pagelayer_content'] = cEle;
		}
		
		if(!('is_dirty' in ref_data) || pagelayer_empty(ref_data['is_dirty'])){
			return;
		}
		
		var content = '',
		tmp = {};
		tmp = Object.assign(tmp, ref_data);
		pagelayer_nav_items[postID] = {};
		
		// Update Mega menu content
		if(!pagelayer_empty(_content)){
			var navItem = jQuery(ref_data['pagelayer_content'])[0].outerHTML;
			var _navItem = jQuery(navItem);
			
			// If is not mega menu
			if('menu_type' in tmp && tmp['menu_type'] != 'mega'){
				_navItem.find('.pagelayer-menu-item-holder').empty();
			}
			
			content = pagelayer_generate_sc(_navItem, true);
			content = pagelayer_Base64.encode(content);
			
			// Send data to save
			var allowed_post = ['title'];
			
			for(var key in allowed_post){
				
				var post_prop = allowed_post[key];
				
				if(!(post_prop in tmp)){
					continue;
				}
				
				pagelayer_nav_items[postID][post_prop] = tmp[post_prop]
			}
			
		}else{
			pagelayer_nav_items[postID] = tmp;
		}
		
		// Delete the html content
		delete tmp['pagelayer_content'];
		
		pagelayer_nav_items[postID]['_pagelayer_content'] = content;
		
	});
	
	return pagelayer_nav_items;
}

// Save data or meta of the nav post
function pagelayer_update_nav_menu_data(){
	
	var tag = 'pl_wp_menu';
	
	pagelayer_ajax_post_data['pagelayer_nav_items'] = {};
	
	jQuery(pagelayer_editable+' [pagelayer-tag="'+tag+'"]').each(function(){
		
		var jEle = jQuery(this);
		var menu_ID = pagelayer_get_att(jEle, 'nav_list');		
		
		if(!pagelayer_empty(pagelayer_ajax_post_data['pagelayer_nav_items'][menu_ID])){
			return;
		}
		
		// Get the Current menu items
		var items = pagelayer_get_nav_items(jEle, true);
		
		if(pagelayer_empty(items)){
			return;
		}
		
		pagelayer_ajax_post_data['pagelayer_nav_items'][menu_ID] = items;  
			
	});
}

// Save the customizer settings
function pagelayer_update_customizer_settings(){
	
	var tag = 'pl_customizer';
	var jEle = jQuery(pagelayer_editable+' [pagelayer-tag="'+tag+'"]');
  
	if(jEle.length < 1){
		return;
	}

	var tmp = pagelayer_data(jEle, true);
	pagelayer_ajax_post_data['pagelayer_customizer_options'] = JSON.stringify(tmp['atts']);

}

// Save the post
function pagelayer_save(){
	
	// hiding and showing loading animation	
	pagelayer.$$('.pagelayer-update-text').hide();
	pagelayer.$$('.pagelayer-update-loader').show();
	
	pagelayer_trigger_action('pagelayer_save');
	
	var pagelayerajaxurl = pagelayer_ajax_url+'&action=pagelayer_save_content&postID='+pagelayer_postID;
	var post = pagelayer_generate_sc(pagelayer_editable);//alert(post);return;
	
	// Update data or meta of the post
	pagelayer_update_post_data();
  
	// Update Customizer Settings
	pagelayer_update_customizer_settings();

	// Update nav menu
	pagelayer_update_nav_menu_data();

	if(pagelayer_empty(pagelayer.post_status) && !pagelayer_empty(pagelayer_ajax_post_data['post_status'])){
		pagelayer.post_status = pagelayer_ajax_post_data['post_status'];
	}
  
	// Do we have contact templates ?
	var contacts_props = pagelayer_get_contact_templates();
	
	// Do we have any global widget to save ?
	var global_data  = {};
	
	if(!pagelayer_empty(pagelayer_global_widgets)){
		global_data = pagelayer_generate_sc_global_widget();
	}
	
	var cancel =  function(){
		pagelayer.$$('.pagelayer-update-text').show();
		pagelayer.$$('.pagelayer-update-loader').hide();
	}
	
	var save = function(){
		var post_data = {
			pagelayer_update_content : pagelayer_Base64.encode(post),
			pagelayer_nonce: pagelayer_ajax_nonce,
			global_widgets: global_data,
			contacts: contacts_props,
			post_status: pagelayer.post_status,
			copyright: pagelayer_copyright
		}
		
		post_data = Object.assign(pagelayer_ajax_post_data, post_data);
		
		jQuery.ajax({
			type: "POST",
			url: pagelayerajaxurl,
			data: post_data,
			success: function(response, status, xhr){
				//alert(data);
				var obj = jQuery.parseJSON(response);
				//alert(obj);
				if(obj['error']){
					pagelayer_show_msg(obj['error'], 'error', 10000);
				}else{
					pagelayer_show_msg(obj['success'], 'success', 10000);
					pagelayer_get_revision();
					
					// Update the post status in the post_props, but first find if its actually there !
					var jEle = jQuery(pagelayer_editable).find("[pagelayer-tag=pl_post_props]");
					if(jEle.length > 0){
						var id = pagelayer_id(jEle);
						pagelayer_set_atts(jEle, 'post_status', obj['post_status']);
						pagelayer_trigger_action('pagelayer_save_success', obj['post_status']);
					}
					
					pagelayer_do_undirty();					
				}
			},
			error: function(jqXHR, textStatus, errorThrown){
				console.log(errorThrown);
				pagelayer_show_msg('An error occured while saving ! Status : '+textStatus+' and Error : '+errorThrown, 'error', 10000);
			},
			complete: function(xhr,status){
				pagelayer.$$('.pagelayer-update-text').show();
				pagelayer.$$('.pagelayer-update-loader').hide();
				
				if(!pagelayer_empty(pagelayer.post_status)){
					pagelayer.$$('.pagelayer-props-modal .pagelayer-meta-iframe').attr('src', pagelayer_post_props );
					pagelayer.post_status = '';
				}
			}
		});
	}
	
	// If the content is empty
	if(pagelayer_empty(post)){
		pagelayer_confirmation_box(pagelayer_l('empty_post_content'), save, cancel);
		return;
	}
	
	save();
};

//Close the Editor
function pagelayer_close(){
	if(pagelayer_isDirty == true){
		var r =	confirm('Your Data has not been Saved yet! \n Press OK to stay on the Page.'+
		'\n Press Cancel to Close Editor. ');
		if(r == false){
			window.top.location.href = pagelayer_returnURL;
		}
	}else{
		window.top.location.href = pagelayer_returnURL;
	}
};
	
function pagelayer_htmlEntities(str) {
	return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}

function pagelayer_serializeAttributes(attributes) {
  return JSON.stringify(attributes) // Don't break HTML comments.
  .replace(/--/g, "\\u002d\\u002d") // Don't break non-standard-compliant tools.
  .replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026") // Bypass server stripslashes behavior which would unescape stringify's
  // escaping of quotation mark.
  // See: https://developer.wordpress.org/reference/functions/wp_kses_stripslashes/
  .replace(/\\"/g, "\\u0022");
}

// Generate blocks Post to save
function pagelayer_generate_sc(selector, selfEle){
	
	selfEle = selfEle || false;
	var txt = '';
	
	var generate_sc_single = function(jEle){
		
		// The ID
		var id = jEle.attr('pagelayer-id');
		
		// If there is an Add element wrapper
		if(pagelayer_empty(id)){
			return;
		}
		
		// Find the type of tag
		var tag = jEle.attr('pagelayer-tag');
		var final_tag = tag;
		var closestEle = jEle.closest('.pagelayer-col-holder');
		
		// Skip to create shortcode to prevent save, allowed by tag
		if('skip_save' in pagelayer_shortcodes[tag] && !pagelayer_empty(pagelayer_shortcodes[tag]['skip_save'])){
			return;
		}
		
		// Define inner row | Note : Commented as we now have a new widget of type inner_row
		/*if(tag == 'pl_row' && closestEle.length > 0 && closestEle.closest(pagelayer_editable).length > 0){
			final_tag = 'pl_inner_row';
		}*/
		
		if(pagelayer_empty(tag)){
			var err = 'Found an error in the content as the TAG was missing. The console will have more details.';
			pagelayer_show_msg(err, 'error');
			console.log(err);
			console.log(jEle);
		}

		// Define inner column
		if(tag == 'pl_col' && closestEle.length > 0 && closestEle.closest(pagelayer_editable).length > 0){
			final_tag = 'pl_inner_col';
		}
		//console.log(tag);
		
		// Is there an innerHTML ele
		var inner = '';
		if('innerHTML' in pagelayer_shortcodes[tag]){
			inner = pagelayer_shortcodes[tag]['innerHTML'];
		}
		
		// Data reference
		var ref_data = pagelayer_el_data_ref(jEle);
		
		// Create the tag
		var data = JSON.parse(JSON.stringify(ref_data['attr']));
		
		data['pagelayer-id'] = id;
		data = pagelayer_serializeAttributes(data);
				
		var content = '';
		
		// Any internal function to handle the save ?
		var func = window['pagelayer_tag_'+tag];
		if(typeof func == 'function'){
			
			content = func(jEle);
			
		// If its a Row or Column or Group then it will have children
		}else if(jEle.hasClass('pagelayer-row') || jEle.hasClass('pagelayer-col') || jEle.hasClass('pagelayer-inner_row') || pagelayer_is_group(tag)){
			
			var sel = jEle;
			
			// Any holder which holds children ?
			if('holder' in pagelayer_shortcodes[tag]){
				sel = jEle.find(pagelayer_shortcodes[tag]['holder']);
			}
			
			// Select the top-most element
			sel = jQuery(sel).first();
			
			// Any child selector - Majorly for owl carousel
			// NOTE : Child selector should be very specific with immediate child selection at all levels
			var child_selector = false;			
			if('child_selector' in pagelayer_shortcodes[tag]){
				childSel = sel.find(pagelayer_shortcodes[tag]['child_selector']);
				
				if(childSel.length > 0){
					sel = childSel;
				}
			}
						
			if(jQuery(sel).children(".pagelayer-ele-wrap").length < 1){
				content = jQuery(sel).html(); // Backward Compatibility
			}else{
				content = pagelayer_generate_sc(sel);
				content = "\n"+content;
			}
		
		// Its a normal element so we might need to handle the content
		}else{
			
			if(inner.length > 0){
				content = pagelayer_get_att(jEle, inner);
				if(!content){
					content = '';
				}
			}else{
				content = '';//jEle.html();
			}
			
		}
		
		// Leaving HTML and non-pagelayer supported content intact 
		if(final_tag == 'pl_missing'){
			txt += content;
			return;
		}
		
		if (pagelayer_empty(content)) {
			txt +=  "<!-- ".concat(pagelayer_block_prefix, ":pagelayer/").concat(final_tag, " ").concat(data, " /-->\n");
		}else{
			txt +=  "<!-- ".concat(pagelayer_block_prefix, ":pagelayer/").concat(final_tag, " ").concat(data, " -->").concat(content, "<!-- /").concat(pagelayer_block_prefix, ":pagelayer/").concat(final_tag, " -->\n");
		}

	};
	
	// Are you an element for which to generate the codes ?
	if(jQuery(selector).hasClass('pagelayer-ele') && selfEle){
  
		generate_sc_single(jQuery(selector));
  
	// The selector is the holder, so loop thru
	}else{
	
		jQuery(selector).children(".pagelayer-ele-wrap").each(function(){
			
			var jEle = jQuery(this).children('.pagelayer-ele');
			generate_sc_single(jEle);
			
		});
	
	}
	
	return txt;
	
};

// Show the required leftbar tab
function pagelayer_leftbar_tab(tab){	
	pagelayer.$$('.pagelayer-leftbar-tab').hide();
	pagelayer.$$('#'+tab).show();	
}

// Sets up the leftbar
function pagelayer_leftbar(){
	
	// Toggle the holder
	pagelayer.$$('.pagelayer-leftbar-toggle').on('click', function(){
		pagelayer.$$('.pagelayer-leftbar-table').toggleClass('pagelayer-leftbar-hidden');
		pagelayer_trigger_action('pagelayer-leftbar-toggle');
	});
	
	// Close leftbar
	pagelayer.$$('.pagelayer-leftbar-close').on('click', function(){
		pagelayer.$$('.pagelayer-leftbar-toggle').click();
	});
	
	// Minimize leftbar
	pagelayer.$$('.pagelayer-leftbar-minimize').on('click', function(){
		pagelayer.$$('.pagelayer-leftbar-table').toggleClass('pagelayer-leftbar-minimize');
	});
	
	var html = '<div class="pagelayer-leftbar">'+
	'<div class="pagelayer-leftbar-scroll">'+
		'<div id="pagelayer-shortcodes" class="pagelayer-leftbar-tab pagelayer-shortcodes">'+
			'<div class="pagelayer-widget-tabs">'+
				'<div class="pagelayer-widget-tab pagelayer-settings" pagelayer-widget-tab="settings">Settings</div>'+
				'<div class="pagelayer-widget-tab" pagelayer-widget-tab="widgets" pagelayer-elpd-active-tab=1>Widgets</div>'+
				'<div class="pagelayer-widget-tab" pagelayer-widget-tab="global">Global</div>'+
			'</div>'+
			'<div class="pagelayer-shortcodes-widget">'+
				'<div class="pagelayer-leftbar-search">'+
					'<i class="pli pli-search" ></i><input class="pagelayer-search-field" /><span class="pagelayer-sf-empty pli">&times;</span>'+
				'</div>';
		
	for(var x in pagelayer_groups){
		
		// Title
		html += '<div class="pagelayer-leftbar-group pagelayer-group-name-'+x+'"><h5>'+x+'</h5>';
		
		// Indivdual icon
		for(var y in pagelayer_groups[x]){
			
			var sc = pagelayer_groups[x][y];
			
			if(!(sc in pagelayer_shortcodes) || 'not_visible' in pagelayer_shortcodes[sc]){
				continue;
			}
			
			html += '<div class="pagelayer-shortcode-drag" draggable="true" pagelayer-tag="'+sc+'">'+
				'<div class="pagelayer-sc">'+
					'<center class="pagelayer-shortcode-inner">';
					
					if('icon' in pagelayer_shortcodes[sc]){
						html += '<i class="pagelayer-shortcode '+pagelayer_shortcodes[sc]['icon']+'"></i>';
					}else{
						html += '<i class="pagelayer-shortcode pli pagelayer-'+sc+'"></i>';
					}
					
					html += '</center>'+
					'<span class="pagelayer-shortcode-text">'+pagelayer_shortcodes[sc]['name']+'</span>'+
				'</div>'+
			'</div>';
			
		}
		
		html += '</div>';
		
	}
	
	html += '</div>'+
		'<div id="pagelayer-global-widget" class="pagelayer-hidden pagelayer-global-widget"></div>'+
		'</div>'+
		'<div id="pagelayer-elpd" class="pagelayer-leftbar-tab pagelayer-elpd"></div>'+
		'<div id="pagelayer-options" class="pagelayer-leftbar-tab pagelayer-options"></div>'+
		'<div id="pagelayer-history" class="pagelayer-leftbar-tab pagelayer-history"></div>'+
		'<div id="pagelayer-post-settings" class="pagelayer-leftbar-tab pagelayer-post-settings"></div>'+
		'<div id="pagelayer-navigator" class="pagelayer-leftbar-tab pagelayer-navigator"></div>'+
		'<div id="pagelayer-general-options" class="pagelayer-leftbar-tab pagelayer-general-options"></div>'+
	'</div>'+
'</div>';

	pagelayer.$$('.pagelayer-leftbar-holder').prepend(html);
	pagelayer_leftbar_tab('pagelayer-shortcodes');
	
	pagelayer.$$('.pagelayer-leftbar-scroll').slimScroll({
		height: '100%',
		railVisible: false,
		alwaysVisible: true,
		color: '#000',
		size: '5px',
	});
	
	// Hide the ones which are not supposed to be shown
	pagelayer.$$('.pagelayer-search-field').on('input', function(){
		
		var val = jQuery(this).val();
		var re = new RegExp(val, 'i');
		
		// Show only the required tags
		pagelayer.$$('.pagelayer-leftbar-group').each(function(){
			
			var group = jQuery(this);
			var res = group.find('[pagelayer-tag]');
			var hidden = 0;
			
			res.each(function(){
				
				var tEle = jQuery(this);
				if(tEle.find('.pagelayer-shortcode-text').html().match(re)){
					tEle.show();
				}else{
					hidden += 1;
					tEle.hide();
				}
				
			});
			
			// Hide the whole group
			if(hidden == res.length){
				group.hide();
			}else{
				group.show();
			}
				
		});
	});
	
	// On click Pagelayer setting icon
	pagelayer.$$('.pagelayer-settings-icon, .pagelayer-settings').click(function(event){
		pagelayer_active = {};
		
		var pl_tag = jQuery(this).attr('pagelayer-tag') || 'pl_post_props';
		var nModal = jQuery(this).attr('pagelayer-modal-none');
		
		pagelayer_post_settings(pl_tag);
		
	});
	
	// Pagelayer post advance setting modal handler
	var propsModal = pagelayer.$$('.pagelayer-props-modal');
	propsModal.find('.pagelayer-props-modal-close').on('click', function(event){
		propsModal.hide();
	});
		
	propsModal.on('click', function(event){
		var target = jQuery(event.target);
		
		if(target.closest('.pagelayer-props-modal-wrap').length > 0){
			return;
		}
		
		propsModal.hide();
	});
		
	
	// On click Pagelayer setting icon
	var global_widget_list = function(){
		
		var gHtml = '';
		
		if(pagelayer_empty(pagelayer_pro)){
			gHtml += '<div class="pagelayer-global-widget-pro">'+pagelayer.pro_txt+
			'<p>Using this feature, you can save the widgets globally and use them on the entire site. The global widget will be editable from one place.</p>'+
			'</div>';
			
			pagelayer.$$('#pagelayer-global-widget').html(gHtml);
			return;
		}
		
		gHtml += '<div class="pagelayer-global-widget-shortcodes">'+
			'<div class="pagelayer-leftbar-search">'+
				'<i class="pli pli-search" ></i><input class="pagelayer-search-field" /><i class="pagelayer-sf-empty pli">&times;</i>'+
			'</div>'+
			'<div class="pagelayer-leftbar-group"><h5>'+pagelayer_l('global_widgets')+'</h5></div>'+
		'</div>';
		
		if(pagelayer_empty(pagelayer_global_widgets)){
			pagelayer_global_widgets = [];
			gHtml += '<div class="pagelayer-leftbar-group"><h5>No global widgets found</h5></div>';
		}

		// Indivdual icon
		for(var y in pagelayer_global_widgets){
			var wEle = jQuery(pagelayer_global_widgets[y]['$']);
			var sc = pagelayer_tag( wEle );
			
			if(!(sc in pagelayer_shortcodes) || 'not_visible' in pagelayer_shortcodes[sc]){
				continue;
			}
			
			gHtml += '<div class="pagelayer-shortcode-drag" draggable="true" pagelayer-tag="'+sc+'" pagelayer-global-id="'+y+'">'+
				'<div class="pagelayer-sc">'+
					'<center class="pagelayer-shortcode-inner">';
					
					if('icon' in pagelayer_shortcodes[sc]){
						gHtml += '<i class="pagelayer-shortcode '+pagelayer_shortcodes[sc]['icon']+'"></i>';
					}else{
						gHtml += '<i class="pagelayer-shortcode pli pagelayer-'+sc+'"></i>';
					}
					
					gHtml += '</center>'+
					'<span class="pagelayer-shortcode-text">'+pagelayer_global_widgets[y]['title']+'</span>'+
				'</div>'+
			'</div>';
			
		}
	
		pagelayer.$$('#pagelayer-global-widget').html(gHtml);
	};
	
	// The widget tabs
	pagelayer.$$('.pagelayer-widget-tab').on('click', function(){	
		var attr = 'pagelayer-elpd-active-tab';
		pagelayer.$$('.pagelayer-widget-tab').each(function(){
			jQuery(this).removeAttr(attr);
		});
		var cEle = jQuery(this);
		cEle.attr(attr, 1);
		
		if(cEle.attr('pagelayer-widget-tab') == 'global'){
			cEle.closest('#pagelayer-shortcodes').find('.pagelayer-shortcodes-widget').addClass('pagelayer-hidden');
			cEle.closest('#pagelayer-shortcodes').find('.pagelayer-global-widget').removeClass('pagelayer-hidden');
			// Trigger create global widgets
			global_widget_list();
		}else{
			cEle.closest('#pagelayer-shortcodes').find('.pagelayer-shortcodes-widget').removeClass('pagelayer-hidden');
			cEle.closest('#pagelayer-shortcodes').find('.pagelayer-global-widget').addClass('pagelayer-hidden');
		}
	});
	
	// On click search empty
	pagelayer.$$('.pagelayer-leftbar-search>.pagelayer-sf-empty').click(function(){
		pagelayer.$$('.pagelayer-search-field').val('').trigger('input');
	});
	
	// Pagelayer General options
	pagelayer.$$('.pagelayer-options-icon ').click(function(){
		pagelayer.$$('.pagelayer-elpd-header').show().find('.pagelayer-elpd-title').text(pagelayer_l('general_options'));
		pagelayer.$$('.pagelayer-logo').hide();
		
		// Setup General options
		pagelayer_setup_general_options();
		
		pagelayer_leftbar_tab('pagelayer-general-options');
		pagelayer_active = {};
	});
	
	// Hide color and typography global list
	pagelayer.$$('.pagelayer-leftbar-table').on('click', function(e){

		var closest = jQuery(e.target).closest('.pagelayer-elp-color-global, .pagelayer-elp-global-icon, .pagelayer-global-color-list, .pagelayer-global-font-list');
		var list = pagelayer.$$('.pagelayer-global-color-list, .pagelayer-global-font-list');

		if(closest.length > 0 ){
			var lEle = closest.closest('.pagelayer-elp-color-div-holder').find('.pagelayer-global-color-list');
			var lFont = closest.closest('.pagelayer-form-item').find('.pagelayer-global-font-list');
			
			list = list.not(lFont);
			list = list.not(lEle);
		}

		list.not(closest).slideUp();
		
	});
};

// Post setting holder
function pagelayer_post_settings(pl_tag, to_click){
	
	to_click = to_click == -1 ? false : true;
	
	// Is there a post settings ?
	var jEle = jQuery(pagelayer_editable+' [pagelayer-tag="'+ pl_tag +'"]');
	
	// Could not find
	if(jEle.length < 1){
		jEle = pagelayer_create_sc(pl_tag);
		var id = pagelayer_id(jEle);
		jQuery(pagelayer_editable).prepend(jEle);
		pagelayer_element_setup('[pagelayer-id='+id+']', true);
		
		// Dont mark as dirty as post_props is not editing anything
		pagelayer_do_undirty();
	}
	
	if(to_click){
		jEle.click();
	}
	
	return jEle;
}

// Get the closest element and method
function pagelayer_near_by_ele(id, sc){
	
	// Get the previous element of the id element
	var prevEle_id = jQuery('[pagelayer-wrap-id="'+id+'"]').prev().attr('pagelayer-wrap-id') || '';
	var method, cEle, args = {};

	if(prevEle_id.length > 0){
		
		// If have previous element of the id element
		// Set the method and previous element selector
		args = {'method' : 'after', 'cEle' : '[pagelayer-wrap-id="'+prevEle_id+'"]'};
		
	}else{
		
		// If don't have previous element of the id element then get parent element
		if(sc == "pl_row"){
			args = {'method' : 'prepend', 'cEle' : pagelayer_editable};
		}else{
			
			// Get the parent element 
			var pEle_id = pagelayer_id(jQuery('[pagelayer-wrap-id="'+id+'"]').closest('.pagelayer-ele'));
			
			// Get the parent element tag
			var pEle_tag = pagelayer_tag(jQuery('[pagelayer-id="'+pEle_id+'"]'));
			var holder = '>'+ pagelayer_shortcodes[pEle_tag]['holder'] || '';
			args = {'method' : 'prepend', 'cEle' : '[pagelayer-id="'+pEle_id+'"] '+ holder+' '};
			
		}
		
	}
	
	return args;
	
};

// Push the action data in the pagelayer_history_obj object
function pagelayer_history_action_push(args){
	
	var currentTime = new Date();
	var history_obj_len = pagelayer_history_obj['action_data'].length;
	
	// If the history_obj_len is less then 1 then set the data in array 0 position 
	if(history_obj_len < 1){
		pagelayer_history_obj['action_data'][0] = {'title' : 'Start Editing', 'action' : 'Start' };
		pagelayer_history_obj['current_active_item_id'] = 0;
	}
	
	// Remove the second array element if the history_obj_len greater then 100
	if(history_obj_len > 100){
		pagelayer_history_obj['action_data'].splice(1, 1);
		pagelayer_history_obj['current_active_item_id'] = pagelayer_history_obj['action_data'].length - 1;
	}
	
	// Get current active history action id 
	var action_id = parseInt(pagelayer_history_obj['current_active_item_id']) || 0;
	
	// Remove the all array element after the active array element  
	var del_ele = history_obj_len - action_id - 1;
	pagelayer_history_obj['action_data'].splice(action_id + 1, del_ele);
	
	// Check if the same attr set as current active history
	if(args.action == "Edited" && history_obj_len > 1 && currentTime - pagelayer.history_lastTime < 1000){
		var atts = pagelayer_history_obj['action_data'][action_id] || '';
		if(atts['atts'] == args['atts'] && atts['pl_id'] == args['pl_id'] && pagelayer_empty(atts['sub_actions_group']) ){
			args['oldVal'] = atts['oldVal'];
			pagelayer_history_obj['action_data'][action_id] = args;
			pagelayer_history_setup();
			
			// Set the last history time
			pagelayer.history_lastTime = currentTime;
			return true;
		}	
	}
	
	// If the action time within 200 millisecond then it count as sub-actions
	if(currentTime - pagelayer.history_lastTime < 200 && history_obj_len > 1){
		
		var cur_action_data = pagelayer_history_obj['action_data'][action_id];
		var sub_actions_len = cur_action_data['sub_actions_group'] || '';
		
		if( !('attrType' in cur_action_data && cur_action_data['attrType'] == 'tmp_attr' && 'attrType' in args && args['attrType'] == 'a_attr') ) {		
			// If the sub_actions_len is less then 1 then set the data in array 0 position 
			if(sub_actions_len.length < 1){
				pagelayer_history_obj['action_data'][action_id]['sub_actions_group'] = [args];
			}else{
				pagelayer_history_obj['action_data'][action_id]['sub_actions_group'].push(args);
			}
		
			return true;
		}
	}
	
	pagelayer_history_obj['action_data'].push(args);
	pagelayer_history_obj['current_active_item_id'] = pagelayer_history_obj['action_data'].length - 1;
	pagelayer_history_setup();
	
	// Set the last history time
	pagelayer.history_lastTime = currentTime;
}

// Setup pagelayer history
function pagelayer_history_setup(force){
	
	var force = force || false;
	
	// If the history tab is visible, only then setup
	if(!pagelayer.$$('#pagelayer-history').is(':visible') && !force){
		return;
	}
	
	// The current active action id
	var current_id = pagelayer_history_obj['current_active_item_id'];
	
	// pagelayer-HISTORY - Element Properties Dialog
	var pagelayer_history_html = '<div class="pagelayer-history-tabs">'+
			'<div class="pagelayer-history-tab" pagelayer-history-tab="actions" pagelayer-history-active-tab="1">Actions</div>'+
			'<div class="pagelayer-history-tab" pagelayer-history-tab="revisions">Revisions</div>'+
		'</div>'+
		'<div class="pagelayer-history-body">'+
			'<div class="pagelayer-history-section active" pagelayer-show-tab="actions">';
	
	// Any actions	
	if(pagelayer_history_obj['action_data'].length > 0){
		
		for(var x in pagelayer_history_obj['action_data']){
			
			if(pagelayer_empty(pagelayer_history_obj['action_data'][x])){continue;}
			
			var title = pagelayer_history_obj['action_data'][x]['title'] || '';
			var subTitle = pagelayer_history_obj['action_data'][x]['subTitle'] || '';
			var action = pagelayer_history_obj['action_data'][x]['action'] || '';
			var tmp_attr = pagelayer_history_obj['action_data'][x]['attrType'] || '';
			var eAttr = '';
			
			if(!pagelayer_empty(tmp_attr) && tmp_attr == "tmp_attr"){
				eAttr = "pagelayer-history-hidden";
			}
			
			pagelayer_history_html += '<div class="pagelayer-history-holder '+((current_id == x) ? 'current_active_item' : '' )+' '+eAttr+'" history-action-id="'+x+'" >'+
				'<div class="pagelayer-history-detail-holder">'+
					'<span class="pagelayer-history-title"><b> '+title+' </b></span>'+
					'<span class="pagelayer-history-subtitle"> '+subTitle+' </span>'+
					'<span class="pagelayer-history-action"><i> '+action+' </i></span>'+
				'</div>'+
				'<div class="pagelayer-history-icon">'+
					'<span class="pagelayer-history-check pli pli-checkmark" aria-hidden="true"></span>'+
				'</div>'+
			'</div>';
		}
		
	}else{
		pagelayer_history_html += 'No Actions history available yet';
	}

	pagelayer_history_html += '</div>'+
	'<div class="pagelayer-history-section" pagelayer-show-tab="revisions">';
	
	// Any revisions ?
	if(pagelayer_revision_obj){
		for(var x in pagelayer_revision_obj){
			pagelayer_history_html += '<div class="pagelayer-revision-holder" revision-id="'+pagelayer_revision_obj[x]['ID']+'">'+
				'<div class="pagelayer-revision-img-holder">'+
					'<img src="'+pagelayer_revision_obj[x]['post_author_url']+'" />'+ 
				'</div>'+
				'<div class="pagelayer-revision-detail-holder">'+
					'<div class="pagelayer-revision-date">'+
						pagelayer_revision_obj[x]['post_date_ago']+
						'('+pagelayer_revision_obj[x]['post_date']+')'+
					'</div>'+
					'<div class="pagelayer-revision-author">'+
						pagelayer_revision_obj[x]['post_type'] +' by '+
						pagelayer_revision_obj[x]['post_author_name']+
					'</div>'+
				'</div>'+
				'<div class="pagelayer-revision-icon-holder">'+
					'<i class="pagelayer-revision-delete pli pli-cross"></i>'+ 
				'</div>'+
			'</div>';
		}
			
	}else{
		pagelayer_history_html += 'No Revisions history available';
	}
		
	pagelayer_history_html += '</div>'+
		'</div>';
	
	// Create the dialog box
	pagelayer.$$('#pagelayer-history').html(pagelayer_history_html);
	var holder = pagelayer.$$('#pagelayer-history');
	
	// Set active history holder
	holder.find('.pagelayer-history-holder').on('click', function(){
		var hEle = jQuery(this);
		var prev_item_id = pagelayer_history_obj['current_active_item_id'];
		hEle.parent().children().removeClass('current_active_item');
		hEle.addClass('current_active_item');
		var do_item_id = parseInt(hEle.attr('history-action-id'));
		pagelayer_history_action_setup(do_item_id, prev_item_id);
	});
	
	// Apply revision
	holder.find('.pagelayer-revision-holder').on('click', function(){
		var revision_id = jQuery(this).attr('revision-id');
		
		jQuery.ajax({
			url: pagelayer_ajax_url+'&action=pagelayer_apply_revision&revisionID='+revision_id,
			type: 'post',
			data: {
				pagelayer_nonce: pagelayer_ajax_nonce,
				'pagelayer-live' : 1,
			},
			success: function(response, status, xhr){
			
				var obj = jQuery.parseJSON(response);
				if(obj['error']){
					pagelayer_show_msg(obj['error'] , 'error');
				}else{
					
					// Get the current post_name and post_status
					var props = jQuery(pagelayer_editable).find('.pagelayer-post_props');
					var post_name = '', post_status = '';
					
					if(props.length > 0){
						post_name = pagelayer_get_att(props, 'post_name');
						post_status = pagelayer_get_att(props, 'post_status');
					}
					
					// Set content
					jQuery(pagelayer_editable).html(obj['content']);
					
					// Add previous post_name and post_status
					var props_new = jQuery(pagelayer_editable).find('.pagelayer-post_props');
					if(props_new.length > 0){
						
						if(pagelayer_empty(post_name)){
							post_name = pagelayer_default_params.pl_post_props.post_name;
						}
						
						if(pagelayer_empty(post_status)){
							post_status = pagelayer_default_params.pl_post_props.post_status;
						}
						
						var tmp = {};
						tmp['post_name'] = post_name;
						tmp['post_status'] = post_status;
						pagelayer_set_atts(props_new, tmp);
					}
					
					// Need to pass true to render table
					pagelayer_element_setup('.pagelayer-ele', true);
					pagelayer_add_widget();
					pagelayer_show_msg(obj['success'], 'success');
				}
			}
		});
	});
	
	// Delete the revision
	holder.find('.pagelayer-revision-delete').click(function(e){
		
		e.stopPropagation();
		var rEle = jQuery(this).closest('.pagelayer-revision-holder');
		var revision_id = rEle.attr('revision-id');
		
		if(confirm("Are you sure you want to delete the revision ?")){
			jQuery.ajax({
				url: pagelayer_ajax_url+'&action=pagelayer_delete_revision&revisionID='+revision_id,
				type: 'post',
				data: {pagelayer_nonce: pagelayer_ajax_nonce},
				success: function(response, status, xhr){
				
					var obj = jQuery.parseJSON(response);
					if(obj['error']){
						pagelayer_show_msg(obj['error'], 'error');
					}else{
						pagelayer_show_msg(obj['success'], 'success');
						rEle.hide();
					}
					
				}
			});
		}

	});
	
	// The tabs
	holder.find('.pagelayer-history-tab').on('click', function(){	
		var attr = 'pagelayer-history-active-tab';
		holder.find('.pagelayer-history-tab').each(function(){
			jQuery(this).removeAttr(attr);
		});
		jQuery(this).attr(attr, 1);
		
		// Get the active tab
		var active_tab = holder.find('[pagelayer-history-active-tab]').attr('pagelayer-history-tab');
		
		// Trigger the showing of rows
		holder.find('[pagelayer-show-tab]').each(function(){
			var sec = jQuery(this);
			
			// Is it the active tab ? 
			if(sec.attr('pagelayer-show-tab') != active_tab){
				sec.hide();
			}else{
				sec.show();
			}
		});
	});
}

// Get revisions Handler
function pagelayer_get_revision(){

	jQuery.ajax({
		url: pagelayer_ajax_url+'&action=pagelayer_get_revision&postID='+pagelayer_postID,
		type: 'post',
		data: {
			pagelayer_nonce: pagelayer_ajax_nonce,
		},
		//async:false,
		success: function(response, status, xhr){
			var obj = jQuery.parseJSON(response);
			
			if(!pagelayer_empty(obj['error'])){
				pagelayer_show_msg(obj['error'], 'error');
			}else{
				pagelayer_revision_obj = obj;
				pagelayer_history_setup(true);
			}
		}
	});
};

// Do the history action - use for ctrl-z and ctrl-y 
function pagelayer_do_history(action){
	
	var cur_id = pagelayer_history_obj['current_active_item_id'];
	var new_id = cur_id; 
	var action_data_len = pagelayer_history_obj['action_data'].length;
	
	
	if(action == 'undo'){
		
		// You cannot undo from the first movement
		if(cur_id == 0){
			return true;
		}
		
		for(var i = (cur_id - 1); i => 0; i--){
		
			var action = pagelayer_history_obj['action_data'][i];
			
			if('attrType' in action && action['attrType'] == 'tmp_attr'){
				continue;
			}
			
			new_id = i;
			break;
			
		}
		
	}else if(action == 'redo'){
		for(var i = cur_id + 1; i < action_data_len; i++){
			
			var action = pagelayer_history_obj['action_data'][i];
			
			if('attrType' in action && action['attrType'] == 'tmp_attr'){
				continue;
			}
			
			new_id = i;
			break;
			
		}
	}
	
	// Do the action
	pagelayer_history_action_setup(new_id, cur_id);
	pagelayer_history_setup();
	
};

// Action setup handle on ctrl-z and ctrl-y 
function pagelayer_history_action_setup(current_item_id, prev_item_id){
	
	// Set this as the current active
	pagelayer_history_obj['current_active_item_id'] = current_item_id;

	// Delete the element
	var delete_ele = function(id){
		
		// Set Pagelayer History FALSE to prevent saving delete action in action history
		pagelayer.history_action = false;
		
		pagelayer_delete_element('[pagelayer-id='+id+']');
		
		// Set Pagelayer History TRUE
		pagelayer.history_action = true;
		
	};
	
	// Re-setup the element
	var resetup_ele = function(history_array){
		jQuery(history_array.cEle.cEle)[history_array.cEle.method](history_array.html);
		pagelayer_element_setup('[pagelayer-id='+history_array.pl_id+'], [pagelayer-id='+history_array.pl_id+'] .pagelayer-ele', true);
		
		var rEle = jQuery('[pagelayer-id="'+history_array.pl_id+'"]');
		pagelayer_empty_col(rEle.closest('.pagelayer-col-holder'));
		
		pagelayer_do_dirty(rEle);
	};
	
	// Re-setup the element attr
	var reset_ele_attr = function(hEle, atts, val, attrType){
		
		// Set Pagelayer History FALSE to prevent saving attributes in action history
		pagelayer.history_action = false;
		if(attrType == "tmp_attr"){
			pagelayer_set_tmp_atts(hEle, atts, val);
		}else{		
			pagelayer_set_atts(hEle, atts, val);
		}
		
		// The property holder
		var holder = pagelayer.$$('.pagelayer-elpd-body');
		holder.html(' ');
		pagelayer_sc_render(hEle);
		pagelayer_elpd_generate(hEle, holder);
		pagelayer.history_action = true;
		
	};
	
	// Move element
	var pagelayer_move_ele = function(id, move_loc){
		var eWrap = pagelayer_wrap_by_id(id);
		var pCol = eWrap.closest('.pagelayer-col-holder') || '';
		
		jQuery(move_loc.cEle)[move_loc.method](eWrap);
		
		// Ensure the column is not empty
		if(!pagelayer_empty(pCol)){
			pagelayer_empty_col(pCol);
			pagelayer_empty_col(pagelayer_wrap_by_id(id).closest('.pagelayer-col-holder'));
		}

		pagelayer_do_dirty(eWrap);
	};
	
	// Undo actions
	var pagelayer_undo_action = function(history_array){
		var action = history_array.action;
		var id = history_array.pl_id;
		
		if(action == "Edited"){
			hEle = jQuery('[pagelayer-id="'+id+'"]');
			reset_ele_attr(hEle, history_array.atts, history_array.oldVal, history_array.attrType);
		}else if(action == "Added"){
			delete_ele(id);
		}else if(action == "Deleted"){
			resetup_ele(history_array);
		}else if(action == "Copied"){
			delete_ele(id);
		}else if(action == "Moved"){
			pagelayer_move_ele(id, history_array.before_loc);
		}
	};
	
	// Redo actions
	var pagelayer_redo_action = function(history_array){
		var action = history_array.action;
		var id = history_array.pl_id;
		
		if(action == "Edited"){
			hEle = jQuery('[pagelayer-id="'+id+'"]');
			reset_ele_attr(hEle, history_array.atts, history_array.newVal, history_array.attrType);
		}else if(action == "Added"){
			resetup_ele(history_array);
			
			if(history_array.tag != "pl_row" && history_array.tag != "pl_col" ){
				// Ensure the column is not empty
				pagelayer_empty_col(history_array.cEle.cEle);
			}
		}else if(action == "Deleted"){
			delete_ele(id);
		}else if(action == "Copied"){
			resetup_ele(history_array);
		}else if(action == "Moved"){
			pagelayer_move_ele(id, history_array.after_loc);
		}
	};
	
	if(prev_item_id > current_item_id){
			
		// All Actions for undo here
		var i = parseInt(prev_item_id);
		
		for(i; i > current_item_id; i--){
			
			var history_array = pagelayer_history_obj['action_data'][i];
			var sub_actions_group = history_array['sub_actions_group'] || '';
			
			// If it has sub-actions
			if(!pagelayer_empty(sub_actions_group)){
				var j = sub_actions_group.length;
				for(j--; j >= 0; j--){
					pagelayer_undo_action(sub_actions_group[j]);
				}
			}
			
			// Main action
			pagelayer_undo_action(history_array);
			
			// Activate the current element and scroll it into viewport
			var jEle = jQuery('[pagelayer-id="'+history_array.pl_id+'"]');
			if(jEle.length > 0){
				pagelayer_set_active(jEle);
				pagelayer_scroll_to_viewport(jEle, 0);
			}
		}
		
	}else{
				
		// All Actions for redo here
		var i = parseInt(prev_item_id)+1;
		
		for(i; i <= current_item_id; i++){
			
			var history_array = pagelayer_history_obj['action_data'][i];
			var sub_actions_group = history_array['sub_actions_group'] || '';
			// Main action
			pagelayer_redo_action(history_array);
			
			// If it has sub-actions
			if(!pagelayer_empty(sub_actions_group)){
				for(var x in sub_actions_group){
					pagelayer_redo_action(sub_actions_group[x]);
				}
			}
			
			// Activate the current element and scroll it into viewport
			var jEle = jQuery('[pagelayer-id="'+history_array.pl_id+'"]');
			if(jEle.length > 0){
				pagelayer_set_active(jEle);
				pagelayer_scroll_to_viewport(jEle, 0);
			}
		}
	}
	
};

// Report an error
function pagelayer_error(error, func){
	var prefix = func || '';
	alert(prefix+error);
};

function pagelayer_bottombar(){
	var holder = pagelayer.$$('.pagelayer-bottombar-holder');
	var html = '<div class="pagelayer-bottombar">'+
		'<div class="pagelayer-bottombar-rightbuttons">'+
			'<button data-tlite="Save Changes" class="pagelayer-update-button pagelayer-success-btn">'+
				'<span class="pagelayer-update-loader">'+
					'<span></span>'+
					'<span></span>'+
					'<span></span>'+
				'</span>'+
				'<span class="pagelayer-update-text">Update</span>'+
			'</button>'+
			'<button data-tlite="Close and Return to Admin Panel" class="pagelayer-close-button">Close</button>'+
			'<div class="pagelayer-mode-wrapper">'+
				'<div class="pagelayer-mode-buttons-wrapper">'+
					'<i class="screen-mode pli pli-desktop" pagelayer-mode-data="desktop"></i>'+
					'<i class="screen-mode pli pli-tablet" pagelayer-mode-data="tablet"></i>'+
					'<i class="screen-mode pli pli-mobile" pagelayer-mode-data="mobile"></i>'+
				'</div>'+
			'</div>'+
			'<i class="pagelayer-mode-button pli pli-desktop"></i>'+
			'<span data-tlite="'+pagelayer_l('preview_changes')+'"><i class="pagelayer-preview pli pli-eye"></i></span>'+
			'<span data-tlite="'+pagelayer_l('historyand_revisions')+'"><i class="pagelayer-history-icon pli pli-history"></i></span>'+
			'<span data-tlite="'+pagelayer_l('navigator')+'"><i class="pagelayer-navigator-icon pli pli-tree"></i></span>'+
			//'<span data-tlite="Close and Return to Admin Panel"><i class="pagelayer-close-button fa fa-close"></i></span>'+
		'</div>'+
	'</div>';
	
	holder.html(html);
	holder.find('.pagelayer-update-button').on('click', function(){
		pagelayer_save();
		pagelayer_history_setup();// Setup history tab after update
	});
	
	holder.find('.pagelayer-close-button').on('click', function(){
		pagelayer_close();
	});
	holder.find('.screen-mode').on('click', function(){
		var screen_mode = jQuery(this).attr('pagelayer-mode-data');
		pagelayer_set_screen_mode(screen_mode);
		holder.find('.pagelayer-mode-buttons-wrapper').toggle();
	});
	
	holder.find('.pagelayer-mode-button').on('click', function(){
		holder.find('.pagelayer-mode-buttons-wrapper').toggle();
	});
	
	holder.find('.pagelayer-history-icon').click(function(){
		pagelayer.$$('.pagelayer-elpd-header').show().find('.pagelayer-elpd-title').text(pagelayer_l('pagelayer_history'));
		pagelayer.$$('.pagelayer-logo').hide();
		pagelayer_leftbar_tab('pagelayer-history');
		pagelayer_active = {};
		pagelayer_history_setup();	
	});
	
	holder.find('.pagelayer-navigator-icon').click(function(){
		pagelayer.$$('.pagelayer-elpd-header').show().find('.pagelayer-elpd-title').text(pagelayer_l('pagelayer_navigator'));
		pagelayer.$$('.pagelayer-logo').hide();
		
		// If the navigator tab visible, then don't setup 
		if(!pagelayer.$$('#pagelayer-navigator').is(':visible')){
			pagelayer_navigator_setup();
		}
		
		pagelayer_leftbar_tab('pagelayer-navigator');
		pagelayer_active = {};
	});
	
	holder.find('.pagelayer-preview').click(function(){
		
		// If the page is not dirty
		if(!pagelayer_isDirty){
			
			// Open in new tab the existing page itself
			window.open(pagelayer_post_permalink, '_blank');
			return;
			
		}
		
		// Get post content
		var post = pagelayer_generate_sc(pagelayer_editable);//alert(post);return;
		
		pagelayer.$$('.pagelayer-body').css({'opacity' : '0.33'});
		jQuery.ajax({
			url: pagelayer_ajax_url+'&action=pagelayer_create_post_autosave&postID='+pagelayer_postID,
			type: 'POST',
			data: {
				'pagelayer_nonce': pagelayer_ajax_nonce,
				'pagelayer_post_content': pagelayer_Base64.encode(post)
			},
			success: function(data) {
				var data = JSON.parse(data);
				
				// If there is some error
				if(!pagelayer_empty(data['error']) || pagelayer_empty(data['id'])){
					pagelayer_show_msg('Unable to set preview for some reason', 'error');
					return;
				}
				
				var url = data['url']+'&preview_id='+pagelayer_postID+'&preview_nonce='+
				pagelayer_preview_nonce;
				
				// Open in new tab
				window.open(url, '_blank');
			},
			complete: function(){
				pagelayer.$$('.pagelayer-body').css({'opacity' : '1'});
			}
		});
	});
};


///////////////////////////////
// Miscellaneuos Functions
///////////////////////////////

// Setup General options
function pagelayer_setup_general_options(){
	
	var holder = pagelayer.$$('.pagelayer-general-options');
  
	if(holder.children().length > 0){
		return;
	}
  
	// TODO: To create this HTML get Array form php
	var html = '<div class="pagelayer-options-sections">'+
		'<h5>'+ pagelayer_l('general_options') +'</h5>'+
		'<div class="pagelayer-option-holder pagelayer-open-customizer">'+
			'<i class="fas fa-paint-brush"></i>'+
			'<span>'+ pagelayer_l('customize') +'</span>'+
		'</div>'+
	'</div>'+
	'<div class="pagelayer-options-sections">'+
		'<h5>'+ pagelayer_l('navigator_options') +'</h5>'+
		'<div class="pagelayer-option-holder pagelayer-options-history-icon">'+
			'<i class="pli pli-history"></i>'+
			'<span>'+ pagelayer_l('historyand_revisions') +'</span>'+
		'</div>'+
		'<div class="pagelayer-option-holder pagelayer-options-navigator-icon">'+
			'<i class="pli pli-tree"></i>'+
			'<span>'+ pagelayer_l('navigator') +'</span>'+
		'</div>'+
		'<div class="pagelayer-option-holder pagelayer-options-preview">'+
			'<i class="pli pli-eye"></i>'+
			'<span>'+ pagelayer_l('preview_changes') +'</span>'+
		'</div>'+
	'</div>'+
	'<div class="pagelayer-options-sections">'+
		'<h5>'+ pagelayer_l('tools') +'</h5>'+
		'<div class="pagelayer-option-holder pagelayer-open-help">'+
			'<i class="fas fa-question"></i>'+
			'<span>'+ pagelayer_l('help') +'</span>'+
		'</div>'+
		'<div class="pagelayer-option-holder pagelayer-open-keyboard-shortcuts">'+
			'<i class="far fa-keyboard"></i>'+
			'<span>'+ pagelayer_l('keyboard_shortcuts') +'</span>'+
		'</div>'+
	'</div>';
	
	holder.html(html);
	
	// Open customizer settings
	holder.find('.pagelayer-open-customizer').click(function(){
		window.open(pagelayer_customizer_url+'&autofocus%5Bpanel%5D=pagelayer_settings', '_blank');
	});
	
	// Open help / support link
	holder.find('.pagelayer-open-help').click(function(){
		 window.open(pagelayer_support_url, '_blank');
	});
	
	// Show Pagelayer History
	holder.find('.pagelayer-options-history-icon').click(function(){
		pagelayer.$$('.pagelayer-bottombar-holder .pagelayer-history-icon').click();
	});
	
	// Show Pagelayer Navigator
	holder.find('.pagelayer-options-navigator-icon').click(function(){
		pagelayer.$$('.pagelayer-bottombar-holder .pagelayer-navigator-icon').click();
	});
	
	// Show Pagelayer Preview
	holder.find('.pagelayer-options-preview').click(function(){
		pagelayer.$$('.pagelayer-bottombar-holder .pagelayer-preview').click();
	});
	
	// Show keyboard shortcut modal
	holder.find('.pagelayer-open-keyboard-shortcuts').click(function() {
		
		var modal = pagelayer.$$('.pagelayer-shortcuts-modal');
		modal.css('display','flex');
		
		modal.find('.pagelayer-editor-modal-close-icon').unbind('click');
		modal.find('.pagelayer-editor-modal-close-icon').click(function(){
			modal.hide();
		});

		modal.unbind('click');
		modal.on('click', function(e){
			
			if(e.target != this) {
				return;
			}
      
			modal.hide();
		});
	});
}

// Setup navigator
function pagelayer_navigator_setup(){
	
	var navigator_ele = pagelayer.$$('#pagelayer-navigator'),
	navigator_padding = 10,
	navigator_html = '';
		
	// Get the child elements list
	var pagelayer_create_navi_list = function(selector){
		
		var navigator_list = '';
		
		selector.children('.pagelayer-ele-wrap, .pagelayer-ele').each(function(){
			
			var cEle = jQuery(this),
			tag = pagelayer_tag(cEle),
			id = pagelayer_id(cEle),
			child_ele = false,
			ele_class = '';
			
			// If tag is not found then return
			if(pagelayer_empty(tag)){
				return;
			}
			
			// if is row or  col or inner-row
			if(tag == 'pl_row' || tag == 'pl_col' || tag == 'pl_inner_row'){
				ele_class = 'pagelayer-navigator-toggle';
				child_ele = true;
			}
			
			navigator_list += '<div class="pagelayer-navigetor-ele" pagelayer-id="'+id+'">'+
				'<div class="pagelayer-ele-name '+ ele_class +'" pagelayer-tag="'+tag+'" style="padding-left:'+navigator_padding+'px">'+
					'<i class="fa pagalayer-arrow"></i><i class="fa pagelayer-'+tag+'"></i>'+
					pagelayer_shortcodes[tag]['name']+
					'<span class="pagelayer-navigator-options"><i class="pli pli-pencil" data-action="edit"></i><i class="pli pli-trashcan" data-action="delete"></i></span>'+
				'</div>';
			
			// Create the list of child element 
			if(child_ele){
				navigator_padding += 15; // Increment padding left for widget
				navigator_list += pagelayer_create_navi_list( cEle.find(pagelayer_shortcodes[tag]['holder']).first() );
				navigator_padding -= 15; // Decrement padding left for widget
			}
			
			navigator_list += '</div>';
		});
		
		return navigator_list;
	}
	
	// Create list of all rows and their child widgets 
	jQuery(pagelayer_editable).children('.pagelayer-wrap-row').each(function(){
		navigator_html += pagelayer_create_navi_list(jQuery(this));
	});
		
	// Put the navigator list
	navigator_ele.html('<div class="pagelayer-leftbar-prop-body">'+navigator_html+'</div>');
	
	// edit and delete element click handler
	navigator_ele.find('.pagelayer-navigator-options .pli').on('click', function(event){
		
		var sEle = jQuery(this).closest('.pagelayer-navigetor-ele');
		var sId = sEle.attr('pagelayer-id');
		var action = jQuery(this).data('action');
		if( action == 'edit'){
			pagelayer_edit_element('[pagelayer-id = '+sId+']', event);
		}else if(action == 'delete'){
			sEle.find('.pagelayer-ele-name').css({'background':'rgb(255, 114, 114)','opacity':'0.5'});
			pagelayer_delete_element('[pagelayer-id = '+sId+']');
		}
		
	});
	
	// On click toggle the element
	navigator_ele.find('.pagelayer-ele-name').on('click', function(){
		
		var tEle = jQuery(this);
		var pl_id = tEle.parent().attr('pagelayer-id'); // Get Pagelayer id
		var jEle = pagelayer_ele_by_id(pl_id);
		
		// If the class "pagelayer-navigator-toggle" exist then toggle
		if(tEle.hasClass('pagelayer-navigator-toggle')){
			tEle.parent().toggleClass('pagelayer-navigator-open');
		}
		
		// Also open all parents 
		tEle.parent().parents('.pagelayer-navigetor-ele').addClass('pagelayer-navigator-open');
			
		// Set the click element active
		navigator_ele.find('.pagelayer-ele-name').removeClass('pagelayer-navi-active');
		tEle.addClass('pagelayer-navi-active')
		
		// Set the element active
		if(jEle.length > 0){
			//pagelayer_active.el = pagelayer_data(jEle);
			pagelayer_set_active(jEle);
			pagelayer_scroll_to_viewport(jEle);
		}
		
	});
	
	// Do active ele tab open
	if( pagelayer_active.el && pagelayer_active.el.id ){
		navigator_ele.find('[pagelayer-id="'+pagelayer_active.el.id+'"]').children('.pagelayer-ele-name').click();
	}
	
	/* var posY = 0, orig_eleY= 0;
	
	// On mouse down in pagelayer-ele-name
	navigator_ele.find('.pagelayer-ele-name').on('mousedown', function(e){
		e = e || window.event;
		e.preventDefault();
		
		// Get ele position
		orig_eleY = jQuery(this).offset().top;
		
		// Get the mouse cursor  at startup:
		posY = e.clientY;
		
		// The variable needs to be empty.
		newMethod = '';
		
		// Mouse up handler
		var ele_mousemove = function(){
			
		}
		
		// Mouse move handler
		var ele_mouseup = function(){
			pagelayer.$$(document).off('mouseup', ele_mouseup);
			pagelayer.$$(document).off('mousemove', ele_mousemove);
		}
		
		pagelayer.$$(document).on('mouseup', ele_mouseup);
		pagelayer.$$(document).on('mousemove', ele_mousemove);

	}); */
	
	
}

// Scroll page to element view port
function pagelayer_scroll_to_viewport(jEle, timeout, parentEle){
	
	var scrolled = parentEle || jQuery('html, body');
	timeout = timeout || 500;
	parentEle = parentEle || jQuery(window);
	
	setTimeout(function(){
		var parentHeight = parentEle.height(),
		parentScrollTop = parentEle.scrollTop(),
		elementTop = jEle.offset().top,
		topToCheck = elementTop - parentScrollTop;
		  
		if (topToCheck > 0 && topToCheck < parentHeight) {
			return;
		}

		var scrolling = elementTop - parentHeight / 2;
		scrolled.stop(true).animate({
			scrollTop: scrolling
		}, 1000);
	}, timeout);
}

// Generates a random string of "n" characters
function pagelayer_randstr(n, special){
	var text = '';
	var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
	
	special = special || 0;
	if(special){
		possible = possible + '&#$%@';
	}
	
	for(var i=0; i < n; i++){
		text += possible.charAt(Math.floor(Math.random() * possible.length));
	}

	return text;
};

function pagelayer_randInt(max) {
	return Math.floor(Math.random() * Math.floor(max));
}

// Convert the regular URL of a Video to a Embed URL
function pagelayer_video_url(src, no_url){
  
	no_url = no_url || false;
	var youtubeRegExp = /youtube\.com|youtu\.be/;
	var vimeoRegExp = /vimeo\.com/;
	var match = '';
	var videoId = '';
	var vid_params = {};
		
	if (youtubeRegExp.exec(src)) {
		match = 'youtube';
	} else if (vimeoRegExp.exec(src)) {
		match = 'vimeo';
	}
	
	switch(match){
		case 'youtube':
				
			var youtubeRegExp1 = /youtube\.com/;
			var youtubewatch = /watch/;
			var youtubeembed = /embed/;
			var youtube = /youtu\.be/;

			if (youtubeRegExp1.exec(src)) {
				
				if (youtubewatch.exec(src)) {
					 videoId = src.split('?v=');
										
				} else if (youtubewatch.exec(src)) {
					videoId = src.split('embed/');
				}
				
			} else if (youtube.exec(src)) {
				videoId = src.split('.be/');
			}
			
			vid_params = {
				type : 'youtube',
				src : '//www.youtube.com/embed/'+videoId[1],
				id : videoId[1]
			};

			pagelayer_yt_api_register();
			
			break;
			
		case 'vimeo':
		
			var vimeoplayer = /player\.vimeo\.com/;
			var vimeovideo = /video/;
			
			if (vimeoplayer.exec(src) && vimeovideo.exec(src)) {
				videoId = src.split('video/');
			} else if (vimeoRegExp.exec(src)) {
				videoId = src.split('.com/');
			}
			
			vid_params = {
				type : 'vimeo',
				src : '//player.vimeo.com/video/'+videoId[1],
				id : videoId[1]
			};
			
			break;
		default:
			vid_params = {
				type : 'local',
				src : src
			};
			
	}
  
	if(!no_url){
		return vid_params.src;
	}
  
	return vid_params;
};

// Youtube API Register
function pagelayer_yt_api_register(){

	if(jQuery('#pagelayer-youtube-script-js').length > 0){
		return;
	}

	jQuery('body').append('<script src="https://www.youtube.com/iframe_api" id="pagelayer-youtube-script-js"></script>');

}

// Add widget section
function pagelayer_add_widget(){
	
	html='<div class="pagelayer-add-widget-area">'+
		'<button class="pagelayer-add-button pagelayer-add-section"><i class="pagelayer-add-row fas fa-file-alt"></i> &nbsp;Add New Section</button>'+
		'<button class="pagelayer-add-button pagelayer-add-row"><i class="pagelayer-add-row fas fa-plus-circle"></i> &nbsp;Add New Row</button>'+
		'<p>Click here to add new row OR drag widgets</p>'+
	'</div>';
	
	jQuery(pagelayer_editable).append(html);
	
	var add_area = jQuery('.pagelayer-add-widget-area');
	
	// Add a code before this
	var add_sc = function(tag, global_id = ''){
		
		var attr = '';
		if(!pagelayer_empty(global_id)){
			attr = ' pagelayer-global-id="'+global_id+'" ';
		}
		
		// Create Row		
		var row = jQuery('<div pagelayer-tag="pl_row" '+((tag == 'pl_row') ? attr : '') +'></div>');
		add_area.before(row);
		var row_id = pagelayer_onadd(row, false);
		var rEle = pagelayer_ele_by_id(row_id);
		
		if(tag == 'pl_row' && !pagelayer_empty(global_id)){
			rEle.click();
			return row_id;
		}
		
		// Create Column
		var col = jQuery('<div pagelayer-tag="pl_col" '+((tag == 'pl_col') ? attr : '') +'></div>');
		rEle.find('.pagelayer-row-holder').append(col);
		var col_id = pagelayer_onadd(col, false);
		var cEle = pagelayer_ele_by_id(col_id);
		
		
		if(tag == 'pl_row'){
			rEle.click();
			return row_id;
		}
		
		if(tag == 'pl_col'){
			cEle.click();
			return col_id;
		}
		
		// Create element
		var ele = jQuery('<div pagelayer-tag="'+tag+'" '+attr+'></div>');
		cEle.find('.pagelayer-col-holder').append(ele);
		//console.log(ele);
		var id = pagelayer_onadd(ele);
		//console.log(id);
		//console.log(col_id);
		var eEle = pagelayer_ele_by_id(col_id);
		//console.log(eEle);
		// Ensure the column is not empty
		pagelayer_empty_col(cEle.find('.pagelayer-col-holder'));
		
		if(tag == 'pl_inner_row' && pagelayer_empty(global_id)){
			// Create Column
			var in_col = jQuery('<div pagelayer-tag="pl_col"></div>');
			eEle.find('.pagelayer-row-holder').append(in_col);
			var in_col_id = pagelayer_onadd(in_col, false);
		}
		
		return id;
		
	}
	
	// Handle Click
	add_area.on('click', function(e){
		e.stopPropagation();
		add_sc('pl_col');
	});
	
	// Handle Click
	add_area.find('.pagelayer-add-section').on('click', function(e){
		e.stopPropagation();
		pagelayer_add_section_area();// Setup and show sections modal
	});
	
	// Handle Drag over
	add_area.on('dragover', function(e){
		//console.log(e)
		add_area.addClass('pagelayer-add-widget-drag');
	});
	
	// Handle Drag Leave
	add_area.on('dragleave', function(e){
		//console.log(e)
		add_area.removeClass('pagelayer-add-widget-drag');
	});
	
	// Handle On Drop
	add_area.on('drop', function(e){
		
		//console.log(e);
		//console.log(e.originalEvent.dataTransfer.getData('tag'));
		add_area.removeClass('pagelayer-add-widget-drag');
		jQuery('.pagelayer-is-dragging').removeClass('pagelayer-is-dragging');
		
		var tag = e.originalEvent.dataTransfer.getData('tag');
		var global_id = e.originalEvent.dataTransfer.getData('global_id');
		
		// Is it an existing element ?
		if(tag.length < 1){
			return false;
		}
		
		e.preventDefault();
		
		//console.log(tag);
		
		add_sc(tag, global_id);
	});
};

// Is the element in view while scrolling
function pagelayer_isElementInView(elem, holder, partial) {
	partial = partial || true;
	var container = jQuery(holder);
	var contHeight = container.height();
	var contTop = container.scrollTop();
	var contBottom = contTop + contHeight ;

	var elemTop = jQuery(elem).offset().top - container.offset().top;
	var elemBottom = elemTop + jQuery(elem).height();

	var isTotal = (elemTop >= 0 && elemBottom <=contHeight);
	var isPart = ((elemTop < 0 && elemBottom > 0 ) || (elemTop > 0 && elemTop <= container.height())) && partial;

	return isTotal || isPart ;
}

// Append section modal into body
function pagelayer_add_section_area(){
	
	var body = pagelayer.$$('body');
	var mEle = body.find('.pagelayer-add-section-modal-container');
	
	if(mEle.length > 0){
		mEle.show();
		return;
	}
	
	var section_modal = '<div class="pagelayer-add-section-modal-container">'+
		'<div class="pagelayer-add-section-modal-holder">'+
			'<div class="pagelayer-add-section-modal">'+
				'<div class="pagelayer-add-section-modal-header">'+
					'<div>Add Sections</div>'+
					'<div class="pagelayer-section-type-div">Type : '+
						'<select name="type" id="pagelayer-section-type">'+
							'<option value="section">Sections</option>'+
							'<option value="header">Headers</option>'+
							'<option value="footer">Footers</option>'+
							'<option value="page">Pages</option>'+
						'</select>'+
					'</div>'+
					'<div class="pagelayer-add-section-modal-close">&times;</div>'+
				'</div>'+
				'<div class="pagelayer-add-section-modal-row">'+
					'<div class="pagelayer-add-section-modal-left">'+
						'<div class="pagelayer-section-search-div">'+
							'<i class="pli pli-search" ></i><input class="pagelayer-section-search" /><span class="pagelayer-sf-empty pli">&times;</span>'+
						'</div>'+
						'<div class="pagelayer-section-tags-holder"></div>'+
					'</div>'+
					'<div class="pagelayer-section-modal-body-holder">'+
						'<div class="pagelayer-add-section-modal-body"></div>'+
					'</div>'+
				'</div>'+
				'<div class="pagelayer-add-section-modal-overlay" style="display:none;">'+
					'<div class="pagelayer-section-wait">'+
						'<div class="pagelayer-loader">'+
							'<div class="pagelayer-percent-parent"></div>'+
						'</div><br/>'+
						'<span>Please wait a moment</span>'+
					'</div>'+
				'</div>'+
			'</div>'+
		'</div>'+
	'</div>';
	
	mEle = jQuery(section_modal);
	
	// Append the element in the body
	body.append(mEle);
	
	// On click close modal 
	mEle.find('.pagelayer-add-section-modal-close').on('click', function(){
		mEle.hide();
	});
	
	// Search Empty
	mEle.find('.pagelayer-sf-empty').on('click', function(){
		mEle.find('.pagelayer-section-search').val('');
	});
	
	// On select section type 
	mEle.find('#pagelayer-section-type').on('change', function(){
		var val = jQuery(this).val();
		pagelayer_add_sections_list_setup(val);
	});
	
	// Append the list items into modal body
	pagelayer_add_sections_list_setup();
	
	mEle.show();// Show the modal
	
};

// Append section list into modal body
function pagelayer_add_sections_list_setup(type){
	
	var mEle = pagelayer.$$('.pagelayer-add-section-modal-container');
	var body = mEle.find('.pagelayer-add-section-modal-body');
	var add_area = jQuery('.pagelayer-add-widget-area');
	type = type || 'section';
	
	// Find the number of cols
	var body_width = jQuery(window.parent).width();
	var num_cols = 3;
	if(body_width >= 1500){
		num_cols = 4;
	}else if(body_width >= 992){
		num_cols = 3;
	}else if(body_width >= 768){
		num_cols = 2;
	}else if(body_width >= 360){
		num_cols = 1;
	}
	//console.log(num_cols+' - '+body_width);
	
	var viewer = '<div class="pagelayer-section-is-visible"></div>';
	var selected_tags = {};
	var result_set = {};
	
	// Setup the scroll
	mEle.find('.pagelayer-section-tags-holder').slimScroll({
		height: 'calc(100vh - 150px)',
		railVisible: false,
		alwaysVisible: true,
		color: '#000',
		size: '5px',
	});
	
	// Create list of items
	var pagelayer_section_list = function(){
		
		// List the tags
		if(!pagelayer_empty(pagelayer_add_section_data[type]['tags'])){
			var tags_html = '';
			var tags = pagelayer_add_section_data[type]['tags'];
			for(var k in tags){
				tags_html += '<span class="pagelayer-section-tags" tag="'+k+'">'+k+' ('+tags[k].length+')</span>';				
			}
			mEle.find('.pagelayer-section-tags-holder').html(tags_html);
			
			// Handle tag click
			mEle.find('.pagelayer-section-tags').unbind('click');
			mEle.find('.pagelayer-section-tags').on('click', function(e){
				
				var search = mEle.find('.pagelayer-section-search');
				
				// Blank the search
				if(search.val().length > 0){
					search.val('');
					selected_tags = {};
				}
				
				// Fill the selected_tags
				tEle = jQuery(this);
				var tag = tEle.attr('tag')
				
				if(tEle.attr('on') == '1'){
					delete selected_tags[tag];
					tEle.removeAttr('on');
				}else{
					tEle.attr('on', 1);
					selected_tags[tag] = 1;
				}
				
				// Filter
				pagelayer_section_filter(false, 1);
				
			});
		}
		
		// Fill in the result
		result_set = { ...pagelayer_add_section_data[type]['list']};
		
		show_result();
		
	};
	
	// How the result and setup scroll
	var show_result = function(){
		
		var html = '';
		for(var i = 0; i < num_cols; i++){
			html += '<div class="pagelayer-section-holder" pagelayer-section-type="'+type+'" num="'+i+'"></div>';
		}
		
		// Blank the body
		body.html(html+viewer);
		
		mEle.find('.pagelayer-section-modal-body-holder').unbind('scroll');
		mEle.find('.pagelayer-section-modal-body-holder').on('scroll', pagelayer_section_body_scroll);
		pagelayer_section_body_scroll();
	}
	
	var scroll_accessed = false;
	
	// Section body ON scroll
	var pagelayer_section_body_scroll = function(){
		
		// Check if there is anything to display in the first place, as we do delete pagelayer_add_section_data
		if(pagelayer_empty(result_set)){
			return;
		}
		
		var tester = mEle.find('.pagelayer-section-is-visible');
		var modal = mEle.find('.pagelayer-section-modal-body-holder');
		
		// If we have scroll
		if(!pagelayer_isElementInView(tester, modal) || scroll_accessed){
			return;
		}
		
		scroll_accessed = true;
		
		var html = '';
		var i = 0;
		
		// Loop result_set
		for(var id in result_set){
			
			if(i >= (num_cols * 5)){
				break;
			}
			
			var col = i % num_cols;
			//console.log(col);
			
			i++;
			
			var pro = 0;
			
			// Is it pro ?
			if(!pagelayer_empty(result_set[id]) && pagelayer_empty(pagelayer_pro)){
				pro = 1;
			}
			
			html = '<div class="pagelayer-section-item" pagelayer-section-type="'+type+'" pagelayer-add-section-id="'+id+'">'+
			'<img src="'+ pagelayer_add_section_data[type]['image_url'] + id +'/screenshot.jpg" alt="Pagelayer code screenshot" />'+
			(pro ? '<div class="pagelayer-section-pro-req">Pro</div><div class="pagelayer-section-pro-txt">'+pagelayer.pro_txt+'</div>' : '')+
			'</div>';
			
			body.find('.pagelayer-section-holder[num='+col+']').append(html);
			
			delete result_set[id];
			
		}
		
		//console.log(result_set);
		
		mEle.find('.pagelayer-section-item').unbind('click');
		mEle.find('.pagelayer-section-item').on('click', function(e){
			pagelayer_section_item_clickable(jQuery(this));
		});
		
		scroll_accessed = false;
		
	}
	
	// If we have searched something / or clicked tags
	var pagelayer_section_filter = function(event, not_input){
				
		var txt = mEle.find('.pagelayer-section-search').val();
		var tags = pagelayer_add_section_data[type]['tags'];
		
		// Searched anything
		if(!pagelayer_empty(txt) || pagelayer_empty(not_input)){
		
			// Blank the tags
			selected_tags = {};
			
			mEle.find('.pagelayer-section-tags').removeAttr('on');
			
			for(var k in tags){
				if(k.search(txt) >= 0){
					selected_tags[k] = 1;
					mEle.find('.pagelayer-section-tags[tag="'+k+'"]').attr('on', 1);
				}
			}
			
		}
		
		var new_result = {};
		var new_length = 0;
		
		// Filter the content
		for(var t in selected_tags){
			
			for(var i in tags[t]){
				new_length++;
				new_result[tags[t][i]] = tags[t][i];
			}
			
		}
		
		// Copy the result
		result_set = {...new_result};
		//console.log(type);console.log(selected_tags);console.log(result_set);
		
		show_result();
		
	}
	
	// On search change
	mEle.find('.pagelayer-section-search').unbind('input');
	mEle.find('.pagelayer-section-search').on('input', pagelayer_section_filter);
	
	// On click items
	var pagelayer_section_item_clickable = function(jEle){
		
		var section_id = jEle.attr('pagelayer-add-section-id');
		
		// IF section id not found
		if(pagelayer_empty(section_id)){
			return false;
		}
		
		if(jEle.find('.pagelayer-section-pro-req').length > 0){
			return false;
		}
		
		// Show the overlay
		mEle.find('.pagelayer-add-section-modal-overlay').show();
		
		// Do shortcode the content
		jQuery.ajax({
			url: pagelayer_ajax_url+'&action=pagelayer_get_section_shortcodes&postID='+pagelayer_postID,
			type: 'POST',
			data: {
				'pagelayer_nonce': pagelayer_ajax_nonce,
				'pagelayer_section_id': section_id,
				'pagelayer-live': 1
			},
			success: function(data) {
				
				try{
					
					var data = JSON.parse(data);
					
					if(!pagelayer_empty(data['error'])){
						pagelayer_show_msg('Error getting the section', 'error');						
						mEle.find('.pagelayer-add-section-modal-overlay').hide();
						mEle.hide();
						return;
					}
					
					var cEle = jQuery(data['code']);
					
					// Add section before add widget area
					add_area.before(cEle);
					
					// We need to it setup
					cEle.each(function(){
						var pl_id = pagelayer_id(jQuery(this));
						
						if(!pagelayer_empty(pl_id)){
							pagelayer_element_setup('[pagelayer-id="'+pl_id+'"], [pagelayer-id='+pl_id+'] .pagelayer-ele', true);
						}
					});
				
				}catch(e){
					pagelayer_show_msg('Error getting the section', 'error');						
					mEle.find('.pagelayer-add-section-modal-overlay').hide();
					mEle.hide();
					return;
				}
				
			},
			complete: function(){
				mEle.find('.pagelayer-add-section-modal-overlay').hide();
				mEle.hide();
			}
		});	
	}
	
	// Load the data if not there
	if(!(type in pagelayer_add_section_data)){
		
		// Show the loading
		mEle.find('.pagelayer-add-section-modal-overlay').show();
		
		// Get the sections list data and append it
		jQuery.ajax({
			url: pagelayer_api_url+'/library.php?give='+type,
			type: 'post',
			success: function(response){
				var tmp = JSON.parse(response);
				
				// Is the list there ?
				if( !('list' in tmp && !pagelayer_empty(tmp['list'])) ){
					return;
				}
				
				pagelayer_add_section_data[type] = tmp;
				
				// Create the Type
				pagelayer_section_list(type);
				
				// Hide the loading
				mEle.find('.pagelayer-add-section-modal-overlay').hide();
				
			},
			complete: function(){
				mEle.find('.pagelayer-add-section-modal-overlay').hide();
			}
		});
	
	// We have the data, so show it
	}else{
		pagelayer_section_list(type);
	}
}

// Upload an image
function pagelayer_upload_image(fileName, blob, pagelayer_ajax_func){
	
	var formData = new FormData();
	formData.append('action', 'upload-attachment');
	formData.append('_ajax_nonce', pagelayer_media_ajax_nonce);
	formData.append('async-upload', blob, fileName);
	
	jQuery.ajax({
		url:pagelayer_ajax_url,
		data: formData,// the formData function is available in almost all new browsers.
		type:"post",
		contentType:false,
		processData:false,
		cache:false,
		beforeSend: function( xhr ) {
			if(typeof pagelayer_ajax_func.beforeSend == 'function'){
				pagelayer_ajax_func.beforeSend(xhr);						
			}
		},		
		xhr: function() {
			var xhr = new window.XMLHttpRequest();
			if(typeof pagelayer_ajax_func.uploadProgress == 'function'){
				xhr = pagelayer_ajax_func.uploadProgress(xhr);						
			}
		  return xhr;
		},		
		error:function(err){
			//console.error(err);
			pagelayer_show_msg('Unable to upload image for some reason.', 'error');						
		},
		success:function(response){
			var obj = jQuery.parseJSON(response);
			if(typeof pagelayer_ajax_func.success == 'function'){
				pagelayer_ajax_func.success(obj);						
			}
		},
		complete:function(xhr){
			if(typeof pagelayer_ajax_func.complete == 'function'){
				pagelayer_ajax_func.complete(xhr);						
			}
		}
	});
};

// On editable area image paste handler
function pagelayer_editable_paste_handler(pasteEvent, pagelayer_ajax_func){
	var items,
	is_Paste = (pasteEvent.type == 'paste' ? true : false),
	mustPreventDefault = false,
	reader;

	try {
		if(is_Paste){
			items = (pasteEvent.originalEvent || pasteEvent).clipboardData.items;			
		}else{
			items = [pasteEvent];
		}
		
		for (var i = items.length - 1; i >= 0; i -= 1) {

			if (items[i].type.match(/^image\//)) {
				
				reader = new FileReader();
				/* jshint -W083 */
				reader.onloadend = function(event) {
					
					var src = event.target.result;		
					
					if(src.indexOf('data:image') === 0 ) {
						
						var block = src.split(";");
						var contentType = block[0].split(":")[1];
						var realData = block[1].split(",")[1];
						if(is_Paste){
							var fileName = "image."+contentType.split("/")[1];					
						}else{
							var fileName = items[0]['name'];
						}
						
						// Convert it to a blob to upload
						var blob = pagelayer_b64toBlob(realData, contentType);
						
						pagelayer_upload_image(fileName, blob, pagelayer_ajax_func);
						
					}
				   
				};
				/* jshint +W083 */
				if(is_Paste){
					reader.readAsDataURL(items[i].getAsFile());	
				}else{
					reader.readAsDataURL(items[i]);					
				}
				mustPreventDefault = true;
			}
		}
		
		if(mustPreventDefault && is_Paste){
			pasteEvent.stopPropagation();
			pasteEvent.preventDefault();
		}
		
	}catch(err){
		console.log(err);
	}
	
	return mustPreventDefault;
	
}

// Convert base64 to Blob 
function pagelayer_b64toBlob(b64Data, contentType, sliceSize) {
	contentType = contentType || '';
	sliceSize = sliceSize || 512;

	var byteCharacters = atob(b64Data);
	var byteArrays = [];

	for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
		var slice = byteCharacters.slice(offset, offset + sliceSize);

		var byteNumbers = new Array(slice.length);
		for (var i = 0; i < slice.length; i++) {
			byteNumbers[i] = slice.charCodeAt(i);
		}

		var byteArray = new Uint8Array(byteNumbers);

		byteArrays.push(byteArray);
	}

	var blob = new Blob(byteArrays, {type: contentType});
	return blob;
}

// Function to check if the URL is external
function pagelayer_parse_theme_vars(img_url){
	
	for(x in pagelayer_theme_vars){
		img_url = img_url.replace(x, pagelayer_theme_vars[x]);
	}
	
	return img_url;
};

// Tooltip Setup for Editor
function pagelayer_tooltip_setup(){	
	//pagelayer.$$('[data-tlite]').each(function(){pagelayer_tlite.show(jQuery(this).get(0));});return;
	pagelayer.$$('[data-tlite]').hover(function(){
		pagelayer_tlite.show(jQuery(this).get(0));
	}, function(){
		pagelayer_tlite.hide(jQuery(this).get(0));
	});
	
};

// Pagelayer Messages
function pagelayer_show_msg(msg, state, time){
	
	time = time || 5000;
	state = !pagelayer_empty(state) ? 'pagelayer-editor-msg-state-'+state : '';
	var nholder = pagelayer.$$('.pagelayer-editor-notice');
	var mEle = jQuery('<div class="pagelayer-editor-msg '+state+'">'+msg+' <span class="pli pli-cross pagelayer-notice-x"></span></div>');
	
	nholder.append(mEle);
	
	mEle.find('.pagelayer-notice-x').on('click', function(){
		mEle.css({opacity: 0});
		setTimeout(function(){
			mEle.css({transition: 'none'});
			mEle.slideUp(function(){
				mEle.remove();
			});
		}, 900);
	});
	
	setTimeout(function(){
		mEle.find('.pagelayer-notice-x').click();
	}, time);
	
}

// Pagelayer confirmation box
function pagelayer_confirmation_box(message, yesCallback, noCallback, yesText, noText) {
	
    yesText = yesText || pagelayer_l('Yes');
    noText = noText || pagelayer_l('No');
	
	var dialog = jQuery('<div class="pagelayer-confirm-box-holder">'+
		'<div class="pagelayer-confirm-box" style="border-radius:5px">'+
			'<div class="pagelayer-confirmation-msg">'+ message +'</div>'+
			'<center>'+
				'<span class="pagelayer-btnyes button button-pagelayer">'+ yesText +'</span>&nbsp;&nbsp;&nbsp;'+
				'<span class="pagelayer-btnno button button-pagelayer">'+ noText +'</span>'+
			'</center>'+
		'</div>'+
	'</div>');
	
	pagelayer.$$('body').append(dialog);

	dialog.find('.pagelayer-btnyes').on('click', function() {
		dialog.remove();
		if(typeof yesCallback == 'function'){
			yesCallback();
		}
	});
	dialog.find('.pagelayer-btnno').on('click', function() {
		dialog.remove();
		if(typeof noCallback == 'function'){
			noCallback();
		}
	});
	dialog.show();
}

function pagelayer_trim(str, charlist){
	//  discuss at: http://locutus.io/php/trim/
	
	if(typeof str != 'string'){
		return str;
	}
	
	var whitespace = [' ', '\n', '\r', '\t', '\f', '\x0b', '\xa0', '\u2000', '\u2001', '\u2002', '\u2003', '\u2004', '\u2005', '\u2006', '\u2007', '\u2008', '\u2009', '\u200a', '\u200b', '\u2028', '\u2029', '\u3000' ].join('');
	var l = 0;
	var i = 0;
	str += '';

	if (charlist) {
		whitespace = (charlist + '').replace(/([[\]().?/*{}+$^:])/g, '$1');
	}

	l = str.length;
	for (i = 0; i < l; i++) {
		if (whitespace.indexOf(str.charAt(i)) === -1) {
			str = str.substring(i);
			break;
		}
	}

	l = str.length;
	for (i = l - 1; i >= 0; i--) {
		if (whitespace.indexOf(str.charAt(i)) === -1) {
			str = str.substring(0, i + 1);
			break;
		}
	}

	return whitespace.indexOf(str.charAt(0)) === -1 ? str : '';
};

function pagelayer_ucwords(str) {
    return (str + '').replace(/^([a-z])|\s+([a-z])/g, function ($1) {
        return $1.toUpperCase();
    });
}

// Check length for string and object
function pagelayer_length(mixed_var) {
	
	var length = 0;
	var undef, key, i, len;
	var emptyValues = [undef, null, false];

	for(i = 0, len = emptyValues.length; i < len; i++) {
		if (mixed_var === emptyValues[i]) {
			return length;
		}
	}
	
	// Is array, object or jQuery object?
	if(typeof mixed_var === 'object'){
		
		// If is jQuery object
		if( mixed_var.hasOwnProperty('length')){
			return mixed_var.length;
		}
		
		for (key in mixed_var) {
			// TODO: should we check for own properties only?
			//if (	.hasOwnProperty(key)) {
			length++;
			//}
		}
		
		return length;
	}
	
	length = String(mixed_var).length;

	return length;
};

// Create Widget list dropdown
function pagelayer_create_widget_tooltip(){

	var html = '<div class="pagelayer-widget-tooltip">'+
			'<div class="pagelayer-widget-search-holder">'+
				'<div class="pagelayer-widget-search">'+
					'<i class="pli pli-search" ></i><input class="pagelayer-search-field" /><span class="pagelayer-sf-empty pli">&times;</span>'+
				'</div>'+
			'</div>';
	
	for(var x in pagelayer_groups){
		
		// Title
		html += '<div class="pagelayer-widget-group pagelayer-group-name-'+x+'"><h5>'+x+'</h5>';
		
		// Indivdual icon
		for(var y in pagelayer_groups[x]){
			
			var sc = pagelayer_groups[x][y];
			
			if(!(sc in pagelayer_shortcodes) || 'not_visible' in pagelayer_shortcodes[sc]){
				continue;
			}
			
			html += '<div class="pagelayer-shortcode-holder" pagelayer-tag="'+sc+'">'+
				'<div class="pagelayer-pointer pagelayer-sc">'+
					'<center class="pagelayer-shortcode-inner">';
					
					if('icon' in pagelayer_shortcodes[sc]){
						html += '<i class="pagelayer-shortcode '+pagelayer_shortcodes[sc]['icon']+'"></i>';
					}else{
						html += '<i class="pagelayer-shortcode pli pagelayer-'+sc+'"></i>';
					}
					
					html += '</center>'+
					'<span class="pagelayer-pointer pagelayer-shortcode-text">'+pagelayer_shortcodes[sc]['name']+'</span>'+
				'</div>'+
			'</div>';
			
		}
		
		html += '</div>';
		
	}
	
	html += '</div>';
		
	pagelayer.$$('body').append(html);
	
	var wdHolder = pagelayer.$$('.pagelayer-widget-tooltip');
	
	// Hide the ones which are not supposed to be shown
	wdHolder.find('.pagelayer-search-field').on('input', function(){
		
		var val = jQuery(this).val();
		var re = new RegExp(val, 'i');
		
		// Show only the required tags
		wdHolder.find('.pagelayer-widget-group').each(function(){
			
			var group = jQuery(this);
			var res = group.find('[pagelayer-tag]');
			var hidden = 0;
			
			res.each(function(){
				
				var tEle = jQuery(this);
				if(tEle.find('.pagelayer-shortcode-text').html().match(re)){
					tEle.show();
				}else{
					hidden += 1;
					tEle.hide();
				}
				
			});
			
			// Hide the whole group
			if(hidden == res.length){
				group.hide();
			}else{
				group.show();
			}
				
		});

		wdHolder.find('.pagelayer-shortcode-holder:visible').first().trigger('widget_active');
		
	});
	
	// On click search empty
	wdHolder.find('.pagelayer-widget-search>.pagelayer-sf-empty').click(function(){
		wdHolder.find('.pagelayer-search-field').val('').trigger('input');
	});
	
	// Register widget active event
	wdHolder.find('.pagelayer-shortcode-holder').on('widget_active', function(){
		var activeEle = jQuery(this);
		wdHolder.find('.pagelayer-list-widget-active').removeClass('pagelayer-list-widget-active');
		
		if(!activeEle.hasClass('pagelayer-list-widget-active')){
			activeEle.addClass('pagelayer-list-widget-active');
		}
		
		activeEle[0].scrollIntoView({behavior: "smooth", block: "end"});
	});
	
	pagelayer.gDocument.on('mousedown.pagelayer_wdlist', function(e){
		var target = jQuery(e.target);
		
		if(target.closest('.pagelayer-widget-tooltip').is(wdHolder)){
			return;
		}
    
		wdHolder.find('.pagelayer-shortcode-holder:visible').first().trigger('widget_active');
    
		wdHolder.hide();
		jQuery('.pagelayer-show-wiget-list').removeClass('pagelayer-show-wiget-list');
		jQuery(window).off('scroll.pagelayer_wdlist resize.pagelayer_wdlist');
	});
  
}

// Show Widget list dropdown
function pagelayer_show_widget_list(jEle, val){
	
	val = val || '';
	jEle = jQuery(jEle);
		
	var wEle = pagelayer.$$('.pagelayer-widget-tooltip'),
	winH = jQuery(window).height(),
	iframe = pagelayer.$$('#pagelayer-iframe'),
	iframeTop = iframe.offset().top,
	iframeLeft = iframe.offset().left,
	style = {},
	wTop = 'auto',
	wBottom = 'auto',
	wLeft = '';
	wHeight = '';
  
	searchField = wEle.find('.pagelayer-search-field');
	searchField.val(val);
	searchField.trigger('input');
	
	// Add widget show class
	if(jEle.hasClass('pagelayer-shortcode-plus')){
		jEle.parent('.pagelayer-ele-overlay').addClass('pagelayer-show-wiget-list');
	}
	
	var bounds = jEle[0].getBoundingClientRect();
  
	wEle.removeClass('pagelayer-widget-list-tooltip');
	wLeft = (bounds.left + iframeLeft) - wEle.width() / 2;
  
	// In list view?
	if(jEle.closest('[pagelayer-editable]').length > 0){
		wEle.addClass('pagelayer-widget-list-tooltip');
		var selection = window.getSelection();
		var range = selection.getRangeAt(0);
		wLeft = (range.getBoundingClientRect().left + iframeLeft) - wEle.width() / 2;
	}
	
	wEle.closest('.pagelayer-widget-tooltip').show();
	wEle.find('.pagelayer-shortcode-holder:visible').first().trigger('widget_active');
	
	// Hide Widget list
	if(jEle.closest('[pagelayer-editable]').length > 0 && wEle.find('.pagelayer-widget-group:visible').length < 1){
		pagelayer.gDocument.trigger('mousedown.pagelayer_wdlist');
		return;		
	}else{
		searchField.focus().select();
	}
	
	var docW = iframeLeft + iframe.width() - 30;
	
	// Prevent to hide on left or right
	if(docW < wLeft + wEle.width()){
		wLeft = docW - wEle.width();
	}else if(iframeLeft > wLeft){
		wLeft = iframeLeft;
	}
	
	if(winH / 2 < bounds.top + 10){
		wBottom = winH - bounds.top + 10;
		wHeight = bounds.top - 10;
	}else{
		wTop = bounds.bottom + iframeTop + 10;
		wHeight = winH - bounds.bottom - 10;
	}
	
	style['left'] = wLeft;
	style['top'] = wTop;
	style['bottom'] = wBottom;
	style['max-height'] = '';
	
	if(wHeight < 350){
		style['max-height'] = wHeight;
	}
	
	wEle.css(style);
	
	jQuery(window).off('scroll.pagelayer_wdlist resize.pagelayer_wdlist');
	jQuery(window).on('scroll.pagelayer_wdlist resize.pagelayer_wdlist', function(){
		var _val = wEle.find('.pagelayer-search-field').val();
		pagelayer_show_widget_list(jEle, _val);
	});
				
	wEle.find('.pagelayer-shortcode-holder').off('click');
	wEle.find('.pagelayer-shortcode-holder').on('click', function(e){
				
		var tag = jQuery(this).attr('pagelayer-tag');
		var mWrap = jEle.closest('.pagelayer-ele-wrap[pagelayer-wrap-id]');
		var mTag = pagelayer_tag(mWrap);
		
		var ele = jQuery('<div pagelayer-tag="'+tag+'"></div>');
		
		// Is col?
		if(mTag == 'pl_col'){
			var colHolder = mWrap.find('>.pagelayer-col > .pagelayer-col-holder');
			colHolder.append(ele);
			pagelayer_empty_col(colHolder);
		}else{
			mWrap.after(ele);
		}
		
		// Replace widget
		if(jEle.closest('[pagelayer-editable]').length > 0){
			pagelayer_delete_element(mWrap.find('>.pagelayer-ele'));
		}
		
		var eleId = pagelayer_onadd(ele, false);
		var eEle = pagelayer_ele_by_id(eleId);
		
		// Create Column
		if( tag == 'pl_inner_row' ){
			var in_col = jQuery('<div pagelayer-tag="pl_col"></div>');
			eEle.find('>.pagelayer-row-holder').append(in_col);
			var in_col_id = pagelayer_onadd(in_col, false);
		}
		
		eEle.click();
		
		// Hide Widget list
		pagelayer.gDocument.trigger('mousedown.pagelayer_wdlist');
	});
  
}

// Set Selection By Character Offsets
function pagelayer_setCaret(containerEl, start, end){
	
	end = end || start;
	
	// Refered from http://jsfiddle.net/zQUhV/47/
	if(window.getSelection && document.createRange){
		
		var charIndex = 0, range = document.createRange();
		range.setStart(containerEl, 0);
		range.collapse(true);
		var nodeStack = [containerEl], node, foundStart = false, stop = false;

		while (!stop && (node = nodeStack.pop())) {
			if (node.nodeType == 3) {
				var nextCharIndex = charIndex + node.length;
				if (!foundStart && start >= charIndex && start <= nextCharIndex) {
					range.setStart(node, start - charIndex);
					foundStart = true;
				}
				if (foundStart && end >= charIndex && end <= nextCharIndex) {
					range.setEnd(node, end - charIndex);
					stop = true;
				}
				charIndex = nextCharIndex;
			} else {
				var i = node.childNodes.length;
				while (i--) {
					nodeStack.push(node.childNodes[i]);
				}
			}
		}

		var sel = window.getSelection();
		sel.removeAllRanges();
		sel.addRange(range);
		
	} else if (document.selection) {
		var textRange = document.body.createTextRange();
		textRange.moveToElementText(containerEl);
		textRange.collapse(true);
		textRange.moveEnd("character", end);
		textRange.moveStart("character", start);
		textRange.select();
	}
}

// Set Selection By Character Offsets
function pagelayer_content_line(containerEl){
	
	var lines = [], charIndex = 0, range = document.createRange();
	range.setStart(containerEl, 0);
	range.collapse(true);
	var bounding = range.getBoundingClientRect();
	var nodeStack = [containerEl], node, prevX = bounding.x, nextStart = 0;
	
	while(node = nodeStack.pop()){
		if (node.nodeType == 3) {
			for(var i = 1; i <= node.length; i++){
				range.setStart(node, i);
				range.setEnd(node, i);
				bounding = range.getBoundingClientRect();
				charIndex ++;

				if(prevX > bounding.x){
					lines.push({start:nextStart, end:charIndex - 1});
					nextStart = charIndex;
				}
				prevX = bounding.x;
			}
		} else {
			var i = node.childNodes.length;
			while(i--){
				nodeStack.push(node.childNodes[i]);
			}
		}
	}
	
	// Push last line
	if(nextStart != charIndex || nextStart == 0){
		lines.push({start:nextStart, end:charIndex});
	}
	
	return lines;
}

//http://jsfiddle.net/TjXEG/900/
function pagelayer_getCaretCharacterOffsetWithin(element){
	var caretOffset = 0;
	var doc = element.ownerDocument || element.document;
	var win = doc.defaultView || doc.parentWindow;
	var sel;
	if( typeof win.getSelection != "undefined" ){
		sel = win.getSelection();
		if (sel.rangeCount > 0) {
			var range = win.getSelection().getRangeAt(0);
			var preCaretRange = range.cloneRange();
			preCaretRange.selectNodeContents(element);
			preCaretRange.setEnd(range.endContainer, range.endOffset);
			caretOffset = preCaretRange.toString().length;
		}
	}else if( (sel = doc.selection) && sel.type != "Control" ){
		var textRange = sel.createRange();
		var preCaretTextRange = doc.body.createTextRange();
		preCaretTextRange.moveToElementText(element);
		preCaretTextRange.setEndPoint("EndToEnd", textRange);
		caretOffset = preCaretTextRange.text.length;
	}
	return caretOffset;
}

Youez - 2016 - github.com/yon3zu
LinuXploit