PluginProbe
Page Builder: Pagelayer – Drag and Drop website builder / 2.2.2
Page Builder: Pagelayer – Drag and Drop website builder v2.2.2
2.2.2 2.2.1 2.2.0 2.1.9 2.1.8 2.1.7 2.1.6 2.1.5 2.1.4 2.1.3 trunk 0.9.0 0.9.1 0.9.2 0.9.3 0.9.4 0.9.5 0.9.6 0.9.7 0.9.8 0.9.9 1.0.0 1.0.2 1.0.3 1.0.4 All 130 releases
← All changes | js/pagelayer-editor.js +4553 -607 1.0.4 → 2.2.2 View file →
@@ -8,20 +8,105 @@
8 8 $: jQuery,
9 9 $$ : function(select){
10 10 return jQuery(select, window.parent.document);
11 11 },
12 + gDocument : jQuery(window.parent.document).add(document),
12 13 p : this,
13 14 copy_selected: '',
14 15 mouse: {x: -1, y: -1},
15 16 history_action : true,
17 + global_render : true,
18 + history_lastTime : new Date(),
19 + props_ref : {},
20 + pro_txt : '',
21 + loaded : 0,
22 + post_status : '',
23 + el: {},// All elements data
16 24 }
17 25
18 26 var pagelayer_history_obj = {}, pagelayer_revision_obj = {};
19 27 var pagelayer_add_section_data = {};
20 28
29 +// Console error manager
30 +window.onerror = function (msg, url, lineNo, columnNo, error) {
31 +
32 + if (typeof pagelayer_doc_width === 'undefined') {
33 + var test_giver = -1;
34 +
35 + jQuery.ajax({
36 + url: pagelayer_url+'/js/givejs.php?test=1',
37 + type: "GET",
38 + dataType: "text",
39 + success: function(data){
40 +
41 + if(data != 1){
42 + return;
43 + }
44 +
45 + test_giver = 1;
46 + },
47 + complete: function(data){
48 + jQuery.ajax({
49 + type: "POST",
50 + url: pagelayer_ajax_url+"&action=pagelayer_set_jscss_giver",
51 + data: {
52 + pagelayer_nonce: pagelayer_ajax_nonce,
53 + set : test_giver
54 + },
55 + error: function(errorThrown){
56 + console.log("Error saving giver data");
57 + console.log(errorThrown);
58 + }
59 + });
60 + }
61 + });
62 + }
63 +
64 + var string = msg.toLowerCase();
65 + var substring = "script error";
66 +
67 + if(pagelayer.loaded > 0){
68 + return;
69 + }
70 +
71 + if (string.indexOf(substring) > -1){
72 + return;
73 + }
74 +
75 + if(url.indexOf('pagelayer')=== -1){
76 + return;
77 + }
78 +
79 + var message = [
80 + "Message: " + msg,
81 + "\r\n<br>URL: " + url,
82 + "\r\n<br>Line: " + lineNo,
83 + "\r\n<br>Column: "+ columnNo,
84 + "\r\n<br>Error object: " + error
85 + ].join('\n');
86 + //alert("Script Error: See browser console for details");
87 +
88 + pagelayer.$$('.pagelayer-errorBox-content').html(message);
89 + pagelayer.$$('.pagelayer-errorBox-close').on('click', function(){
90 + pagelayer.$$('.pagelayer-errorBox').fadeOut();
91 + });
92 + pagelayer.$$('.pagelayer-errorBox').fadeIn();
93 +
94 + return false;
95 +};
96 +
21 97 // Lets start
22 -jQuery(document).ready(function(){
98 +jQuery(document).ready(pagelayer_start);
99 +
100 +// Function to load the codes
101 +function pagelayer_start(){
23 102
103 + pagelayer.loading = 1;
104 + console.log('['+pagelayer_brand+'] Starting Pagelayer');
105 +
106 + // Prevent the click Insite editor
107 + pagelayer_prevent_click();
108 +
24 109 // Set the title of the parent window
25 110 try{ pagelayer.$$('head').append(pagelayer.$('title')[0].outerHTML); }catch(e){};
26 111
27 112 pagelayer.blank_img = pagelayer_url+'/images/default-image.png';
@@ -28,15 +113,21 @@
28 113
29 114 pagelayer_shortcodes['pl_inner_row'] = JSON.parse(JSON.stringify(pagelayer_shortcodes['pl_row']));
30 115 pagelayer_shortcodes['pl_inner_row']['name'] = 'Inner Row';
31 116 pagelayer_groups['grid'].push('pl_inner_row');
117 +
118 + // Removing post props options
119 + pagelayer_setting_post_props();
32 120
33 121 // Make the Topbar
34 122 pagelayer_bottombar();
35 123
36 124 // Make the Leftbar
37 - pagelayer_leftbar();
38 -
125 + pagelayer_leftbar();
126 +
127 + // Make widget list toolbar
128 + pagelayer_create_widget_tooltip();
129 +
39 130 // Add widget section
40 131 pagelayer_add_widget();
41 132
42 133 // Setup the ELPD
@@ -41,8 +132,11 @@
41 132
42 133 // Setup the ELPD
43 134 pagelayer_elpd_setup();
44 135
136 + // Dump the data we have
137 + pagelayer_element_dump_data();
138 +
45 139 // Setup the properties of the elements
46 140 pagelayer_element_setup();
47 141
48 142 // An image to show for drag
@@ -56,8 +150,11 @@
56 150
57 151 // Set to desktop
58 152 pagelayer_set_screen_mode('desktop');
59 153
154 + // Create list of fonts
155 + pagelayer_fonts = pagelayer_l('pl_fonts_list');
156 +
60 157 // Set up right click
61 158 pagelayer_left_click();
62 159 pagelayer_right_click();
63 160
@@ -64,8 +161,14 @@
64 161 // Setup pagelayer history handle
65 162 pagelayer_history_obj['action_data'] = [];
66 163 pagelayer_history_setup(true);
67 164
165 + // Make a quick access of the props
166 + pagelayer_make_props_ref();
167 +
168 + // Post props exported defaults need to be updated
169 + pagelayer_set_exported_defaults();
170 +
68 171 // Do any actions here
69 172 pagelayer_trigger_action('pagelayer_setup_history');
70 173
71 174 // Editor Tooltips
@@ -80,10 +183,252 @@
80 183 pagelayer_icons[item] = JSON.parse(pagelayer_get_stored_data(pagelayer_url+'/fonts/'+item+'.json', pagelayer_ver));
81 184 });
82 185 };
83 186
84 -});
187 + // Set row-option top zero(0) of the first row
188 + pagelayer_set_row_option_position();
189 +
190 + // Just the txt
191 + pagelayer.pro_txt = pagelayer_pro_txt;
192 +
193 + // Open post props on document load
194 + pagelayer.$$('.pagelayer-settings').click();
195 +
196 + // Open post props and Make elements editable to edit post props data
197 + pagelayer_setup_props_editable();
198 +
199 + // Make elements editable
200 + jQuery(pagelayer_editable+' [pagelayer-editable]').attr('contenteditable', 'true');
201 +
202 + // Use text widget for search widget
203 + pagelayer_search_widgets();
204 +
205 + // Hide the loader
206 + pagelayer_loader_hide();
207 +
208 + // ON comment mode
209 + const urlParams = new URLSearchParams(window.location.search);
210 + pagelayer.cmode = urlParams.get('cmode');
211 +
212 + // Start custom UX Improvements engine
213 + setTimeout(pagelayer_ux_improvements_init, 200);
214 +}
85 215
216 +// Post props attribute
217 +function pagelayer_post_props_atts(prop, val, temp){
218 +
219 + val = val || null;
220 + temp = temp || false;
221 +
222 + var proEle = jQuery(pagelayer_editable+' .pagelayer-post_props.pagelayer-ele').first();
223 +
224 + if(!pagelayer_empty(temp)){
225 + if(val === null){
226 + return pagelayer_get_tmp_att(proEle, prop);
227 + }
228 +
229 + // Set the temp property as well
230 + pagelayer_set_tmp_atts(proEle, prop, val);
231 + return true;
232 + }
233 +
234 + if(val === null){
235 + return pagelayer_get_att(proEle, prop);
236 + }
237 +
238 + // Set the property as well
239 + pagelayer_set_atts(proEle, prop, val);
240 + return true;
241 +}
242 +
243 +// Open post props and Make elements editable to edit post props data
244 +function pagelayer_setup_props_editable(){
245 +
246 + jQuery('[pagelayer-props-editable]').each(function(){
247 + var jEle = jQuery(this);
248 +
249 + // Skip element under the editable area
250 + if (jEle.closest(pagelayer_editable).length > 0) {
251 + return;
252 + }
253 +
254 + var prop = jEle.attr('pagelayer-props-editable');
255 +
256 + // Make editable
257 + jEle.attr('contenteditable', 'true');
258 +
259 + // Reverse setup the event
260 + jEle.on('focus', function(){
261 + // Set the property as well
262 + var data = pagelayer_post_props_atts(prop);
263 + jEle.html(data);
264 + });
265 +
266 + // Reverse setup the event
267 + jEle.on('input', function(){
268 +
269 + var val = pagelayer_trim(jEle.html());
270 +
271 + // Set the property as well
272 + pagelayer_post_props_atts(prop, val);
273 +
274 + // Update the property
275 + var input = pagelayer.$$('[pagelayer-elp-name='+prop+']').find('input,textarea,.trumbowyg-editor');
276 + //console.log(input);
277 +
278 + if(input.length > 0){
279 + if(input.hasClass('trumbowyg-editor')){
280 + input.html(val);
281 + }else{
282 + input.val(val);
283 + }
284 + }
285 +
286 + });
287 +
288 + });
289 +
290 +}
291 +
292 +// Prevent the click Insite editor
293 +function pagelayer_prevent_click(){
294 + jQuery(document).on('submit', function(event){
295 + var target = jQuery(event.target);
296 + if (target.closest(pagelayer_editable).length < 1) {
297 + event.preventDefault();
298 + }
299 + });
300 +
301 + jQuery(document).on('click', function(event){
302 + var target = jQuery(event.target);
303 + if (target.closest('a').length > 0 && target.closest(pagelayer_editable).length < 1) {
304 + event.preventDefault()
305 + }
306 + });
307 +}
308 +
309 +// Removing post props options from the editor
310 +function pagelayer_setting_post_props(){
311 +
312 + if(pagelayer_empty(pagelayer_post_categories)){
313 + delete pagelayer_shortcodes.pl_post_props.postCategory;
314 + }
315 +
316 + if(pagelayer_empty(pagelayer_post_tags)){
317 + delete pagelayer_shortcodes.pl_post_props.postTags;
318 + }
319 +
320 + if(pagelayer_empty(pagelayer_shortcodes.pl_post_props.pageParent.post_parent.list)){
321 + delete pagelayer_shortcodes.pl_post_props.pageParent;
322 + }
323 +
324 + if(pagelayer_post.post_type != 'post'){
325 + delete pagelayer_shortcodes.pl_post_props.params.post_sticky;
326 + }
327 +
328 + if(pagelayer_empty(pagelayer_post_type_features['comments'])){
329 + delete pagelayer_shortcodes.pl_post_props.postDiscussion.comment_status;
330 + }
331 +
332 + if(pagelayer_empty(pagelayer_post_type_features['trackbacks'])){
333 + delete pagelayer_shortcodes.pl_post_props.postDiscussion.ping_status;
334 + }
335 +
336 + if(pagelayer_empty(pagelayer_shortcodes.pl_post_props.postDiscussion)){
337 + delete pagelayer_shortcodes.pl_post_props.postDiscussion;
338 + }
339 +
340 + if(pagelayer_empty(pagelayer_post_type_features['excerpt'])){
341 + delete pagelayer_shortcodes.pl_post_props.postExcerpt;
342 + }
343 +
344 + if(pagelayer_empty(pagelayer_post_type_features['thumbnail'])){
345 + delete pagelayer_shortcodes.pl_post_props.postFeaturedImage;
346 + }
347 +
348 + if(pagelayer_empty(pagelayer_post_type_features['author'])){
349 + delete pagelayer_shortcodes.pl_post_props.params.post_author;
350 + }
351 +}
352 +
353 +// Set the default values of all default exported codes
354 +function pagelayer_set_exported_defaults(){
355 +
356 + // Set defaults for the exported variety
357 + if(pagelayer_empty(pagelayer_default_params)){
358 + return;
359 + }
360 +
361 + for(var tag in pagelayer_default_params){
362 +
363 + for(var x in pagelayer_default_params[tag]){
364 +
365 + if(x in pagelayer.props_ref[tag]){
366 + pagelayer.props_ref[tag][x]['default'] = pagelayer_default_params[tag][x];
367 + }
368 +
369 + }
370 +
371 + }
372 +
373 +}
374 +
375 +// Do pagelayer Dirty
376 +function pagelayer_do_dirty(jEle){
377 +
378 + pagelayer_isDirty = true;
379 +
380 + if (!window.onbeforeunload) {
381 + window.onbeforeunload = function(){
382 + return true;
383 + };
384 + }
385 +
386 + pagelayer_trigger_action('pagelayer_do_dirty', [jEle]);
387 +}
388 +
389 +function pagelayer_do_undirty(){
390 +
391 + pagelayer_isDirty = false;
392 +
393 + if (window.onbeforeunload) {
394 + window.onbeforeunload = null;
395 + }
396 +
397 +}
398 +
399 +// Executes when pagelayer is fully loaded
400 +function pagelayer_loader_hide(){
401 + var inner = pagelayer.$$('.pagelayer-percent');
402 + inner.attr('loaded', 1);
403 + var w = parseInt(inner.text());
404 + var t = setInterval(function() {
405 + w = w + 1;
406 + inner.html(w +'<sup>%</sup>');
407 + if (w >= 100){
408 + clearInterval(t);
409 + w = 0;
410 + var loaderWrapper = pagelayer.$$('#pagelayer-loader-wrapper');
411 + loaderWrapper.addClass('pagelayer-loaded');
412 + loaderWrapper.animate({opacity:0}, function(){
413 + loaderWrapper.remove();
414 + });
415 + }
416 + }, 1);
417 + pagelayer.loaded = 1;
418 +}
419 +
420 +// Set row-option top zero(0) of the first row
421 +function pagelayer_set_row_option_position(){
422 + try{
423 + if(jQuery(pagelayer_editable).offset().top < 20){
424 + jQuery(pagelayer_editable).addClass('pagelayer-row-option-zero');
425 + }
426 + }catch(e){
427 + console.log(pagelayer_editable+" not found and hence Pagelayer wont work on this page !");
428 + }
429 +}
430 +
86 431 // The jQuery Object of the ELPD
87 432 var pagelayer_elpd;
88 433
89 434 // Store data values
@@ -163,9 +508,9 @@
163 508 var pl_iframe = pagelayer.$$('.pagelayer-iframe'),
164 509 pl_leftbar = pagelayer.$$('.pagelayer-leftbar-table');
165 510
166 511 // On mouse down in pagelayer-topbar-holder
167 - pagelayer.$$('.pagelayer-topbar-holder').on('mousedown', function(e){
512 + pagelayer.$$('.pagelayer-topbar-mover').on('mousedown', function(e){
168 513 e = e || window.event;
169 514 e.preventDefault();
170 515
171 516 // Get leftbar position
@@ -177,9 +522,8 @@
177 522 var posY = e.clientY;
178 523
179 524 // The variable needs to be empty.
180 525 var newMethod = '',
181 - par_doc = jQuery(window.parent.document).add(document),
182 526 change = true;
183 527
184 528 var leftbar_mousemove = function(e){
185 529 e = e || window.event;
@@ -232,10 +576,10 @@
232 576
233 577 var leftbar_mouseup = function(e){
234 578
235 579 // Remove events
236 - par_doc.off('mousemove', leftbar_mousemove);
237 - par_doc.off('mouseup', leftbar_mouseup);
580 + pagelayer.gDocument.off('mousemove', leftbar_mousemove);
581 + pagelayer.gDocument.off('mouseup', leftbar_mouseup);
238 582
239 583 // Remove class to leftbar
240 584 pagelayer.$$('.pagelayer-leftbar-move').remove();
241 585
@@ -258,10 +602,10 @@
258 602 // make change true
259 603 change = true;
260 604 };
261 605
262 - par_doc.on('mouseup', leftbar_mouseup);
263 - par_doc.on('mousemove', leftbar_mousemove);
606 + pagelayer.gDocument.on('mouseup', leftbar_mouseup);
607 + pagelayer.gDocument.on('mousemove', leftbar_mousemove);
264 608
265 609 });
266 610
267 611 }
@@ -384,9 +728,21 @@
384 728 var onWrap;
385 729
386 730 // If we are a column, we can be over another column or row
387 731 if(tag == 'pl_col'){
388 - onWrap = jQuery(ele).closest('.pagelayer-wrap-col,.pagelayer-wrap-row,.pagelayer-wrap-inner-row');
732 +
733 + // Prevent column in inner-row and it's columns, if the draged column have inner-rows
734 + if(wrap.find('.pagelayer-wrap-inner-row').length > 0){
735 + onWrap = jQuery(ele).closest('.pagelayer-wrap-col,.pagelayer-wrap-row');
736 +
737 + var innerRow = onWrap.closest(pagelayer_editable +' .pagelayer-wrap-inner-row');
738 + if( onWrap.length < 1 || innerRow.length > 0){
739 + onWrap = jQuery(innerRow).closest('.pagelayer-wrap-col,.pagelayer-wrap-row');
740 + }
741 +
742 + }else{
743 + onWrap = jQuery(ele).closest('.pagelayer-wrap-col,.pagelayer-wrap-row,.pagelayer-wrap-inner-row');
744 + }
389 745 //console.log(pagelayer_id(onWrap));
390 746
391 747 // If we are a row, we can be over another row or a column
392 748 }else if(tag == 'pl_row'){
@@ -407,8 +763,70 @@
407 763 }
408 764 // For every other element, we can be over a col or ele
409 765 }else{
410 766 onWrap = jQuery(ele).closest('.pagelayer-wrap-ele,.pagelayer-wrap-col,.pagelayer-wrap-inner-row');
767 +
768 + // If we are inside the same widget tag
769 + // We are allowing for now, hence the following is commented
770 + /*var sameTag = onWrap.closest(pagelayer_editable +' [pagelayer-tag="'+tag+'"]');
771 + if(sameTag.length > 0){
772 + onWrap = sameTag.closest('.pagelayer-wrap-ele');
773 + }*/
774 +
775 + // Is prevent to go inside any widget?
776 + if('prevent_inside' in pagelayer_shortcodes[tag] && !pagelayer_empty(pagelayer_shortcodes[tag]['prevent_inside'])){
777 +
778 + var preTags = pagelayer_shortcodes[tag]['prevent_inside'];
779 + var prevent_inside = false;
780 + var preEle = onWrap;
781 +
782 + if(typeof preTags === 'string'){
783 + preTags = [preTags];
784 + }
785 +
786 + for(var toFind in preTags){
787 + preEle = onWrap.closest(pagelayer_editable +' [pagelayer-tag="'+preTags[toFind]+'"]');
788 + if (preEle.length > 0) {
789 + prevent_inside = true;
790 + break;
791 + }
792 + }
793 +
794 + // If we find
795 + if(prevent_inside){
796 + onWrap = preEle.closest('.pagelayer-wrap-ele');
797 + }
798 + }
799 +
800 + var widGroup = onWrap.closest('.pagelayer-ele-widget-group');
801 +
802 + // If we are inside the group widget
803 + if(widGroup.length > 0 && widGroup.closest(pagelayer_editable).length > 0){
804 +
805 + var wGroupTag = pagelayer_tag(widGroup);
806 + var use_inside = false;
807 +
808 + // If defined use inside only
809 + if('use_inside' in pagelayer_shortcodes[tag] && !pagelayer_empty(pagelayer_shortcodes[tag]['use_inside'])){
810 +
811 + var inTags = pagelayer_shortcodes[tag]['use_inside'];
812 +
813 + if(typeof inTags === 'string'){
814 + inTags = [inTags];
815 + }
816 +
817 + for(var toFind in inTags){
818 + if (wGroupTag == inTags[toFind]) {
819 + use_inside = true;
820 + }
821 + }
822 + }
823 +
824 + // If we find nothing
825 + if(!use_inside){
826 + onWrap = widGroup.parent('.pagelayer-wrap-ele');
827 + }
828 + }
411 829 }
412 830 //console.log(onWrap);
413 831
414 832 // If we find nothing
@@ -436,20 +854,29 @@
436 854 }
437 855 }*/
438 856
439 857 // Get the ID
440 - var onId = onWrap.attr('pagelayer-wrap-id');
441 - var onEle = onWrap.children('.pagelayer-ele');
858 + var onId = pagelayer_id(onWrap);
859 + var onEle = pagelayer_ele_by_id(onId);
442 860
443 861 // Do we have a parent ?
444 - var pOnId = pagelayer_get_parent(onEle);
445 -
446 - if(pOnId){
862 + var have_parent = function(Ele){
863 + var pOnId = pagelayer_get_parent(Ele);
864 +
865 + if(pagelayer_empty(pOnId) || tag == 'pl_col'){
866 + return;
867 + }
868 +
447 869 onId = pOnId;
448 - onEle = pagelayer_ele_by_id(onId);
449 - onWrap = pagelayer_wrap_by_id(onId);
870 + onEle = pagelayer_ele_by_id(pOnId);
871 + onWrap = pagelayer_wrap_by_id(pOnId);
872 + have_parent(onEle);
873 +
450 874 }
451 875
876 + // Do we have a parent ?
877 + have_parent(onEle);
878 +
452 879 var changed = false;
453 880
454 881 // Was it the same ID like the one we were on before
455 882 if(pagelayer.drag_closest != onId){
@@ -489,10 +916,10 @@
489 916 }
490 917
491 918 //console.log(changed);
492 919
493 - // If we are on our self then clear return false
494 - if(onId == id){
920 + // If we are on our self then clear return false and we are on hide active widget
921 + if(onId == id || onWrap.hasClass('pagelayer-hide-active')){
495 922 clear_prospect();// Clear existing prospects
496 923 reset_on_drag();// Also reset the last on item
497 924 return false;
498 925 }
@@ -589,10 +1016,17 @@
589 1016 e.preventDefault();
590 1017
591 1018 var wrap = pagelayer.dragging;
592 1019 var tag = pagelayer_tag(wrap);
1020 + var gId = wrap.attr('pagelayer-global-id');
593 1021 var fromEl = wrap.parent();
594 1022 var id;
1023 +
1024 + // Global ID is there for sure ?
1025 + if(pagelayer_empty(gId) || pagelayer_empty(pagelayer_global_widgets[gId])){
1026 + gId = 0;
1027 + }
1028 +
595 1029 wrap.removeClass('pagelayer-is-dragging');
596 1030
597 1031 // Find any prospect
598 1032 var prospect = jQuery('.pagelayer-drag-prospect');
@@ -609,10 +1043,15 @@
609 1043 var method = (corner == 'top') ? 'before' : 'after';
610 1044 var before_loc; // Location before the drop
611 1045
612 1046 // Create the element if it needs to be created
613 - if(pagelayer.drag_is_new){
1047 + if(pagelayer.drag_is_new){
614 1048 dropped = jQuery('<div pagelayer-tag="'+tag+'"></div>');
1049 +
1050 + // Is there a global ID
1051 + if(!pagelayer_empty(gId)){
1052 + dropped.attr('pagelayer-global-id', gId);
1053 + }
615 1054
616 1055 // Move the object
617 1056 }else{
618 1057
@@ -641,8 +1080,15 @@
641 1080
642 1081 // Trigger the onadd
643 1082 if(pagelayer.drag_is_new){
644 1083 id = pagelayer_onadd(dropped);
1084 +
1085 + // Create Column
1086 + if((tag == 'pl_row' || tag == 'pl_inner_row') && pagelayer_empty( dropped.attr('pagelayer-global-id') )){
1087 + var col = jQuery('<div pagelayer-tag="pl_col"></div>');
1088 + jQuery('[pagelayer-id="'+id+'"]').find('.pagelayer-row-holder').append(col);
1089 + var col_id = pagelayer_onadd(col, false);
1090 + }
645 1091
646 1092 // Existing elements
647 1093 }else{
648 1094 id = pagelayer_id(wrap);
@@ -655,9 +1101,9 @@
655 1101 'before_loc' : before_loc,
656 1102 'after_loc' : {'method' : method, 'cEle' : onWrap}
657 1103 });
658 1104
659 - pagelayer_isDirty = true;
1105 + pagelayer_do_dirty(pagelayer_ele_by_id(id));
660 1106 }
661 1107
662 1108 // Defining the variables as needed
663 1109 var jEle = pagelayer_ele_by_id(id);
@@ -705,13 +1151,14 @@
705 1151 jQuery(document).on('dragover', ondragover);
706 1152 jQuery(document).on('drop', ondrop);
707 1153
708 1154 // For addition of new elements
709 - pagelayer.$$('[pagelayer-tag]').on('dragstart', function(e){
1155 + pagelayer.$$('.pagelayer-leftbar').on('dragstart', function(e){
710 1156 //console.log(e);
711 1157
712 1158 var tEle = jQuery(e.target);
713 1159 var jEle = tEle.closest('.pagelayer-shortcode-drag');
1160 + var global_id = jEle.attr('pagelayer-global-id');
714 1161
715 1162 // Is it an existing element ?
716 1163 if(jEle.length < 1){
717 1164 return false;
@@ -718,8 +1165,12 @@
718 1165 }
719 1166
720 1167 e.originalEvent.dataTransfer.setData('tag', pagelayer_tag(jEle));
721 1168
1169 + if(!pagelayer_empty(global_id)){
1170 + e.originalEvent.dataTransfer.setData( 'global_id', global_id );
1171 + }
1172 +
722 1173 pagelayer.dragging = jEle;
723 1174 pagelayer.drag_is_new = true;
724 1175
725 1176 });
@@ -763,20 +1214,11 @@
763 1214
764 1215 // Column is becoming blank, so show add ele
765 1216 if(jEle.children().length < 1){
766 1217 //from.addClass('pagelayer-empty-col');
767 - jEle.append('<div class="pagelayer-add-ele pagelayer-ele-wrap"><i class="fa fa-plus"></i><br /><span>Empty column please Drag Widgets</span></div>');
1218 + 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>');
768 1219 //var h = jEle.parent().parent().children('.pagelayer-ele-overlay').height();
769 1220 //jEle.children('.pagelayer-add-ele').height(h);
770 - jEle.find('>.pagelayer-add-ele .fa').unbind('click');
771 - jEle.find('>.pagelayer-add-ele .fa').on('click', function(event){
772 - event.stopPropagation();
773 - pagelayer.$$('.pagelayer-elpd-close').click();
774 -
775 - // Show left bar
776 - pagelayer.$$('.pagelayer-leftbar-table').removeClass('pagelayer-leftbar-hidden pagelayer-leftbar-minimize');
777 -
778 - });
779 1221
780 1222 // Any add ele sign with non-empty columns here ?
781 1223 }else if(jEle.children('.pagelayer-add-ele').length > 0 && jEle.children().length > 1){
782 1224 jEle.children('.pagelayer-add-ele').remove();
@@ -781,8 +1223,16 @@
781 1223 }else if(jEle.children('.pagelayer-add-ele').length > 0 && jEle.children().length > 1){
782 1224 jEle.children('.pagelayer-add-ele').remove();
783 1225 }
784 1226
1227 + jEle.find('>.pagelayer-add-ele .fas').unbind('click');
1228 + jEle.find('>.pagelayer-add-ele .fas').on('click', function(event){
1229 + event.stopPropagation();
1230 + pagelayer.$$('.pagelayer-elpd-close').click();
1231 +
1232 + pagelayer_show_widget_list(jQuery(this));
1233 + });
1234 +
785 1235 });
786 1236
787 1237 };
788 1238
@@ -812,13 +1262,13 @@
812 1262 }
813 1263 }
814 1264 jEle.addClass('pagelayer-col-'+cols);
815 1265 jEle.css({'width': ''});
816 - Ele.addClass('pagelayer-col-'+cols);
817 - Ele.css({'width': ''});
818 1266
819 1267 // Set the att
820 1268 pagelayer_set_atts(Ele, obj);
1269 + pagelayer_set_atts(Ele, 'col_width','');
1270 + pagelayer_sc_render(Ele)
821 1271 });
822 1272 }
823 1273
824 1274 // Make column resizable handler
@@ -844,13 +1294,16 @@
844 1294 var rHolder_width = wrap.closest('.pagelayer-row-holder').width();
845 1295 var new_width, nEle_new_width;
846 1296
847 1297 // Original width
848 - var original_width = wrap.width();
1298 + var original_width = parseFloat(window.getComputedStyle(wrap[0]).getPropertyValue('width'));
1299 + var next_ele_width = parseFloat(window.getComputedStyle(next_ele[0]).getPropertyValue('width'));
849 1300 var original_mouse_x = e.pageX;
850 1301
1302 + var both_width = parseInt(original_width + next_ele_width);
1303 +
851 1304 // Add the element width and next element width
852 - both_width = (original_width / rHolder_width *100) + (next_ele.width() / rHolder_width *100);
1305 + both_width = ((both_width / rHolder_width) *100);
853 1306
854 1307 if(both_width > 100){
855 1308 return false;
856 1309 }
@@ -857,9 +1310,13 @@
857 1310
858 1311 jQuery('body').css({'cursor': 'ew-resize'});
859 1312 rHandler.css({'display': 'block'});
860 1313
1314 + var mousemoved = false;
1315 +
861 1316 var r_mousemove = function(e){
1317 + mousemoved = true;
1318 +
862 1319 var width = original_width + (e.pageX - original_mouse_x);
863 1320
864 1321 // Covert width in percentage
865 1322 new_width = (width / rHolder_width *100).toFixed(2);
@@ -876,19 +1333,31 @@
876 1333
877 1334 var r_mouseup = function(e){
878 1335
879 1336 jQuery(document).off('mousemove', r_mousemove);
1337 + jQuery(document).off('mouseup', r_mouseup);
880 1338 jQuery('body').css({'cursor': ''});
881 1339 rHandler.removeAttr('style pre-width next-width');
882 1340
1341 + // IF mouseMoved
1342 + if(!mousemoved) return;
1343 +
883 1344 // find real element and next real element
884 1345 var jEle = wrap.find('>.pagelayer-ele');
885 1346 var nEle = next_ele.find('>.pagelayer-ele');
886 -
1347 + var mode = pagelayer_get_screen_mode();
1348 + var col_width = 'col_width';
1349 +
1350 + // Do we have screen ?
1351 + if(mode != 'desktop'){
1352 + col_width = col_width +'_'+mode;
1353 + }
1354 +
887 1355 // Set the element attrs
888 - jEle.attr({'pagelayer-a-col_width': new_width, 'pagelayer-a-col': ''});
889 - nEle.attr({'pagelayer-a-col_width': nEle_new_width, 'pagelayer-a-col': ''});
890 - jQuery(document).off('mouseup', r_mouseup);
1356 + pagelayer_set_atts(jEle, col_width, new_width);
1357 + pagelayer_set_atts(jEle, 'col', '');
1358 + pagelayer_set_atts(nEle, col_width, nEle_new_width);
1359 + pagelayer_set_atts(nEle, 'col', '');
891 1360
892 1361 };
893 1362
894 1363 // Resize start
@@ -921,14 +1390,25 @@
921 1390 function pagelayer_element_added(jEle){
922 1391
923 1392 var sc = jEle.attr('pagelayer-tag');
924 1393 var id, par_id;
1394 + var gId = jEle.attr('pagelayer-global-id');
1395 + gId = gId && !pagelayer_empty(pagelayer_global_widgets[gId]) ? gId : 0;
925 1396
926 1397 // Set Pagelayer History FALSE to prevent saving attributes in action history
927 1398 pagelayer.history_action = false;
928 -
1399 + pagelayer.global_render = false;
1400 +
1401 + // Is this a global widget ?
1402 + if(!pagelayer_empty(gId)){
1403 +
1404 + html = pagelayer_element_unsetup(pagelayer_global_widgets[gId].$);
1405 +
929 1406 // Generate the HTML
930 - html = pagelayer_create_sc(sc);
1407 + }else{
1408 + html = pagelayer_create_sc(sc);
1409 + }
1410 +
931 1411 id = pagelayer_assign_id(html);
932 1412 par_id = id;
933 1413
934 1414 // Insert the HTML
@@ -936,8 +1416,13 @@
936 1416
937 1417 // Setup the properties of the elements
938 1418 pagelayer_element_setup("[pagelayer-id="+par_id+"], [pagelayer-id="+par_id+"] .pagelayer-ele", true);
939 1419
1420 + // Is this a global widget ? Then set this as global element
1421 + if(!pagelayer_empty(gId)){
1422 + html = pagelayer_set_ele_global(jQuery('[pagelayer-id="'+par_id+'"]'), gId);
1423 + }
1424 +
940 1425 // Any children to add ?
941 1426 if(!('widget' in pagelayer_shortcodes[sc])){
942 1427
943 1428 // The element props
@@ -944,17 +1429,29 @@
944 1429 var props = pagelayer_shortcodes[sc];
945 1430
946 1431 // Do we have to create children ?
947 1432 if('has_group' in props){
1433 +
1434 + // Is this not a global widget ?
1435 + if(pagelayer_empty(gId)){
1436 + var has_group = props['has_group'];
1437 + var gProp = props[has_group['section']][has_group['prop']];
1438 +
1439 + for(var i=0; i < gProp['count']; i++){
1440 + var cid = pagelayer_element_add_child(jQuery("[pagelayer-id="+id+"]"), gProp['sc'], gProp);
1441 + //pagelayer_element_setup('[pagelayer-id='+cid+']', true);
948 1442
949 - var has_group = props['has_group'];
950 - var gProp = props[has_group['section']][has_group['prop']];
951 -
952 - for(var i=0; i < gProp['count']; i++){
953 - var cid = pagelayer_element_add_child(jQuery("[pagelayer-id="+id+"]"), gProp['sc']);
954 - //pagelayer_element_setup('[pagelayer-id='+cid+']', true);
1443 + var cEle = pagelayer_ele_by_id(cid);
1444 +
1445 + // Set default
1446 + if( 'item_atts' in gProp && i in gProp['item_atts'] && !pagelayer_empty(gProp['item_atts'][i]) ){
1447 + pagelayer_set_atts(cEle, gProp['item_atts'][i]);
1448 + pagelayer_sc_render(cEle);
1449 + }
1450 + }
1451 + }else{
1452 + pagelayer_sc_render(jQuery('[pagelayer-id="'+par_id+'"]'));
955 1453 }
956 -
957 1454 }
958 1455
959 1456 }
960 1457
@@ -964,21 +1461,27 @@
964 1461 pagelayer_history_action_push({
965 1462 'title' : pagelayer_shortcodes[sc]['name'],
966 1463 'action' : 'Added',
967 1464 'pl_id' : id,
968 - 'html' : jQuery("[pagelayer-id="+id+"]"),
1465 + 'html' : jQuery("[pagelayer-id="+id+"]")[0].outerHTML,
969 1466 'cEle' : cEle
970 - });
1467 + });
971 1468
972 1469 // Set pagelayer history TRUE
973 1470 pagelayer.history_action = true;
1471 + pagelayer.global_render = true;
974 1472
1473 + // To update nav item list
1474 + pagelayer_do_dirty(pagelayer_ele_by_id(id));
1475 +
975 1476 return id;
976 1477
977 1478 };
978 1479
979 1480 // Add an element
980 -function pagelayer_element_add_child(pEle, sc){
1481 +function pagelayer_element_add_child(pEle, sc, gProp){
1482 +
1483 + gProp = gProp || {};
981 1484 var child = pagelayer_create_sc(sc);
982 1485 var cid = pagelayer_assign_id(child);
983 1486 pagelayer_set_parent(child, pagelayer_assign_id(pEle));
984 1487
@@ -996,8 +1499,73 @@
996 1499 }
997 1500
998 1501 pagelayer_element_setup('[pagelayer-id='+cid+']', true);
999 1502
1503 + // Certain element have editable areas which are inner rows. For UX we need to add columns for the users
1504 + if(sc == 'pl_inner_row'){
1505 +
1506 + var rHolder = pagelayer_ele_by_id(cid).find('.pagelayer-row-holder');
1507 +
1508 + if( !pagelayer_empty(gProp) && 'inner_content' in gProp){
1509 +
1510 + var inner_content = gProp['inner_content'];
1511 +
1512 + // Add default element
1513 + if(!pagelayer_empty(inner_content)){
1514 +
1515 + var add_sc = function(hEle, _tag, content){
1516 +
1517 + var dEle = jQuery('<div pagelayer-tag="'+_tag+'"></div>');
1518 +
1519 + if(_tag == 'pl_col'){
1520 + hEle = hEle.closest('.pagelayer-row-holder');
1521 + }else{
1522 + hEle = hEle.find('.pagelayer-col-holder');
1523 + }
1524 +
1525 + hEle.append(dEle);
1526 + var curID = pagelayer_onadd(dEle, false);
1527 + var curEle = pagelayer_ele_by_id(curID);
1528 +
1529 + // Set default
1530 + if('atts' in content[_tag]){
1531 + pagelayer_set_atts(curEle, content[_tag]['atts']);
1532 + pagelayer_sc_render(curEle);
1533 + }
1534 +
1535 + // Set inner content
1536 + if('inner_content' in content[_tag]){
1537 + for( var key in content[_tag]['inner_content'] ){
1538 + for( var _key in content[_tag]['inner_content'][key] ){
1539 + add_sc(curEle, _key, content[_tag]['inner_content'][key]);
1540 + }
1541 + }
1542 + }
1543 +
1544 + if(_tag == 'pl_col'){
1545 + // TODO: unable to set col width
1546 + pagelayer_renumber_col(hEle);
1547 + }else{
1548 + pagelayer_empty_col(hEle);
1549 + }
1550 + };
1551 +
1552 + for( var key in inner_content ){
1553 + for( var tag in inner_content[key] ){
1554 + add_sc(rHolder, tag, inner_content[key]);
1555 + }
1556 + }
1557 + }
1558 +
1559 + pagelayer_empty_col(jQuery('[pagelayer-id="'+cid+'"]').find('.pagelayer-col-holder'));
1560 +
1561 + }else{
1562 + var col = jQuery('<div pagelayer-tag="pl_col"></div>');
1563 + rHolder.append(col);
1564 + pagelayer_onadd(col, false);
1565 + }
1566 + }
1567 +
1000 1568 // Do we have to create children ?
1001 1569 if('has_group' in pagelayer_shortcodes[sc]){
1002 1570
1003 1571 var has_group = pagelayer_shortcodes[sc]['has_group'];
@@ -1003,9 +1571,9 @@
1003 1571 var has_group = pagelayer_shortcodes[sc]['has_group'];
1004 1572 var gProp = pagelayer_shortcodes[sc][has_group['section']][has_group['prop']];
1005 1573
1006 1574 for(var i=0; i < gProp['count']; i++){
1007 - var in_cid = pagelayer_element_add_child(jQuery("[pagelayer-id="+cid+"]"), gProp['sc']);
1575 + var in_cid = pagelayer_element_add_child(jQuery("[pagelayer-id="+cid+"]"), gProp['sc'], gProp);
1008 1576 }
1009 1577
1010 1578 }
1011 1579
@@ -1035,8 +1603,14 @@
1035 1603 return id;
1036 1604
1037 1605 }
1038 1606
1607 +// Remove Pagelayer ID class
1608 +function pagelayer_remove_id_class(jEle){
1609 + var id = jEle.attr('pagelayer-id');
1610 + jEle.removeClass('p-'+id);
1611 +}
1612 +
1039 1613 // Assign the jQuery object an ID
1040 1614 function pagelayer_assign_id(jEle){
1041 1615
1042 1616 // Do you have the pagelayer id
@@ -1041,9 +1615,10 @@
1041 1615
1042 1616 // Do you have the pagelayer id
1043 1617 var id = jEle.attr("pagelayer-id");
1044 1618 if(!id || id.length < 1){
1045 - id = pagelayer_randstr(16);
1619 + id = pagelayer_randstr(3)+pagelayer_randInt(9999).toString();
1620 + id = id.toLowerCase();
1046 1621 jEle.attr("pagelayer-id", id);
1047 1622 }
1048 1623
1049 1624 return id;
@@ -1074,11 +1649,13 @@
1074 1649 //pagelayer_clear_editable();// First clear
1075 1650 jEle.find('[pagelayer-editable]').each(function (){
1076 1651 pagelayer_make_editable(jQuery(this), e);
1077 1652 });
1078 -
1653 +
1079 1654 // Show left bar
1080 - pagelayer.$$('.pagelayer-leftbar-table').removeClass('pagelayer-leftbar-hidden pagelayer-leftbar-minimize');
1655 + if(pagelayer_empty(e)){
1656 + pagelayer.$$('.pagelayer-leftbar-table').removeClass('pagelayer-leftbar-hidden pagelayer-leftbar-minimize');
1657 + }
1081 1658
1082 1659 // Lets not rebuild everything to make it faster
1083 1660 if(pagelayer_is_active(jEle)){
1084 1661 return false;
@@ -1083,8 +1660,10 @@
1083 1660 if(pagelayer_is_active(jEle)){
1084 1661 return false;
1085 1662 }
1086 1663
1664 + pagelayer_trigger_action('pagelayer_element_clicked', [jEle]);
1665 +
1087 1666 // Set this as the active element
1088 1667 pagelayer_set_active(jEle);
1089 1668
1090 1669 // Show the properties
@@ -1091,13 +1670,69 @@
1091 1670 pagelayer_elpd_open(jEle);
1092 1671
1093 1672 }
1094 1673
1674 +// Use text widget for search widget
1675 +function pagelayer_search_widgets(hEle){
1676 +
1677 + hEle = hEle || jQuery(pagelayer_editable +' [pagelayer-tag="pl_text"], '+pagelayer_editable +' [pagelayer-tag="pl_heading"]');
1678 +
1679 + hEle.each(function(){
1680 +
1681 + var jEle = jQuery(this);
1682 + var tEle = jEle.find('[pagelayer-editable="text"]');
1683 +
1684 + var addPlaceholder = function(ele){
1685 +
1686 + var tVal = ele.text();
1687 +
1688 + if(pagelayer_empty(tVal)){
1689 + ele.attr('data-placeholder-text', 'Type / to open widget list');
1690 + }else if(ele.attr('data-placeholder-text')){
1691 + ele.removeAttr('data-placeholder-text');
1692 + }
1693 + }
1694 +
1695 + // Add placeholder text
1696 + addPlaceholder(tEle);
1697 +
1698 + tEle.off('input.search_widgets');
1699 + tEle.on('input.search_widgets', function(){
1700 +
1701 + var val = tEle.text();
1702 +
1703 + // Add placeholder text
1704 + addPlaceholder(tEle);
1705 +
1706 + if(val.charAt(0) == "/"){
1707 + val = val.replace('/', '');
1708 + pagelayer_show_widget_list(tEle, val);
1709 + }else if(pagelayer.$$('.pagelayer-widget-tooltip').is(':visible')){
1710 + // Hide Widget list
1711 + pagelayer.gDocument.trigger('mousedown.pagelayer_wdlist');
1712 + }
1713 +
1714 + });
1715 +
1716 + });
1717 +
1718 +}
1719 +
1095 1720 // The edit option
1096 1721 function pagelayer_edit_element(selector){
1097 1722 pagelayer_element_clicked(selector);
1098 1723 }
1099 1724
1725 +// Dump the data from the el to the elements
1726 +function pagelayer_element_dump_data(){
1727 + for(var x in pagelayer.el){
1728 + var jEle = pagelayer_ele_by_id(x);
1729 + if(jEle.length > 0){
1730 + pagelayer_el_dump_data(jEle);
1731 + }
1732 + }
1733 +}
1734 +
1100 1735 // Setup the properties on a single click
1101 1736 function pagelayer_element_setup(selector, render){
1102 1737
1103 1738 var selector = selector || ".pagelayer-ele";
@@ -1104,9 +1739,9 @@
1104 1739 render = render || false;
1105 1740
1106 1741 // Loop through
1107 1742 jQuery(pagelayer_editable+' '+selector).each(function(){
1108 -
1743 +
1109 1744 var jEle = jQuery(this);
1110 1745
1111 1746 // Assign an ID if not there
1112 1747 var id = pagelayer_assign_id(jEle);
@@ -1112,8 +1747,13 @@
1112 1747 var id = pagelayer_assign_id(jEle);
1113 1748 var pId = pagelayer_get_parent(jEle) || '';// Options to show on hover
1114 1749 var selector = '[pagelayer-id='+id+']';
1115 1750
1751 + // Get data part
1752 + pagelayer.el[id] = pagelayer_el_get_data(jEle);
1753 + //console.log(jEle[0].outerHTML);
1754 + //console.log(pagelayer.el[id]);
1755 +
1116 1756 if(render){
1117 1757 pagelayer_sc_render(jEle);
1118 1758 }
1119 1759
@@ -1118,8 +1758,9 @@
1118 1758 }
1119 1759
1120 1760 // Get the tag
1121 1761 var tag = pagelayer_tag(jEle);
1762 + var props = pagelayer_get_props(jEle);
1122 1763
1123 1764 // Lets check if we are the child of a parent i.e. element of a group
1124 1765 if(pagelayer_empty(pId)){
1125 1766
@@ -1146,9 +1787,14 @@
1146 1787
1147 1788 }
1148 1789
1149 1790 }
1150 -
1791 +
1792 + // If is group of widget?
1793 + if('widget_group' in props && !pagelayer_empty(props['widget_group'])){
1794 + pagelayer_set_widget_group(jEle);
1795 + }
1796 +
1151 1797 // Make the wraps
1152 1798 jEle.wrap('<div class="pagelayer-ele-wrap" pagelayer-wrap-id="'+id+'"></div>');
1153 1799 var wrap = jEle.parent();
1154 1800
@@ -1161,15 +1807,10 @@
1161 1807 col = 'pagelayer-col-'+x;
1162 1808 break;
1163 1809 }
1164 1810 }
1811 +
1165 1812
1166 - var is_custom_width = pagelayer_get_att(jEle, 'col');
1167 - var col_width = pagelayer_get_att(jEle, 'col_width');
1168 - if(pagelayer_empty(is_custom_width) && col_width){
1169 - wrap.css('width', col_width+'%');
1170 - }
1171 -
1172 1813 wrap.addClass('pagelayer-col '+col);
1173 1814 //jEle.removeClass('pagelayer-col '+col);
1174 1815 wrap.addClass('pagelayer-wrap-col');
1175 1816
@@ -1195,11 +1836,13 @@
1195 1836 pagelayer_sc_render(jEle);
1196 1837 }
1197 1838
1198 1839 html = '<div class="pagelayer-row-option" pagelayer-option-edit pagelayer-option-id="'+id+'">'+
1199 - '<i class="fa fa-clone pagelayer-eoi" onclick="pagelayer_copy_element(\''+selector+'\')" />'+
1200 - '<i class="fa fa-trash pagelayer-eoi" onclick="pagelayer_delete_element(\''+selector+'\')" />'+
1201 - '<i class="fa fa-pencil pagelayer-eoi" onclick="pagelayer_edit_element(\''+selector+'\', event)" />'+
1840 + '<i class="fas fa-caret-up pagelayer-eoi pagelayer-move-up" onclick="pagelayer_move_element_up(\''+selector+'\')" ></i>'+
1841 + '<i class="far fa-clone pagelayer-eoi" onclick="pagelayer_copy_element(\''+selector+'\')" ></i>'+
1842 + '<i class="fas fa-trash pagelayer-eoi" onclick="pagelayer_delete_element(\''+selector+'\')" ></i>'+
1843 + '<i class="fas fa-pencil-alt pagelayer-eoi" onclick="pagelayer_edit_element(\''+selector+'\', event)" ></i>'+
1844 + '<i class="fas fa-caret-down pagelayer-eoi pagelayer-move-down" onclick="pagelayer_move_element_down(\''+selector+'\')" ></i>'+
1202 1845 '</div>';
1203 1846
1204 1847 }else if(tag == 'pl_col'){
1205 1848
@@ -1205,9 +1848,9 @@
1205 1848
1206 1849 overlay.addClass('pagelayer-col-hover');
1207 1850
1208 1851 html = '<div class="pagelayer-col-option" pagelayer-option-edit pagelayer-option-id="'+id+'">'+
1209 - '<i class="fa fa-columns pagelayer-eoi" onclick="pagelayer_edit_element(\''+selector+'\', event)" />'+
1852 + '<i class="fas fa-columns pagelayer-eoi" onclick="pagelayer_edit_element(\''+selector+'\', event)" ></i>'+
1210 1853 '</div>';
1211 1854
1212 1855 // Is it an empty col ?
1213 1856 pagelayer_empty_col(jEle.children('.pagelayer-col-holder'));
@@ -1217,11 +1860,13 @@
1217 1860
1218 1861 }else{
1219 1862
1220 1863 html = '<div class="pagelayer-ele-option" pagelayer-option-edit pagelayer-option-id="'+id+'">'+
1221 - '<i class="fa fa-clone pagelayer-eoi" onclick="pagelayer_copy_element(\''+selector+'\')" />'+
1222 - '<i class="fa fa-trash pagelayer-eoi" onclick="pagelayer_delete_element(\''+selector+'\')" />'+
1223 - '<i class="fa fa-pencil pagelayer-eoi" onclick="pagelayer_edit_element(\''+selector+'\', event)" />'+
1864 + '<i class="fas fa-caret-up pagelayer-eoi pagelayer-move-up" onclick="pagelayer_move_element_up(\''+selector+'\')" ></i>'+
1865 + '<i class="far fa-clone pagelayer-eoi" onclick="pagelayer_copy_element(\''+selector+'\')" ></i>'+
1866 + '<i class="fas fa-trash pagelayer-eoi" onclick="pagelayer_delete_element(\''+selector+'\')" ></i>'+
1867 + '<i class="fas fa-pencil-alt pagelayer-eoi" onclick="pagelayer_edit_element(\''+selector+'\', event)" ></i>'+
1868 + '<i class="fas fa-caret-down pagelayer-eoi pagelayer-move-down" onclick="pagelayer_move_element_down(\''+selector+'\')" ></i>'+
1224 1869 '</div>';
1225 1870
1226 1871 }
1227 1872
@@ -1226,10 +1871,23 @@
1226 1871 }
1227 1872
1228 1873 // Append to the child
1229 1874 overlay.append(html);
1875 +
1876 + // Add shortcode icon
1877 + if(tag != 'pl_row' && tag != 'pl_col'){
1878 + overlay.append('<span class="pagelayer-shortcode-plus" onclick="event.stopPropagation();pagelayer_show_widget_list(this);"><i class="fas fa-plus"></i></span>');
1879 + }
1880 +
1230 1881 jQuery('[pagelayer-option-id='+id+']').hide();
1231 1882
1883 + // Hide active when not supported by tag
1884 + if(!pagelayer_empty(props['hide_active'])){
1885 + wrap.addClass('pagelayer-hide-active');
1886 + }
1887 +
1888 + pagelayer_trigger_action('pagelayer_element_setup', [jEle]);
1889 +
1232 1890 // Setup the HOVER events ABD create WRAPS IF we dont have a parent
1233 1891 if(pId.length > 0){
1234 1892 return;
1235 1893 }
@@ -1263,8 +1921,44 @@
1263 1921
1264 1922 });
1265 1923 }
1266 1924
1925 +// Unsetup element for restup
1926 +function pagelayer_element_unsetup(selector, id){
1927 +
1928 + id = id || false;
1929 +
1930 + var src = jQuery(selector);
1931 + var html = src[0].outerHTML;
1932 +
1933 + var jEle = jQuery(html);
1934 + pagelayer_remove_id_class(jEle);
1935 + jEle.removeAttr('pagelayer-id');
1936 + jEle.removeAttr('pagelayer-active');
1937 + jEle.find('[pagelayer-id]').each(function(){
1938 + pagelayer_remove_id_class(jQuery(this));
1939 + jQuery(this).removeAttr('pagelayer-id');
1940 + });
1941 + jEle.find('[pagelayer-parent]').removeAttr('pagelayer-parent');// Remove the parent attribute as it will be reset during pagelayer_element_setup
1942 + jEle.find('style').remove();
1943 + jEle.find('.pagelayer-ele-overlay').remove();
1944 +
1945 + // Unwrap the wraps
1946 + jEle.find('.pagelayer-ele').each(function (){
1947 + var ele = jQuery(this);
1948 + if(ele.parent().is('.pagelayer-ele-wrap')){
1949 + ele.unwrap();
1950 + }
1951 + });
1952 +
1953 + // Assign id
1954 + if(!pagelayer_empty(id)){
1955 + jEle.attr('pagelayer-id', id);
1956 + }
1957 +
1958 + return jEle;
1959 +}
1960 +
1267 1961 // Left Click
1268 1962 function pagelayer_left_click(){
1269 1963
1270 1964 jQuery(pagelayer_editable).on('click', function(e){
@@ -1294,12 +1988,15 @@
1294 1988
1295 1989 var html = '<div class="pagelayer-right-click-options" style="display:none;">'+
1296 1990 '<ul>'+
1297 1991 '<li><a class="pagelayer-right-edit">Edit</a></li>'+
1298 - '<li><a class="pagelayer-right-duplicate"><i class="fa fa-clone" /> Duplicate</a></li>'+
1299 - '<li><a class="pagelayer-right-copy"><i class="fa fa-files-o" /> Copy</a></li>'+
1300 - '<li><a class="pagelayer-right-paste"><i class="fa fa-clipboard" /> Paste</a></li>'+
1301 - '<li><a class="pagelayer-right-delete"><i class="fa fa-trash-o" /> Delete</a></li>'+
1992 + '<li><a class="pagelayer-right-duplicate"><i class="far fa-clone" ></i> '+pagelayer_l('Duplicate')+'</a></li>'+
1993 + '<li><a class="pagelayer-right-copy"><i class="far fa-copy" ></i> '+pagelayer_l('Copy')+' <span style="margin-left:10px;opacity:0.6">Ctrl+c</span></a></li>'+
1994 + '<li><a class="pagelayer-right-paste pagelayer-context-disable" title="If the paste is not done correctly then use Ctrl+V"><i class="far fa-clipboard" ></i> '+pagelayer_l('Paste')+' <span style="margin-left:10px;opacity:0.6">Ctrl+v</span></a></li>'+
1995 + '<li><a class="pagelayer-right-delete"><i class="far fa-trash-alt" ></i> '+pagelayer_l('Delete')+'</a></li>'+
1996 + '<li><a class="pagelayer-right-save-global-widget" pro="1"><i class="far fa-save" ></i> '+pagelayer_l('save_global')+'</a></li>'+
1997 + '<li><a class="pagelayer-right-save-section" pro="1"><i class="far fa-heart" ></i> '+pagelayer_l('save_as_section')+'</a></li>'+
1998 + '<li><a class="pagelayer-right-save-global-section" pro="1"><i class="fas fa-globe" ></i> '+pagelayer_l('save_as_global_section')+'</a></li>'+
1302 1999 '</ul>'+
1303 2000 '</div>';
1304 2001
1305 2002 jQuery('body').append(html);
@@ -1310,8 +2007,13 @@
1310 2007
1311 2008 var tEle = jQuery(e.target);
1312 2009 var jEle = tEle.closest('.pagelayer-ele-wrap').children('.pagelayer-ele');
1313 2010
2011 + // If copy_selected is empty then copy data from localStorage
2012 + if(pagelayer_empty(pagelayer.copy_selected)){
2013 + pagelayer_copy_from_clipboard();
2014 + }
2015 +
1314 2016 // Get the parent
1315 2017 var pId = pagelayer_get_parent(jEle);
1316 2018
1317 2019 // If we found a parent
@@ -1322,31 +2024,89 @@
1322 2024 // The basics
1323 2025 var id = pagelayer_assign_id(jEle);
1324 2026 var tag = pagelayer_tag(jEle);
1325 2027
1326 - $contextMenu.find('.pagelayer-right-edit').attr('onclick', 'pagelayer_edit_element("[pagelayer-id='+id+']")').html('<i class="fa fa-pencil-square-o" /> Edit '+pagelayer_shortcodes[tag]['name']);
2028 + $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']);
1327 2029 $contextMenu.find('.pagelayer-right-duplicate').attr('onclick', 'pagelayer_copy_element("[pagelayer-id='+id+']")');
1328 2030 $contextMenu.find('.pagelayer-right-copy').attr('onclick', 'pagelayer_copy_select("[pagelayer-id='+id+']")');
1329 - $contextMenu.find('.pagelayer-right-paste').attr('onclick', 'pagelayer_paste_element("[pagelayer-id='+id+']")');
1330 2031 $contextMenu.find('.pagelayer-right-delete').attr('onclick', 'pagelayer_delete_element("[pagelayer-id='+id+']")');
1331 2032
1332 - // If copy_selected is empty then copy data from localStorage
1333 - if(pagelayer_empty(pagelayer.copy_selected)){
1334 - pagelayer_copy_from_localStorage();
2033 + // If is pagelayer pro
2034 + if(!pagelayer_empty(pagelayer_pro)){
2035 + $contextMenu.find('.pagelayer-right-save-global-widget').attr('onclick', 'pagelayer_save_sections("[pagelayer-id='+id+']", "global_widget")');
2036 + $contextMenu.find('.pagelayer-right-save-section').attr('onclick', 'pagelayer_save_sections("[pagelayer-id='+id+']", "section")');
2037 + $contextMenu.find('.pagelayer-right-save-global-section').attr('onclick', 'pagelayer_save_sections("[pagelayer-id='+id+']", "global_section")');
2038 + }else{
2039 + var pro = $contextMenu.find('[pro="1"]');
2040 +
2041 + if(pro.find('.pagelayer-pro-req').length < 1){
2042 + pro.append('<span class="pagelayer-pro-req">Pro</span>');
2043 + }
2044 +
2045 + pro.css({'color': '#a7a7a7'});
2046 +
2047 + // To stopPropagation
2048 + pro.parent().on('click', function(e){
2049 + e.stopPropagation();
2050 + });
1335 2051 }
1336 2052
2053 + var showPaste = function(){
2054 + if(!pagelayer_empty(pagelayer.copy_selected) && pagelayer_can_copy_to(jEle)){
2055 + $contextMenu.find('.pagelayer-right-paste').removeClass('pagelayer-context-disable');
2056 + $contextMenu.find('.pagelayer-right-paste').attr('onclick', 'pagelayer_paste_element("[pagelayer-id='+id+']")');
2057 + }
2058 + }
2059 +
1337 2060 // Are we to hide the paste ?
1338 - if(!pagelayer_empty(pagelayer.copy_selected) && pagelayer_can_copy_to(jEle)){
1339 - //console.log(pagelayer_can_copy_to(jEle));
1340 - $contextMenu.find('.pagelayer-right-paste').parent().show();
2061 + if(pagelayerClipboardLoading){
2062 + var clipboardLoading = {};
2063 + clipboardLoading = setInterval(function(){
2064 +
2065 + if(pagelayerClipboardLoading){
2066 + return;
2067 + }
2068 +
2069 + clearInterval(clipboardLoading);
2070 + showPaste();
2071 +
2072 + }, 100);
1341 2073 }else{
1342 - $contextMenu.find('.pagelayer-right-paste').parent().hide();
2074 + showPaste();
1343 2075 }
1344 2076
2077 + var gId = pagelayer_get_global_id(jEle);
2078 +
2079 + // Are we to hide the global widget ?
2080 + if(!pagelayer_empty(gId) || tag == 'pl_row' || tag == 'pl_inner_row'|| tag == 'pl_col'){
2081 + $contextMenu.find('.pagelayer-right-save-global-widget').parent().hide();
2082 + }else{
2083 + $contextMenu.find('.pagelayer-right-save-global-widget').parent().show();
2084 + }
2085 +
2086 + var sId = pagelayer_get_att(jEle, 'global-section-id');
2087 +
2088 + // Are we to hide the save as global section ?
2089 + if( tag == 'pl_row' && pagelayer_empty(sId)){
2090 + $contextMenu.find('.pagelayer-right-save-global-section').parent().show();
2091 + }else{
2092 + $contextMenu.find('.pagelayer-right-save-global-section').parent().hide();
2093 + }
2094 +
2095 + // Are we to hide the save as section ?
2096 + if( tag == 'pl_row' ){
2097 + $contextMenu.find('.pagelayer-right-save-section').parent().show();
2098 + }else{
2099 + $contextMenu.find('.pagelayer-right-save-section').parent().hide();
2100 + }
2101 +
2102 + var hPosition = (e.pageX+$contextMenu.width()>jQuery(window).width()) ? (e.pageX-$contextMenu.width()) : e.pageX;
2103 + var vPosition = (e.pageY+$contextMenu.height()>jQuery(document).scrollTop()+jQuery(window).height()) ? (e.pageY-$contextMenu.height()) : e.pageY;
2104 +
1345 2105 $contextMenu.css({
1346 2106 display: "block",
1347 - left: e.pageX,
1348 - top: e.pageY
2107 + left: hPosition,
2108 + top: vPosition
1349 2109 });
1350 2110
1351 2111 return false;
1352 2112
@@ -1361,9 +2121,14 @@
1361 2121 function pagelayer_set_parent(jEle, id){
1362 2122 jEle.attr('pagelayer-parent', id);
1363 2123 };
1364 2124
1365 -// Set the parent for the group
2125 +// Set the widget group
2126 +function pagelayer_set_widget_group(jEle){
2127 + jEle.addClass('pagelayer-ele-widget-group');
2128 +};
2129 +
2130 +// Get the parent for the group
1366 2131 function pagelayer_get_parent(jEle){
1367 2132 return jEle.attr('pagelayer-parent');
1368 2133 };
1369 2134
@@ -1406,16 +2171,509 @@
1406 2171 }
1407 2172 }
1408 2173 }
1409 2174
2175 +var pagelayer_keydown_data = {};
2176 +pagelayer_add_action('pagelayer_do_dirty', function(){
2177 + pagelayer_keydown_data = {};
2178 +});
2179 +
2180 +var pagelayer_active_ele_timmer = {};
2181 +// Handle widget selecttion and move cursor in editable areas on key press events
2182 +jQuery(document).keydown(function(e){
2183 + //alert(String.fromCharCode(e.which));
2184 +
2185 + var tEle = jQuery(e.target);
2186 + var editable = tEle.closest('[contenteditable="true"]');
2187 + var tooltip = pagelayer.$$('.pagelayer-widget-tooltip');
2188 +
2189 + // If ArrowDown and ArrowUp key not pressed
2190 + if(!(e.key == 'ArrowDown' || e.key == 'ArrowUp') || tooltip.is(':visible')){
2191 + pagelayer_keydown_data = {};
2192 + return;
2193 + }
2194 +
2195 + var findEles = jQuery(pagelayer_editable+' .pagelayer-ele,'+pagelayer_editable+' [contenteditable="true"]');
2196 + var activeEle = findEles.first();
2197 +
2198 + if(editable.length > 0){
2199 + activeEle = editable;
2200 + }else if( '$' in pagelayer_keydown_data ){
2201 + activeEle = pagelayer_keydown_data.$;
2202 + }else if( pagelayer_active.el && 'id' in pagelayer_active.el ){
2203 + activeEle = pagelayer_active.el.$;
2204 + }
2205 +
2206 + if(pagelayer_empty(activeEle) || activeEle.length < 1){
2207 + return;
2208 + }
2209 +
2210 + // Make element active
2211 + var makeEleActive = function(index, next){
2212 +
2213 + next = next || false;
2214 + var cursorPos = 0, focusEle;
2215 +
2216 + // We are editable area
2217 + if(editable.length > 0){
2218 +
2219 + var lines = pagelayer_content_line(editable.get(0));
2220 + var cursorPos = pagelayer_getCaretCharacterOffsetWithin(editable.get(0));
2221 +
2222 + if((next && lines[lines.length - 1].start > cursorPos) || (!next && lines[0].end < cursorPos)){
2223 + return;
2224 + }
2225 +
2226 + e.preventDefault();
2227 +
2228 + var lastLineStart = lines[lines.length - 1]['start'];
2229 +
2230 + // We are on the last line
2231 + if(next && lastLineStart <= cursorPos){
2232 + cursorPos = cursorPos - lastLineStart;
2233 + }
2234 +
2235 + }
2236 +
2237 + // Search for next/previous element
2238 + var searchEle = function(indexEle){
2239 +
2240 + indexEle = next ? ++indexEle : --indexEle;
2241 + var sIndex = findEles.eq(indexEle);
2242 +
2243 + if(sIndex.length < 1){
2244 + return sIndex;
2245 + }
2246 +
2247 + var sEle = sIndex.closest('.pagelayer-ele');
2248 + var tag = pagelayer_tag(sEle);
2249 +
2250 + if(tag == 'pl_row' || tag == 'pl_inner_row' || tag == 'pl_col' || sEle.parent().hasClass('pagelayer-hide-active') || !pagelayer_empty(sIndex.attr('pagelayer-parent'))){
2251 + sIndex = searchEle(indexEle);
2252 + }
2253 +
2254 + return sIndex;
2255 + }
2256 +
2257 + var ele = searchEle(index);
2258 +
2259 + // If ArrowUp and we are come from editable area and previous element is not editable
2260 + if(ele.length > 0 && !next && ele.attr('contenteditable') != 'true'){
2261 + ele = searchEle(findEles.index( ele ));
2262 + }
2263 +
2264 + if(ele.length < 1){
2265 + return;
2266 + }
2267 +
2268 + // Save in global variable
2269 + pagelayer_keydown_data.$ = ele;
2270 + jQuery(':focus').blur();
2271 +
2272 + var jEle = ele.closest('.pagelayer-ele');
2273 + var tag = pagelayer_tag(jEle);
2274 +
2275 + if(ele.attr('contenteditable') == 'true'){
2276 + focusEle = ele;
2277 + }else if(tag != 'pl_row' && tag != 'pl_inner_row' && tag != 'pl_col'){
2278 +
2279 + var focusAble = ele.find('[contenteditable="true"]');
2280 + var isfocusAble = focusAble.closest('.pagelayer-ele').is(jEle);
2281 +
2282 + if(isfocusAble && next){
2283 + focusEle = focusAble.first();
2284 + }else if(isfocusAble){
2285 + focusEle = focusAble.last();
2286 + }
2287 + }
2288 +
2289 + if(!pagelayer_empty(focusEle) && focusEle.length > 0){
2290 + focusEle.focus();
2291 +
2292 + var focusLine = pagelayer_content_line(focusEle.get(0));
2293 + var fLine = next ? focusLine[0] : focusLine[focusLine.length -1];
2294 +
2295 + cursorPos = (fLine['start'] + cursorPos > fLine['end'] ? fLine['end'] : fLine['start'] + cursorPos);
2296 +
2297 + pagelayer_setCaret(focusEle.get(0), cursorPos);
2298 + }
2299 +
2300 + pagelayer_set_active(jEle);
2301 + ele[0].scrollIntoView({behavior: "smooth", block: "nearest"});
2302 +
2303 + clearTimeout(pagelayer_active_ele_timmer);
2304 + pagelayer_active_ele_timmer = setTimeout(function(){
2305 + pagelayer_keydown_data = {};
2306 + ele.closest('.pagelayer-ele').click();
2307 + }, 1000);
2308 + }
2309 +
2310 + // If cursor on first line & up arrow key
2311 + var currentIndex = findEles.index( activeEle );
2312 + pagelayer_keydown_data.$ = activeEle;
2313 +
2314 + // Move active element and cursor arround editor
2315 + if(e.key == 'ArrowDown'){
2316 + makeEleActive(currentIndex, true);
2317 + }
2318 +
2319 + if(e.key == 'ArrowUp'){
2320 + makeEleActive(currentIndex, false);
2321 + }
2322 +});
2323 +
1410 2324 // Handle key press events
1411 -jQuery(document).keydown(function(event){
2325 +pagelayer.gDocument.keydown(function(event){
1412 2326 //alert(String.fromCharCode(event.which));
1413 2327
1414 2328 var tEle = jQuery(event.target);
2329 + var editable = tEle.closest('[contenteditable="true"]');
2330 + var tooltip = pagelayer.$$('.pagelayer-widget-tooltip');
2331 +
2332 + // Enter handle
2333 + if(event.keyCode == 13){
2334 +
2335 + var jEle = tEle.closest('.pagelayer-ele');
2336 + var tag = pagelayer_tag(jEle);
2337 +
2338 + // Add selected widget from widget list
2339 + if(tooltip.is(':visible')){
2340 + tooltip.find('.pagelayer-list-widget-active:visible').click();
2341 + return;
2342 + }
2343 +
2344 + if( pagelayer_empty(pagelayer_active.el) || !('id' in pagelayer_active.el) ){
2345 + return;
2346 + }
2347 +
2348 + var active_el_par = pagelayer_active.el.$.parent();
2349 +
2350 + // Create and add text widget
2351 + var addTitle = function(insertAfter){
2352 + var ele = jQuery('<div pagelayer-tag="pl_text"></div>');
2353 + insertAfter.after(ele);
2354 + return pagelayer_ele_by_id( pagelayer_onadd(ele) );
2355 + }
2356 +
2357 + // If we have an active element then add text widget
2358 + if(!(tEle.is('input, textarea') || editable.length > 0)){
2359 +
2360 + event.preventDefault();
2361 +
2362 + var activeTag = pagelayer_active.el.tag;
2363 +
2364 + // If is row or column ?
2365 + if(activeTag == 'pl_row' || activeTag == 'pl_col'){
2366 + return;
2367 + }
2368 +
2369 + var hEle = addTitle(active_el_par);
2370 + hEle.click();
2371 + hEle.find('[pagelayer-editable]').focus();
2372 +
2373 + // Ensure the column is not empty
2374 + pagelayer_empty_col(hEle.closest('.pagelayer-col-holder'));
2375 + return;
2376 + }
1415 2377
2378 + if( (tag != 'pl_text' && tag != 'pl_heading') || editable.length < 1 || event.shiftKey){
2379 + return;
2380 + }
2381 +
2382 + var selection = window.getSelection();
2383 + var range = selection.getRangeAt(0);
2384 +
2385 + // We are within the list tag
2386 + if(jQuery(range.startContainer).closest('[pagelayer-editable] li').length > 0){
2387 + return;
2388 + }
2389 +
2390 + event.preventDefault();
2391 +
2392 + var lastChild = editable[0].lastChild;
2393 + var startContainer = range.startContainer;
2394 +
2395 + if(startContainer.nodeType == Node.TEXT_NODE && startContainer.parentNode != editable[0]){
2396 + startContainer = startContainer.parentNode;
2397 + }
2398 +
2399 + range.setEndAfter(lastChild);
2400 +
2401 + var val = range.cloneContents();
2402 + var selfEle = jQuery('<div>').append(val);
2403 + var selContent = selfEle.html();
2404 + var selfFC = selfEle[0].firstChild;
2405 + var emptyContent = false;
2406 +
2407 + if(selfFC == null || pagelayer_empty(selContent)){
2408 + selContent = '<p><br></p>';
2409 + emptyContent = true;
2410 + }else if(selfFC.nodeType == Node.TEXT_NODE){
2411 + selContent = '<p>'+selContent+'</p>';
2412 + }else if(selfEle.text() == '' && selfEle.find('br').length < 1){
2413 + selContent = '<p><br></p>';
2414 + emptyContent = true;
2415 + }else if(selfEle.text().trim() == ''){
2416 + selContent = selContent.replace(/\s+/, "\u00A0");
2417 + emptyContent = true;
2418 + }
2419 +
2420 + range.deleteContents();
2421 +
2422 + if( jQuery(startContainer).is(':first-child') && jQuery(startContainer).is(':empty') ){
2423 + jQuery(startContainer).html('<br>');
2424 + }else if( jQuery(startContainer).is(':empty') ){
2425 + jQuery(startContainer).remove();
2426 + }
2427 +
2428 + // If editor is empty
2429 + if( editable.is(':empty') ){
2430 + editable.html('<p><br></p>');
2431 + }
2432 +
2433 + editable.trigger('input');
2434 + editable.blur();
2435 +
2436 + // Create and add text widget
2437 + var ele;
2438 + if(emptyContent){
2439 + ele = addTitle(jEle.parent());
2440 + }else{
2441 + var id = pagelayer_copy_element(jEle);
2442 + ele = pagelayer_ele_by_id(id);
2443 + }
2444 +
2445 + ele.click();
2446 + var editorArea = ele.find('[pagelayer-editable]');
2447 + editorArea.html(selContent);
2448 + editorArea.find('p:empty').remove();
2449 + editorArea.focus().trigger('input');
2450 + }
2451 +
2452 + // ctrl+s handle
2453 + if(event.keyCode == 83 && event.ctrlKey){
2454 + event.preventDefault();
2455 + pagelayer.$$('.pagelayer-iframe-top-bar').find('.pagelayer-update-button').click();
2456 + }
2457 +
2458 + // ctrl+d handle
2459 + if(event.keyCode == 68 && event.ctrlKey){
2460 +
2461 + // If we have an active element
2462 + if( pagelayer_active.el && pagelayer_active.el.id ){
2463 + event.preventDefault();
2464 + pagelayer_copy_element('[pagelayer-id='+pagelayer_active.el.id+']');
2465 + }
2466 +
2467 + }
2468 +
2469 + // Delete handler for text widget
2470 + if(event.keyCode == 46 && editable.length > 0){
2471 + var jEle = tEle.closest('.pagelayer-ele-wrap');
2472 + var tag = pagelayer_tag(jEle);
2473 + var next = jEle.next();
2474 + var pTag = pagelayer_tag(next);
2475 +
2476 + var selection = window.getSelection();
2477 + var orgRange = selection.getRangeAt(0);
2478 + var cloneRange = orgRange.cloneRange();
2479 +
2480 + if((tag != 'pl_text' && tag != 'pl_heading') || next.length < 1 || pTag != tag || !cloneRange.collapsed ){
2481 + return;
2482 + }
2483 +
2484 + var currentOffset = pagelayer_getCaretCharacterOffsetWithin(editable[0]);
2485 + cloneRange.selectNodeContents(editable[0]);
2486 + var caretOffset = cloneRange.toString().length;
2487 +
2488 + if(currentOffset != caretOffset){
2489 + return;
2490 + }
2491 +
2492 + var nextHtml = next.find('[pagelayer-editable="text"]').html();
2493 + editable.append(nextHtml);
2494 + pagelayer_delete_element(next.children('.pagelayer-ele'));
2495 + }
2496 +
2497 + // Backspace handler
2498 + if(event.keyCode == 8 && editable.length > 0){
2499 + var jEle = tEle.closest('.pagelayer-ele-wrap');
2500 + var tag = pagelayer_tag(jEle);
2501 + var prev = jEle.prev();
2502 +
2503 + if((tag != 'pl_text' && tag != 'pl_heading') || prev.length < 1){
2504 + return;
2505 + }
2506 +
2507 + var pTag = pagelayer_tag(prev);
2508 + var selection = window.getSelection();
2509 +
2510 + if (selection == null || selection.rangeCount <= 0) return null;
2511 +
2512 + var range1 = selection.getRangeAt(0);
2513 +
2514 + if(pTag != tag || range1.startOffset != 0){
2515 + return;
2516 + }
2517 +
2518 + var prevArea = prev.find('[pagelayer-editable="text"]');
2519 +
2520 + if( pagelayer_getCaretCharacterOffsetWithin(editable[0]) != 0 || prevArea.length < 1){
2521 + return;
2522 + }
2523 +
2524 + //event.preventDefault();
2525 + var html = editable.html();
2526 + editable.blur();
2527 + prev.children('.pagelayer-ele').click();
2528 + prevArea.click();
2529 +
2530 + var newSel = window.getSelection();
2531 + var newRange = newSel.getRangeAt(0);
2532 + var lastChild = jQuery(prevArea[0].lastChild);
2533 +
2534 + prevArea.append(html);
2535 + prevArea.trigger('input');
2536 +
2537 + if(lastChild.length > 0){
2538 + if(lastChild[0].nextSibling != null){
2539 + newRange.setStart(lastChild[0].nextSibling, 0);
2540 + }else{
2541 + newRange.setStartAfter(lastChild[0]);
2542 + }
2543 + }
2544 +
2545 + newRange.collapse(true);
2546 + newSel.removeAllRanges();
2547 + newSel.addRange(newRange);
2548 +
2549 + pagelayer_delete_element(jEle.children('.pagelayer-ele'));
2550 +
2551 + }
2552 +
2553 + if(tooltip.is(':visible')){
2554 +
2555 + // Select previous widget in widget tooltip
2556 + if(event.key == 'ArrowUp' || event.key == 'ArrowLeft' || (event.key == 'Tab' && event.shiftKey)){
2557 +
2558 + event.preventDefault();
2559 +
2560 + var current = tooltip.find('.pagelayer-list-widget-active:visible'),
2561 + prev = current.prevAll('.pagelayer-shortcode-holder:visible');
2562 +
2563 + if(event.key == 'ArrowUp'){
2564 + var _prev = prev,
2565 + cOffset = current.offset();
2566 + findNext = false;
2567 +
2568 + var searchNext = function(nEle){
2569 +
2570 + var nOffset = nEle.offset();
2571 + var nBottom = nOffset.top + nEle.height();
2572 +
2573 + if(nBottom > cOffset.top){
2574 + return true;
2575 + }
2576 +
2577 + prev = nEle;
2578 + findNext = true;
2579 +
2580 + // Current element left set +20 to manager previous scale (css) element on hover
2581 + if(cOffset.left + 20 >= nOffset.left){
2582 + return false;
2583 + }
2584 +
2585 + return true;
2586 + }
2587 +
2588 + _prev.each(function(){
2589 + return searchNext(jQuery(this));
2590 + });
2591 +
2592 + if(!findNext){
2593 + var gNext = current.parent().prevAll('.pagelayer-widget-group:visible').first();
2594 + _prev = gNext.children('.pagelayer-shortcode-holder:visible');
2595 +
2596 + jQuery(_prev.get().reverse()).each(function(){
2597 + return searchNext(jQuery(this));
2598 + });
2599 + }
2600 +
2601 + }
2602 +
2603 + if(prev.length < 1){
2604 + prev = current.parent().prevAll('.pagelayer-widget-group:visible').first().find('.pagelayer-shortcode-holder:visible').last();
2605 + }
2606 +
2607 + if(prev.length < 1){
2608 + return;
2609 + }
2610 +
2611 + prev.first().trigger('widget_active');
2612 + }
2613 +
2614 + // Select next widget in widget tooltip
2615 + if(event.key == 'ArrowDown' || event.key == 'ArrowRight' || (event.key == 'Tab' && !event.shiftKey)){
2616 +
2617 + event.preventDefault();
2618 +
2619 + var current = tooltip.find('.pagelayer-list-widget-active:visible');
2620 + next = current.nextAll('.pagelayer-shortcode-holder:visible');
2621 +
2622 + if(event.key == 'ArrowDown'){
2623 +
2624 + var _next = next,
2625 + cOffset = current.offset(),
2626 + findNext = false;
2627 +
2628 + var searchNext = function(nEle){
2629 + var nOffset = nEle.offset();
2630 + var cBottom = cOffset.top + current.height();
2631 +
2632 + if(cBottom > nOffset.top){
2633 + return true;
2634 + }
2635 +
2636 + next = nEle;
2637 + findNext = true;
2638 +
2639 + // Current element left set -20 to manager next scale (css) element on hover
2640 + if(cOffset.left - 20 <= nOffset.left){
2641 + return false;
2642 + }
2643 +
2644 + return true;
2645 + }
2646 +
2647 + _next.each(function(){
2648 + return searchNext(jQuery(this));
2649 + });
2650 +
2651 + if(!findNext){
2652 + var gNext = current.parent().nextAll('.pagelayer-widget-group:visible').first();
2653 + _next = gNext.children('.pagelayer-shortcode-holder:visible');
2654 + _next.each(function(){
2655 + return searchNext(jQuery(this));
2656 + });
2657 + }
2658 +
2659 + }
2660 +
2661 + if(next.length < 1){
2662 + next = current.parent().nextAll('.pagelayer-widget-group:visible').first().find('.pagelayer-shortcode-holder:visible');
2663 + }
2664 +
2665 + if(next.length < 1){
2666 + return;
2667 + }
2668 +
2669 + next.first().trigger('widget_active');
2670 +
2671 + }
2672 + }
2673 +
1416 2674 // Is this in the editable area ?
1417 - if (tEle.is('input, textarea') || tEle.closest('[contenteditable]').length > 0) {
2675 + if (tEle.is('input, textarea') || editable.length > 0) {
1418 2676 return;
1419 2677 }
1420 2678
1421 2679 // Delete
@@ -1432,43 +2690,66 @@
1432 2690 if(event.keyCode == 89 && event.ctrlKey){
1433 2691 pagelayer_do_history('redo');
1434 2692 }
1435 2693
1436 - // ctrl+d handle
1437 - if(event.keyCode == 68 && event.ctrlKey){
1438 -
1439 - // If we have an active element
1440 - if( pagelayer_active.el && pagelayer_active.el.id ){
1441 - event.preventDefault();
1442 - pagelayer_copy_element('[pagelayer-id='+pagelayer_active.el.id+']');
1443 - }
1444 -
1445 - }
1446 2694 });
1447 2695
1448 2696 // Handle Copy of content
1449 2697 jQuery(document).on('copy', function(copyEvent){
2698 +
2699 + // Is Selected string?
2700 + var selectedText = "";
2701 + if (window.getSelection){ // all modern browsers and IE9+
2702 + selectedText = window.getSelection().toString();
2703 + }
1450 2704
1451 - // Check the active element
2705 + if(selectedText.length > 0){
2706 + return;
2707 + }
2708 +
1452 2709 if(pagelayer_active.el && pagelayer_active.el.id){
1453 -
2710 + copyEvent.preventDefault();
2711 +
1454 2712 // Save the active element id
1455 - pagelayer_copy_select("[pagelayer-id='"+pagelayer_active.el.id+"']");
2713 + pagelayer_copy_select("[pagelayer-id='"+pagelayer_active.el.id+"']", copyEvent);
1456 2714
1457 2715 }
1458 2716
1459 2717 });
1460 2718
2719 +// This is for preload clipboard data
2720 +// Content can be copied from outside
2721 +var pagelayerIsParentBlured = true;
2722 +jQuery(window).on('focus', function(e){
2723 + if(pagelayerIsParentBlured){
2724 + pagelayer_copy_from_clipboard();
2725 + }
2726 + pagelayerIsParentBlured = true;
2727 +});
2728 +
2729 +jQuery(window.parent).on('focus', function(){
2730 + pagelayerIsParentBlured = false;
2731 +});
2732 +
1461 2733 // Handle Paste in the editor
1462 2734 jQuery(document).on('paste', function(pasteEvent){
1463 -
2735 +
1464 2736 var pEle_target = jQuery((pasteEvent.originalEvent || pasteEvent).target);
2737 + var tag = pagelayer_tag(pEle_target.closest('[pagelayer-id]'));
2738 + var clipboardData = (pasteEvent.originalEvent || pasteEvent).clipboardData;
2739 + var items = clipboardData.items;
2740 +
1465 2741 var pagelayer_ajax_func = {};
1466 2742 var contenteditable = false;
2743 + var pasteWidget = false;
2744 +
2745 + if( pEle_target.closest('[contenteditable="true"]').length > 0 || pEle_target.is('input, textarea') ){
2746 + pEle_target = pEle_target.closest('[contenteditable="true"], input, textarea');
2747 + contenteditable = true;
2748 + }
1467 2749
1468 - if(pEle_target.closest('[contenteditable]').length > 0 || pEle_target.is('input, textarea')){
1469 - pEle_target = pEle_target.closest('[contenteditable]');
1470 - contenteditable = true;
2750 + if( items.length < 1 || (items.length == 1 && pagelayer_empty(clipboardData.getData(items[0].type))) ){
2751 + pasteWidget = true;
1471 2752 }
1472 2753
1473 2754 // This function for ajax before send call back
1474 2755 pagelayer_ajax_func['beforeSend'] = function(xhr){
@@ -1477,8 +2758,9 @@
1477 2758 if( pagelayer_empty(contenteditable) ){
1478 2759
1479 2760 // If we dont have an active element then return false and stop ajax
1480 2761 if( !(pagelayer_active.el && pagelayer_active.el.id) ){
2762 + pagelayer_show_msg(pagelayer_l('active_ele_paste_msg'));
1481 2763 return false;
1482 2764 }
1483 2765
1484 2766 pagelayer.copy_selected = jQuery('<div pagelayer-tag="pl_image"></div>');
@@ -1504,31 +2786,77 @@
1504 2786 document.execCommand('insertImage', false, obj['data']['url']);
1505 2787
1506 2788 // For our widgets
1507 2789 }else{
2790 +
2791 + if(pagelayer_empty(pagelayer_active.el) || pagelayer_empty(pagelayer_active.el.id)){
2792 + pagelayer_show_msg('active_ele_paste_msg');
2793 + return;
2794 + }
2795 +
1508 2796 var fTo = pagelayer_can_copy_to('[pagelayer-id="'+pagelayer_active.el.id+'"]');
1509 2797 // We need to empty pagelayer.copy_selected
1510 2798 pagelayer.copy_selected = '';
1511 2799
1512 - // Prevent to add action history
1513 - pagelayer.history_action = false;
1514 -
1515 - // Create image html
1516 - var html = jQuery( pagelayer_create_sc('pl_image') );
1517 - html.attr('pagelayer-a-id', obj['data']['id']);
1518 - html.attr('pagelayer-tmp-id-url', obj['data']['url']);
2800 + var pasteAfter = function(){
2801 +
2802 + // Prevent to add action history
2803 + pagelayer.history_action = false;
2804 +
2805 + // Create image html
2806 + var html = pagelayer_create_sc('pl_image');
2807 +
2808 + pagelayer_set_atts(html, 'id', obj['data']['id']);
2809 + pagelayer_set_tmp_atts(html, 'id-url', obj['data']['url']);
2810 +
2811 + // Allow to add action history
2812 + pagelayer.history_action = true;
2813 +
2814 + // Copy the element
2815 + var id = pagelayer_copy_element(html, fTo);
2816 + jQuery('[pagelayer-id="'+id+'"]').click();
2817 +
2818 + };
1519 2819
1520 - // Allow to add action history
1521 - pagelayer.history_action = true;
1522 -
1523 - // Copy the element
1524 - var id = pagelayer_copy_element(html, fTo);
1525 - jQuery('[pagelayer-id="'+id+'"]').click();
2820 + var replaceURL = function(){
2821 +
2822 + // Finding widget image setting using id of jEle. Finding image editor setting from all of the other settings.
2823 + var row = pagelayer.$$('[pagelayer-element-id='+pagelayer_active.el.id+']').find('.pagelayer-elp-image').eq(0).parent().parent();
2824 +
2825 + row.find('.pagelayer-elp-image').css('background-image', 'url(\''+obj['data']['url']+'\')');
2826 +
2827 + // To remove past temp attr so that they are not involve in future temp values
2828 + var cname = row.attr('pagelayer-elp-name');
2829 + var old = _pagelayer_img_tmp_atts(row);
2830 + delete old[cname+'-url'];
2831 +
2832 + for(var x in obj['data']['sizes']){
2833 + _pagelayer_set_tmp_atts(row, x+'-url', obj['data']['sizes'][x]['url']);
2834 + delete old[cname+'-'+x+'-url'];
2835 + }
2836 +
2837 + for(var x in old){
2838 + _pagelayer_set_tmp_atts(row, x+'-url', '');
2839 + }
2840 +
2841 + // Save and render
2842 + _pagelayer_set_tmp_atts(row, 'url', obj['data']['url']);
2843 + _pagelayer_set_atts(row, obj['data']['id']);
2844 + };
2845 +
2846 + // Image paste confirmation.
2847 + if(!pagelayer_empty(pagelayer_active.el.tag) && pagelayer_active.el.tag == 'pl_image'){
2848 +
2849 + pagelayer_confirmation_box(pagelayer_l('img_paste_conf'), replaceURL, pasteAfter, pagelayer_l('replace_img'), pagelayer_l('paste_after'));
2850 +
2851 + }else{
2852 + pasteAfter();
2853 + }
1526 2854 }
1527 2855
1528 2856 // Some error occured
1529 2857 }else{
1530 - alert(obj['data']['message']);
2858 + pagelayer_show_msg(obj['data']['message'], 'error', 10000);
1531 2859 }
1532 2860 }
1533 2861
1534 2862 // This function for ajax complete call back
@@ -1538,20 +2866,36 @@
1538 2866 }
1539 2867
1540 2868 var findImg = pagelayer_editable_paste_handler(pasteEvent, pagelayer_ajax_func);
1541 2869
1542 - if(pagelayer_empty(findImg) && pagelayer_empty(contenteditable)){
2870 + if(pagelayer_empty(findImg) || pasteWidget){
1543 2871
1544 2872 // Check the active element
1545 - if(pagelayer_active.el && pagelayer_active.el.id){
2873 + if(pagelayer_active.el && pagelayer_active.el.id && pagelayer_active.el.tag != 'pl_post_props'){
1546 2874
1547 - var jEle = jQuery("[pagelayer-id='"+pagelayer_active.el.id+"']");
1548 -
1549 - // Check if the any element is copied
1550 - if(pagelayer_can_copy_to(jEle)){
1551 - pagelayer_paste_element("[pagelayer-id='"+pagelayer_active.el.id+"']");
2875 + const text = clipboardData.getData('text');
2876 + var pEle = jQuery(text);
2877 + var getData = true;
2878 +
2879 + if(pEle.length > 0 && !pagelayer_empty(pagelayer_tag(pEle)) ){
2880 +
2881 + // Cache pEle to make contextmenu paste faster
2882 + pagelayer.copy_selected = pEle;
2883 + getData = false;
2884 +
2885 + // Is it to be pastable
2886 + if(pagelayer_can_copy_to('[pagelayer-id="'+pagelayer_active.el.id+'"]')){
2887 + pasteEvent.preventDefault();
2888 + var jEle = jQuery("[pagelayer-id='"+pagelayer_active.el.id+"']");
2889 +
2890 + // Check if the any element is copied
2891 + pagelayer_paste_element(jEle, false);
2892 + }
2893 +
1552 2894 }
1553 2895
2896 + }else{
2897 + pagelayer_show_msg(pagelayer_l('no_active_ele_paste'));
1554 2898 }
1555 2899 }
1556 2900 });
1557 2901
@@ -1557,8 +2901,9 @@
1557 2901
1558 2902 // Delete an element as per the selector
1559 2903 function pagelayer_delete_element(selector){
1560 2904 var jEle = jQuery(selector);
2905 + var nearBy = jEle;
1561 2906
1562 2907 // Anything found ?
1563 2908 if(jEle.length > 0){
1564 2909
@@ -1573,8 +2918,10 @@
1573 2918 // Save this element in history action
1574 2919 if(pagelayer.history_action){
1575 2920 var cEle = pagelayer_near_by_ele(id, sc);
1576 2921
2922 + nearBy = jQuery(cEle.cEle);
2923 +
1577 2924 // To save in history, we need to save only element not the wraps as we call setup if we redo or undo
1578 2925 jEle.find('style').remove();
1579 2926 jEle.find('.pagelayer-ele-overlay').remove();
1580 2927
@@ -1589,9 +2936,9 @@
1589 2936 pagelayer_history_action_push({
1590 2937 'title' : pagelayer_shortcodes[sc]['name'],
1591 2938 'action' : 'Deleted',
1592 2939 'pl_id' : id,
1593 - 'html' : jEle,
2940 + 'html' : jEle[0].outerHTML,
1594 2941 'cEle' : cEle
1595 2942 });
1596 2943 }
1597 2944
@@ -1598,28 +2945,93 @@
1598 2945 wrap.remove();
1599 2946
1600 2947 pagelayer_empty_col(par);
1601 2948
1602 - if( pagelayer_active.el && pagelayer_active.el.id == id || jQuery('[pagelayer-id="'+pagelayer_active.el.id +'"]').length < 1 ){
2949 + if( (pagelayer_active.el && pagelayer_active.el.id == id) ||
2950 + (pagelayer_active.el && pagelayer_active.el.id && jQuery('[pagelayer-id="'+pagelayer_active.el.id+'"]').length < 1)){
1603 2951 pagelayer.$$('.pagelayer-elpd-close').click();
1604 2952 }
1605 2953
1606 2954 }
1607 2955
1608 - pagelayer_isDirty = true;
2956 + // Do Pagelayer dirty
2957 + pagelayer_do_dirty(nearBy);
1609 2958 };
1610 2959
1611 2960 // Select an element
1612 -function pagelayer_copy_select(selector){
2961 +function pagelayer_copy_select(selector, copyEvent = false){
1613 2962
1614 - var eHtml = jQuery(selector)[0].outerHTML;
2963 + var sEle = jQuery(selector);
1615 2964
1616 - // Copy data on localStorage
1617 - localStorage.setItem("pagelayer_ele", eHtml);
2965 + if(sEle.length < 1){
2966 + pagelayer_show_msg( pagelayer_l('invalid_copy_ele_msg'));
2967 + return;
2968 + }
1618 2969
1619 - pagelayer.copy_selected = selector;
2970 + var tag = pagelayer_tag(sEle);
2971 +
2972 + if(
2973 + pagelayer_empty(tag) ||
2974 + pagelayer_empty(pagelayer_shortcodes[tag]) ||
2975 + !pagelayer_empty(pagelayer_shortcodes[tag]['not_visible'])
2976 + ){
2977 + pagelayer_show_msg( pagelayer_l('invalid_copy_ele_msg'));
2978 + return;
2979 + }
2980 +
2981 + var eHtml = sEle[0].outerHTML;
2982 +
2983 + pagelayer.copy_selected = eHtml;
2984 +
2985 + // To hide Cliboard warning while pasting
2986 + pagelayerClipboardReadable = true;
2987 +
2988 + if(copyEvent){
2989 + // set clipbord data
2990 + (copyEvent.originalEvent || copyEvent).clipboardData.setData('text/plain', eHtml);
2991 + pagelayer_show_msg(pagelayer_l('copied_msg'));
2992 +
2993 + return;
2994 + }
2995 +
2996 + // Copy element to clipboard
2997 + pagelayer_copy_ele_to_clipboard(eHtml);
2998 +
1620 2999 }
1621 3000
3001 +// Select an element
3002 +function pagelayer_copy_ele_to_clipboard(eHtml){
3003 +
3004 + var fallbackCopy = function(text){
3005 + const textarea = document.createElement("textarea");
3006 + textarea.value = text;
3007 + textarea.style.position = "fixed"; // avoid scrolling
3008 + textarea.style.opacity = 0;
3009 + document.body.appendChild(textarea);
3010 + textarea.focus();
3011 + textarea.select();
3012 + try {
3013 + document.execCommand('copy');
3014 + pagelayer_show_msg( pagelayer_l('copied_msg'));
3015 + }catch(err){
3016 + //console.error("Copy failed", err);
3017 + pagelayer_show_msg( pagelayer_l('Copy failed'));
3018 + }
3019 + document.body.removeChild(textarea);
3020 + }
3021 +
3022 + // Modern clipboard API
3023 + if(navigator.clipboard && window.isSecureContext) {
3024 + navigator.clipboard.writeText(eHtml).then(() => {
3025 + pagelayer_show_msg( pagelayer_l('copied_msg'));
3026 + }).catch(() => {
3027 + fallbackCopy(eHtml);
3028 + });
3029 + }else{
3030 + fallbackCopy(eHtml);
3031 + }
3032 +}
3033 +
1622 3034 function pagelayer_can_copy_to(to){
1623 3035 var jEle = jQuery(pagelayer.copy_selected);
1624 3036 var tEle = jQuery(to);
1625 3037
@@ -1625,8 +3037,14 @@
1625 3037
1626 3038 var eTag = pagelayer_tag(jEle);
1627 3039 var tTag = pagelayer_tag(tEle);
1628 3040 //console.log(eTag+' - '+tTag);
3041 +
3042 + // Invalid HTML copied
3043 + if(pagelayer_empty(eTag)){
3044 + return false;
3045 + }
3046 +
1629 3047 // Final to
1630 3048 var fTo;
1631 3049
1632 3050 // Selected element is a Row, can go only after a row
@@ -1652,12 +3070,25 @@
1652 3070
1653 3071 }
1654 3072
1655 3073 // Select an element
1656 -function pagelayer_paste_element(to){
3074 +function pagelayer_paste_element(to, syncClipboard = true){
1657 3075
1658 - // Copy data from localStorage
1659 - pagelayer_copy_from_localStorage();
3076 + // Wait for clipboard sync
3077 + // This is for context paste
3078 + if(syncClipboard){
3079 + if(pagelayerClipboardLoading){
3080 + setTimeout(function(){
3081 + pagelayer_paste_element(to);
3082 + }, 200);
3083 + return false;
3084 + }
3085 +
3086 + // There may be some problems reading the clipboard
3087 + if(pagelayerClipboardReadable !== true){
3088 + pagelayer_show_msg('If the paste is not done correctly then use Ctrl+V', 'warning');
3089 + }
3090 + }
1660 3091
1661 3092 var fTo = pagelayer_can_copy_to(to);
1662 3093
1663 3094 // Is it a valid to
@@ -1666,20 +3097,49 @@
1666 3097 }
1667 3098
1668 3099 if(!pagelayer_empty(pagelayer.copy_selected)){
1669 3100 pagelayer_copy_element(pagelayer.copy_selected, fTo);
3101 + return true;
1670 3102 }
1671 3103
3104 + pagelayer_show_msg(pagelayer_l('no_copied'));
3105 +
1672 3106 return false;
1673 -
1674 3107 }
1675 3108
3109 +var pagelayerClipboardLoading = false;
3110 +var pagelayerClipboardReadable = true;
1676 3111 // If copy_selected is empty then copy data from localStorage
1677 -function pagelayer_copy_from_localStorage(){
1678 - if(!pagelayer_empty(localStorage.getItem("pagelayer_ele"))){
1679 - // Set copy data from localStorage
1680 - pagelayer.copy_selected = localStorage.getItem("pagelayer_ele");
3112 +async function pagelayer_copy_from_clipboard(){
3113 +
3114 + if(pagelayerClipboardLoading){
3115 + return;
1681 3116 }
3117 +
3118 + if (navigator.clipboard && window.isSecureContext) {
3119 + try {
3120 +
3121 + pagelayerClipboardLoading = true;
3122 +
3123 + const text = await navigator.clipboard.readText();
3124 + var pEle = jQuery(text);
3125 +
3126 + if(pEle.length > 0 && !pagelayer_empty(pagelayer_tag(pEle)) ){
3127 + pagelayer.copy_selected = pEle;
3128 + }
3129 +
3130 + pagelayerClipboardLoading = false;
3131 + pagelayerClipboardReadable = true;
3132 +
3133 + } catch (err) {
3134 + pagelayerClipboardLoading = false;
3135 + pagelayerClipboardReadable = 'Clipboard readText failed';
3136 + //console.warn("Clipboard readText failed", err);
3137 + }
3138 + } else {
3139 + pagelayerClipboardReadable = 'Clipboard API not available or insecure context.';
3140 + // console.warn("Clipboard API not available or insecure context.");
3141 + }
1682 3142 }
1683 3143
1684 3144 // Copy an element
1685 3145 // Note : insertAfter should always be an pagelayer-ele
@@ -1684,28 +3144,14 @@
1684 3144 // Copy an element
1685 3145 // Note : insertAfter should always be an pagelayer-ele
1686 3146 function pagelayer_copy_element(selector, insertAfter){
1687 3147 var src = jQuery(selector);
1688 - var html = src[0].outerHTML;
1689 3148 var tag = pagelayer_tag(src);
1690 3149 insertAfter = insertAfter || src;
1691 3150 insertAfter = insertAfter.parent();
1692 3151
1693 - var jEle = jQuery(html);
1694 - jEle.removeAttr('pagelayer-id');
1695 - jEle.find('[pagelayer-id]').removeAttr('pagelayer-id');
1696 - jEle.find('[pagelayer-parent]').removeAttr('pagelayer-parent');// Remove the parent attribute as it will be reset during pagelayer_element_setup
1697 - jEle.find('style').remove();
1698 - jEle.find('.pagelayer-ele-overlay').remove();
3152 + var jEle = pagelayer_element_unsetup(src);
1699 3153
1700 - // Unwrap the wraps
1701 - jEle.find('.pagelayer-ele').each(function (){
1702 - var ele = jQuery(this);
1703 - if(ele.parent().is('.pagelayer-ele-wrap')){
1704 - ele.unwrap();
1705 - }
1706 - });
1707 -
1708 3154 // Give it an ID
1709 3155 var id = pagelayer_assign_id(jEle);
1710 3156
1711 3157 jQuery(insertAfter).after(jEle);
@@ -1711,8 +3157,12 @@
1711 3157 jQuery(insertAfter).after(jEle);
1712 3158
1713 3159 pagelayer_element_setup('[pagelayer-id='+id+'], [pagelayer-id='+id+'] .pagelayer-ele', true);
1714 3160
3161 + if(pagelayer_is_group(tag)){
3162 + pagelayer_sc_render(jEle);
3163 + }
3164 +
1715 3165 // Save this element in history action
1716 3166 if(pagelayer.history_action){
1717 3167 var cEle = pagelayer_near_by_ele(id, tag);
1718 3168 pagelayer_history_action_push({
@@ -1718,9 +3168,9 @@
1718 3168 pagelayer_history_action_push({
1719 3169 'title' : pagelayer_shortcodes[tag]['name'],
1720 3170 'action' : 'Copied',
1721 3171 'pl_id' : id,
1722 - 'html' : jEle,
3172 + 'html' : jEle[0].outerHTML,
1723 3173 'cEle' : cEle
1724 3174 });
1725 3175 }
1726 3176
@@ -1729,13 +3179,309 @@
1729 3179 var row = src.parent().closest('.pagelayer-row');
1730 3180 pagelayer_renumber_col(row);
1731 3181 }
1732 3182
1733 - pagelayer_isDirty = true;
3183 + pagelayer_do_dirty(jEle);
1734 3184
1735 3185 return id;
1736 3186 };
1737 3187
3188 +// Traversing up one step an element
3189 +function pagelayer_move_element_up(selector){
3190 +
3191 + var src = jQuery(selector);
3192 + var srcParent = src.parent();
3193 +
3194 + var srcParentPrev = srcParent.prev('.pagelayer-wrap-row, .pagelayer-wrap-inner-row, .pagelayer-wrap-ele');
3195 +
3196 + if(srcParentPrev.length<=0){
3197 + return;
3198 + }
3199 +
3200 + var srcTopValue = srcParent.offset().top;
3201 +
3202 + if(srcParentPrev.hasClass('pagelayer-wrap-ele')){
3203 +
3204 + var animUpCalc = srcTopValue-srcParentPrev.offset().top;
3205 +
3206 + srcParent.animate({top:-animUpCalc}, 200, function(){
3207 + srcParent.css('top', '');
3208 + srcParentPrev.css('top', '');
3209 + srcParentPrev.before(srcParent.detach());
3210 + });
3211 +
3212 + srcParentPrev.animate({top:(srcParent.height()+srcParentPrev.height())-animUpCalc}, 200, function(){
3213 + srcParentPrev.css('top', '');
3214 + });
3215 +
3216 + // Traverse window scroll with the element
3217 + jQuery('html, body').animate({scrollTop:('-='+(srcTopValue-(srcParentPrev.offset().top)))},200);
3218 + }else{
3219 + srcParentPrev.before(srcParent.detach());
3220 +
3221 + // Traverse window scroll with the element
3222 + jQuery('html, body').animate({scrollTop:('-='+(srcTopValue-(src.parent().offset().top)))},200);
3223 + }
3224 +
3225 + pagelayer_do_dirty(src);
3226 +}
3227 +
3228 +// Traversing down one step an element
3229 +function pagelayer_move_element_down(selector){
3230 +
3231 + var src = jQuery(selector);
3232 + var srcParent = src.parent();
3233 +
3234 + var srcParentNext = srcParent.next('.pagelayer-wrap-row, .pagelayer-wrap-inner-row, .pagelayer-wrap-ele');
3235 +
3236 + if(srcParentNext.length<=0){
3237 + return;
3238 + }
3239 +
3240 + var srcTopValue = srcParent.offset().top;
3241 +
3242 + if(srcParentNext.hasClass('pagelayer-wrap-ele')){
3243 +
3244 + var animDownCalc = srcParentNext.offset().top-srcTopValue;
3245 +
3246 + srcParent.animate({top:(animDownCalc-(srcParent.height()-srcParentNext.height()))}, 200, function(){
3247 + srcParent.css('top', '');
3248 + srcParentNext.css('top', '');
3249 + srcParentNext.after(srcParent.detach());
3250 + });
3251 +
3252 + srcParentNext.animate({top:-animDownCalc}, 200, function(){
3253 + srcParentNext.css('top', '');
3254 + });
3255 +
3256 + // Traverse window scroll with the element
3257 + jQuery('html, body').animate({scrollTop:('+='+(animDownCalc-(srcParent.height()-srcParentNext.height())))},200);
3258 + }else{
3259 + srcParentNext.after(srcParent.detach());
3260 +
3261 + // Traverse window scroll with the element
3262 + jQuery('html, body').animate({scrollTop:('+='+((src.parent().offset().top)-srcTopValue))},200);
3263 + }
3264 +
3265 + pagelayer_do_dirty(src);
3266 +}
3267 +
3268 +// Save sections as template
3269 +function pagelayer_ajax_save_template(data, ajax_call_back = ''){
3270 +
3271 + if(pagelayer_empty(data)){
3272 + return;
3273 + }
3274 +
3275 + //save global sections and widgets
3276 + jQuery.ajax({
3277 + type: "POST",
3278 + url: pagelayer_ajax_url+'&action=pagelayer_save_templ_content&postID='+pagelayer_postID,
3279 + data: {
3280 + pagelayer_nonce: pagelayer_ajax_nonce,
3281 + global_widgets : data
3282 + },
3283 + success: function(response, status, xhr){
3284 + //alert(data);
3285 + var obj = jQuery.parseJSON(response);
3286 + if(!pagelayer_empty(ajax_call_back) || typeof ajax_call_back == 'function'){
3287 + ajax_call_back(obj);
3288 + }
3289 + },
3290 + error: function(errorThrown){
3291 + console.log(errorThrown);
3292 + }
3293 + });
3294 +
3295 +}
3296 +
3297 +// Get global id of the element
3298 +function pagelayer_get_global_id(jEle){
3299 + return pagelayer_get_att(jEle, 'global_id');
3300 +}
3301 +
3302 +// Set element as a global widget
3303 +function pagelayer_set_ele_global(jEle, post_id){
3304 +
3305 + // Add attribute for global ID
3306 + jEle.attr('pagelayer-global-id', post_id);
3307 + pagelayer.history_action = false;
3308 + pagelayer_set_atts(jEle, 'global_id', post_id);
3309 + pagelayer.history_action = true;
3310 +
3311 + return jEle;
3312 +}
3313 +
3314 +// Save widgets as a global widget
3315 +function pagelayer_save_sections(sel, section = 'section'){
3316 +
3317 + var jEle = jQuery(sel);
3318 +
3319 + var pagelayer_ajax_func = {};
3320 + var label = 'Please enter the title';
3321 + var content = pagelayer_generate_sc(jEle, true);
3322 + var data = {};// create array for template data
3323 + data[0] = {};
3324 +
3325 + switch(section){
3326 +
3327 + case 'global_widget' :
3328 + var title = prompt(label, 'Global Widget');
3329 + if (title == null) return;
3330 +
3331 + // Save the widget data in global widget array
3332 + if(pagelayer_empty(pagelayer_global_widgets)){
3333 + pagelayer_global_widgets = {};
3334 + }
3335 +
3336 + break;
3337 +
3338 + case'global_section' :
3339 + var title = prompt(label, 'Global Section');
3340 + if (title == null) return;
3341 +
3342 + break;
3343 +
3344 + case 'section':
3345 + var title = prompt(label, 'Section');
3346 + if (title == null) return;
3347 +
3348 + break;
3349 +
3350 + }
3351 +
3352 + // Add Data
3353 + data[0]['title'] = title;
3354 + data[0]['post_type'] = 'pagelayer-template';
3355 + data[0]['type'] = section;
3356 + data[0]['content'] = content.replace(/pagelayer-id="(.*?)"/g, ""); // Need to remove pagelayer id,
3357 + data[0]['content'] = pagelayer_Base64.encode(data[0]['content']);
3358 +
3359 + // This function for ajax success call back of global widget
3360 + pagelayer_ajax_func['global_widget'] = function(obj){
3361 +
3362 + if(pagelayer_empty(obj['success'])){
3363 + return;
3364 + }
3365 +
3366 + for(var post_id in obj['success']){
3367 +
3368 + pagelayer_set_ele_global(jEle, post_id);
3369 +
3370 + // Add global
3371 + jData = {};
3372 + jData['post_id'] = post_id;
3373 + jData['title'] = title; // TODO : create modal to input title
3374 + jData['$'] = jEle;
3375 + jData['is_dirty'] = true;
3376 +
3377 + // Add the array in global widgets array
3378 + pagelayer_global_widgets[post_id] = jData;
3379 +
3380 + pagelayer.$$('.pagelayer-elpd-close').click();
3381 + pagelayer.$$('.pagelayer-widget-tab').click();
3382 + break;
3383 + }
3384 +
3385 + }
3386 +
3387 + // This function for ajax success call back of global sections
3388 + pagelayer_ajax_func['global_section'] = function(obj){
3389 + // TODO: For global Sections
3390 + //console.log(obj);
3391 + }
3392 +
3393 + // This function for ajax success call back of section s
3394 + pagelayer_ajax_func['section'] = function(obj){
3395 + //console.log(obj);
3396 + }
3397 +
3398 + pagelayer_ajax_save_template(data, pagelayer_ajax_func[section]);
3399 +
3400 +}
3401 +
3402 +// Genrate sc for global widgets
3403 +function pagelayer_generate_sc_global_widget(){
3404 +
3405 + var global_widgets = {};
3406 +
3407 + // Create shortcode for all the global widgets
3408 + for(var y in pagelayer_global_widgets){
3409 + var cWidget = pagelayer_global_widgets[y];
3410 +
3411 + // If is_dirty empty then continue the loop
3412 + if(pagelayer_empty(cWidget['is_dirty'])){
3413 + continue;
3414 + }
3415 +
3416 + global_widgets[y] = {};
3417 + global_widgets[y]['title'] = cWidget['title'];
3418 + global_widgets[y]['post_id'] = pagelayer_empty(cWidget['post_id']) ? 0 : cWidget['post_id'];
3419 + global_widgets[y]['post_type'] = 'pagelayer-template';
3420 + global_widgets[y]['type'] = 'global_widget';
3421 +
3422 + var content = pagelayer_generate_sc(jQuery(cWidget.$), true);
3423 + var tag = pagelayer_tag(jQuery(cWidget.$));
3424 +
3425 + // IF is group then need to remove pagelayer id,
3426 + if(!pagelayer_empty(tag) && pagelayer_is_group(tag)){
3427 + content = content.replace(/pagelayer-id="(.*?)"/g, "");
3428 + }
3429 +
3430 + global_widgets[y]['content'] = pagelayer_Base64.encode(content);
3431 + pagelayer_global_widgets[y]['is_dirty'] = false;
3432 + }
3433 +
3434 + return global_widgets;
3435 +}
3436 +
3437 +var pagelayer_set_global_timmer = {};
3438 +
3439 +// If you edit one Global widget it should be copied to other instances of the same global widget
3440 +function pagelayer_setup_global_widgets(id, jEle){
3441 +
3442 + if(pagelayer_empty(id) || pagelayer_empty(pagelayer_global_widgets[id])){
3443 + return;
3444 + }
3445 +
3446 + var elData = pagelayer_global_widgets[id];
3447 +
3448 + clearTimeout(pagelayer_set_global_timmer);
3449 + pagelayer_set_global_timmer = setTimeout(function(){
3450 + // Set attrs for all the global widgets
3451 + jQuery(pagelayer_editable+' [pagelayer-global-id='+ id +']').each(function(){
3452 +
3453 + var cEle = jQuery(this);
3454 + var cEleID = pagelayer_id(cEle);
3455 +
3456 + if( jEle.length > 0 && jEle.is(cEle)){
3457 + return true;
3458 + }
3459 +
3460 + pagelayer.history_action = false;
3461 + pagelayer.global_render = false;
3462 +
3463 + // Get HTML form global array
3464 + var html = pagelayer_element_unsetup(elData.$, cEleID);
3465 +
3466 + if(cEle.parent().is('.pagelayer-ele-wrap')){
3467 + cEle.parent().children('.pagelayer-ele-overlay').remove();
3468 + cEle.unwrap();
3469 + }
3470 +
3471 + cEle[0].outerHTML = html[0].outerHTML;
3472 +
3473 + pagelayer_element_setup('[pagelayer-id='+cEleID+'], [pagelayer-id='+cEleID+'] .pagelayer-ele');
3474 + pagelayer_sc_render(jQuery('[pagelayer-id="'+cEleID+'"]'));
3475 +
3476 + pagelayer.history_action = true;
3477 + pagelayer.global_render = true;
3478 + });
3479 +
3480 + }, 3000);
3481 +
3482 +}
3483 +
1738 3484 // Language key
1739 3485 function pagelayer_l(k){
1740 3486 if(k in pagelayer_lang){
1741 3487 return pagelayer_lang[k];
@@ -1748,8 +3494,51 @@
1748 3494 var props = pagelayer_shortcodes[pagelayer_tag(jEle)];
1749 3495 return props;
1750 3496 }
1751 3497
3498 +// Get all props based on the tag but in a single structure
3499 +function pagelayer_make_props_ref(){
3500 +
3501 + // Loop through pagelayer_shortcodes
3502 + for(var tag in pagelayer_shortcodes){
3503 +
3504 + var all_props = pagelayer_shortcodes[tag];
3505 + pagelayer.props_ref[tag] = {};
3506 +
3507 + // Loop through all props
3508 + for(var i in pagelayer_tabs){
3509 +
3510 + var tab = pagelayer_tabs[i];
3511 +
3512 + for(var section in all_props[tab]){
3513 +
3514 + var props = section in pagelayer_shortcodes[tag] ? pagelayer_shortcodes[tag][section] : pagelayer_styles[section];
3515 +
3516 + // In case of widgets its possible !
3517 + if(pagelayer_empty(props)){
3518 + continue;
3519 + }
3520 +
3521 + for(var x in props){
3522 +
3523 + // Create an easy REFERENCE for access
3524 + pagelayer.props_ref[tag][x] = props[x];
3525 +
3526 + // Screen option REFERENCE is also needed for lookup
3527 + if('screen' in props[x]){
3528 + pagelayer.props_ref[tag][x+'_tablet'] = props[x];
3529 + pagelayer.props_ref[tag][x+'_mobile'] = props[x];
3530 + }
3531 +
3532 + }
3533 + }
3534 +
3535 + }
3536 +
3537 + }
3538 +
3539 +}
3540 +
1752 3541 // Set the given jELE as active
1753 3542 function pagelayer_set_active(jEle){
1754 3543
1755 3544 // Make all other element as inactive
@@ -1764,14 +3553,8 @@
1764 3553 jQuery('.pagelayer-active').removeClass('pagelayer-active');
1765 3554
1766 3555 jEle.parent().children('.pagelayer-ele-overlay').addClass('pagelayer-active');
1767 3556
1768 - // Hide active when not supported by tag
1769 - var props = pagelayer_get_props(jEle);
1770 - if(!pagelayer_empty(props['hide_active'])){
1771 - jEle.parent().children('.pagelayer-ele-overlay').addClass('pagelayer-hide-active');
1772 - }
1773 -
1774 3557 }
1775 3558
1776 3559 function pagelayer_sc(sc){
1777 3560 return sc.replace('pl_', '');
@@ -1853,16 +3636,88 @@
1853 3636
1854 3637 return jEle.attr('pagelayer-tag');
1855 3638 }
1856 3639
3640 +function pagelayer_el_data_ref(jEle){
3641 + var id = pagelayer_id(jEle);
3642 +
3643 + if(!(id in pagelayer.el)){
3644 + pagelayer.el[id] = {};
3645 + }
3646 +
3647 + if(typeof pagelayer.el[id] !== 'object'){
3648 + pagelayer.el[id] = {};
3649 + }
3650 +
3651 + if(!('attr' in pagelayer.el[id])){
3652 + pagelayer.el[id]['attr'] = {};
3653 + }
3654 +
3655 + if(Array.isArray(pagelayer.el[id]['attr'])){
3656 + pagelayer.el[id]['attr'] = {};
3657 + }
3658 +
3659 + if(!('tmp' in pagelayer.el[id])){
3660 + pagelayer.el[id]['tmp'] = {};
3661 + }
3662 +
3663 + if(Array.isArray(pagelayer.el[id]['tmp'])){
3664 + pagelayer.el[id]['tmp'] = {};
3665 + }
3666 +
3667 + return pagelayer.el[id];
3668 +};
3669 +
3670 +// Gets the data node which can be position 0 or 1
3671 +function pagelayer_el_get_data_node(jEle){
3672 + var node = jEle[0].childNodes[0];
3673 + if(node && node.nodeType === 8){
3674 + return node;
3675 + }
3676 + node = jEle[0].childNodes[1];
3677 + if(node && node.nodeType === 8){
3678 + return node;
3679 + }
3680 + return false;
3681 +}
3682 +
3683 +// Get the data
3684 +function pagelayer_el_get_data(jEle){
3685 + var node = pagelayer_el_get_data_node(jEle);
3686 + if(node){
3687 + return JSON.parse(node.nodeValue);
3688 + }
3689 + return false;
3690 +};
3691 +
3692 +// Add the data back again
3693 +function pagelayer_el_dump_data(jEle){
3694 + var node = pagelayer_el_get_data_node(jEle);
3695 + var d = pagelayer_serializeAttributes(pagelayer_el_data_ref(jEle));
3696 +
3697 + if(node){
3698 + node.nodeValue = d;
3699 + }else{
3700 + jEle.prepend('<!-- '+d+' -->');
3701 + }
3702 +};
3703 +
1857 3704 // Gets a single attribute value
1858 3705 function pagelayer_get_att(jEle, att){
1859 - return jEle.attr('pagelayer-a-'+att);
3706 + var ref_data = pagelayer_el_data_ref(jEle);
3707 + if(att in ref_data['attr']){
3708 + return ref_data['attr'][att];
3709 + }
3710 + return;
1860 3711 };
1861 3712
1862 3713 // Gets a single attribute value
1863 3714 function pagelayer_get_tmp_att(jEle, att){
1864 - return jEle.attr('pagelayer-tmp-'+att);
3715 + var ref_data = pagelayer_el_data_ref(jEle);
3716 + if(att in ref_data['tmp']){
3717 + return ref_data['tmp'][att];
3718 + }
3719 + return;
1865 3720 };
1866 3721
1867 3722 // This function will just set atts and not do anything else
1868 3723 // Atts can be string or object. If its string, then val is needed
@@ -1922,10 +3777,25 @@
1922 3777 if('no_val' in props[x]){
1923 3778 no_val[x] = 1;
1924 3779 }
1925 3780
1926 - if('req' in props[x] || 'show' in props[x]){
3781 + if('req' in props[x] || 'show' in props[x]){
1927 3782 var show = 'req' in props[x] ? props[x]['req'] : props[x]['show'];
3783 +
3784 + // We have both req and show, so lets just combine the values and then show
3785 + // NOTE : We need to make an array and not just merge the 2 as they are references
3786 + if('req' in props[x] && 'show' in props[x]){
3787 +
3788 + // Add the req values
3789 + show = JSON.parse(JSON.stringify(props[x]['req']));
3790 +
3791 + // Now the show values need to be looped
3792 + for(var t in props[x]['show']){
3793 + show[t] = props[x]['show'][t];
3794 + }
3795 +
3796 + }
3797 +
1928 3798 for(var showParam in show){
1929 3799 var val = show[showParam];
1930 3800 var except = showParam.substr(0, 1) == '!' ? true : false;
1931 3801 showParam = except ? showParam.substr(1) : showParam;
@@ -1939,8 +3809,10 @@
1939 3809 }
1940 3810
1941 3811 }
1942 3812
3813 + var ref_data = pagelayer_el_data_ref(jEle);
3814 +
1943 3815 for(var x in atts){
1944 3816
1945 3817 // Are we to trigger change
1946 3818 if(x in trigger_props){
@@ -1949,9 +3821,9 @@
1949 3821
1950 3822 //console.log(x+'-'+atts[x]);
1951 3823
1952 3824 // Is this a pro feature and we are not pro ? Then we dont do anything and continue !
1953 - if('pro' in _props[x] && pagelayer_empty(pagelayer_pro)){
3825 + if(!pagelayer_empty(_props[x]) && 'pro' in _props[x] && pagelayer_empty(pagelayer_pro)){
1954 3826 continue;
1955 3827 }
1956 3828
1957 3829 if(x in no_val){
@@ -1961,11 +3833,17 @@
1961 3833
1962 3834 // Record History
1963 3835 if(pagelayer.history_action){
1964 3836 var old_val = pagelayer_get_att(jEle, x) || '';
3837 + var label = x;
3838 +
3839 + if(x in _props && 'label' in _props[x]){
3840 + label = _props[x]['label'];
3841 + }
3842 +
1965 3843 pagelayer_history_action_push({
1966 3844 'title' : all_props['name'],
1967 - 'subTitle' : _props[x]['label'],
3845 + 'subTitle' : label,
1968 3846 'action' : 'Edited',
1969 3847 'attrType' : 'a_attr',
1970 3848 'pl_id' : pagelayer_id(jEle),
1971 3849 'atts' : x,
@@ -1972,40 +3850,27 @@
1972 3850 'oldVal' : old_val,
1973 3851 'newVal' : atts[x]
1974 3852 });
1975 3853 }
1976 -
3854 +
1977 3855 // Remove the attribute if its BLANK and there is no default for it
1978 3856 // If there is a default, we set it to blank to keep record of the current val
1979 - if(atts[x].length < 1){
3857 + if(pagelayer_length(atts[x]) < 1){
1980 3858
1981 - // Dont remove the value as there is a default
3859 + // Remove values which are not defaults
1982 3860 if(!(x in defaults)){
1983 - jEle.removeAttr('pagelayer-a-'+x);
1984 - // Otherwise blank it
3861 + delete ref_data['attr'][x];
3862 + // Otherwise keep value set for avoiding resetting
1985 3863 }else{
1986 - jEle.attr('pagelayer-a-'+x, atts[x]);
3864 + ref_data['attr'][x] = atts[x];
1987 3865 }
1988 3866
1989 3867 // Remove the tmp atts anyway
1990 - var to_del = new Array();
1991 - var regexp = new RegExp('pagelayer\-tmp\-'+x, 'gi');
1992 -
1993 - jQuery.each(jEle[0].attributes, function(index, att){
1994 - if(!att) return;
1995 - if(att.name.match(regexp)){
1996 - to_del.push(att.name);
1997 - }
1998 - });
1999 -
2000 - //console.log(to_del);
2001 - for(var n in to_del){
2002 - jEle.removeAttr(to_del[n]);
2003 - }
3868 + pagelayer_clear_tmp_atts(jEle, x);
2004 3869
2005 3870 // Set the value
2006 3871 }else{
2007 - jEle.attr('pagelayer-a-'+x, atts[x]);
3872 + ref_data['attr'][x] = pagelayer_trim(atts[x]);
2008 3873 }
2009 3874
2010 3875 // Are you the active element
2011 3876 if(pagelayer_is_active(jEle)){
@@ -2015,14 +3880,17 @@
2015 3880 }
2016 3881
2017 3882 }
2018 3883
3884 + pagelayer_el_dump_data(jEle);
3885 +
2019 3886 // Trigger the change of the parameter and show the required properties
2020 3887 if(trigger_onchange){
2021 3888 pagelayer_elpd_show_rows();
2022 3889 }
2023 3890
2024 - pagelayer_isDirty = true;
3891 + pagelayer_do_dirty(jEle);
3892 +
2025 3893 };
2026 3894
2027 3895 // This function will just set atts and not do anything else
2028 3896 // Atts can be string or object. If its string, then val is needed
@@ -2037,10 +3905,12 @@
2037 3905 if(typeof atts != 'object'){
2038 3906 return false;
2039 3907 }
2040 3908
3909 + var ref_data = pagelayer_el_data_ref(jEle);
3910 +
2041 3911 for(var x in atts){
2042 -
3912 +
2043 3913 // Record history
2044 3914 if(pagelayer.history_action){
2045 3915
2046 3916 var old_val = pagelayer_get_tmp_att(jEle, x) || '';
@@ -2055,27 +3925,51 @@
2055 3925 'newVal' : atts[x]
2056 3926 });
2057 3927
2058 3928 }
2059 -
2060 - jEle.attr('pagelayer-tmp-'+x, atts[x]);
3929 +
3930 + ref_data['tmp'][x] = atts[x];
3931 +
2061 3932 }
2062 3933
3934 + pagelayer_el_dump_data(jEle);
3935 +
2063 3936 };
2064 3937
2065 -// Set the att and classes of an HTML which is not yet created
2066 -function pagelayer_sc_atts(classes, atts){
3938 +// This function removes the temporary attributes of an ele
3939 +function pagelayer_clear_tmp_atts(jEle, attr){
2067 3940
2068 - if(typeof atts != 'object'){
2069 - atts = new Object();
3941 + var to_del = new Array();
3942 + var regexp = new RegExp('^'+attr+'\-', 'gi');
3943 + var ref_data = pagelayer_el_data_ref(jEle);
3944 +
3945 + //console.log(to_del);
3946 + for(var n in ref_data['tmp']){
3947 + if(n.match(regexp)){
3948 + delete ref_data['tmp'][n];
3949 + }
2070 3950 }
3951 +}
3952 +
3953 +// This function removes the temporary attributes of an ele
3954 +function pagelayer_img_tmp_atts(jEle, attr){
2071 3955
2072 - var r = new Array();
3956 + var found = {};
3957 + var regexp = new RegExp('^'+attr+'\-', 'gi');
3958 + var ref_data = pagelayer_el_data_ref(jEle);
2073 3959
2074 - for(var x in atts){
2075 - r.push('pagelayer-a-'+x+'="'+atts[x]+'"');
3960 + for(var n in ref_data['tmp']){
3961 + if(n.match(regexp)){
3962 + found[n] = 1;
3963 + }
2076 3964 }
2077 3965
3966 + return found;
3967 +}
3968 +
3969 +// Set the att and classes of an HTML which is not yet created
3970 +function pagelayer_sc_atts(classes){
3971 + var r = new Array();
2078 3972 return 'class="'+classes+' pagelayer-ele" '+r.join(' ');
2079 3973 }
2080 3974
2081 3975 // Is the jEle the active element ?
@@ -2101,16 +3995,33 @@
2101 3995
2102 3996 // Seperator
2103 3997 seperator = seperator || ',';
2104 3998
3999 + var replaceCss = function(rule, value, toreplace){
4000 +
4001 + value = pagelayer_hex8_to_rgba(value);
4002 +
4003 + // If value has css var then we remove units
4004 + if(value.match(/var\(/)){
4005 + var toreplace = toreplace.replace(/[-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
4006 + toreplace = new RegExp( toreplace+'?[^\\s|;]+', 'ig');
4007 + }
4008 +
4009 + return rule.split(toreplace).join(value);
4010 + }
4011 +
2105 4012 // Replace the val
2106 - css = css.split('{{val}}').join(pagelayer_hex8_to_rgba(val));
4013 + css = replaceCss(css, val, '{{val}}');
2107 4014
2108 4015 // If there is an array
2109 4016 if(css.match(/val\[\d/)){
2110 - val = val.split(seperator);
4017 +
4018 + if(typeof val != 'object' || val === null){
4019 + val = String(val).split(seperator);
4020 + }
4021 +
2111 4022 for(var i in val){
2112 - css = css.split('{{val['+i+']}}').join(pagelayer_hex8_to_rgba(val[i]));
4023 + css = replaceCss(css, val[i], '{{val['+i+']}}');
2113 4024 }
2114 4025 }
2115 4026
2116 4027 //console.log('Final CSS '+css);
@@ -2121,8 +4032,10 @@
2121 4032
2122 4033 // Handle hexa to rgba and also remove alpha which is ff
2123 4034 function pagelayer_hex8_to_rgba(val){
2124 4035
4036 + val = String(val);
4037 +
2125 4038 // If opacity is ff then discard ff
2126 4039 if(val.match(/^#([a-f0-9]{6})ff$/)){
2127 4040 return val.substr(0,7);
2128 4041 }
@@ -2139,9 +4052,9 @@
2139 4052
2140 4053 // Replace the variables
2141 4054 function pagelayer_parse_el_vars(str, el){
2142 4055
2143 - str = str.split('{{element}}').join(el.CSS.sel);
4056 + str = str.split('{{element}}').join(el.CSS.cssSel);
2144 4057 str = str.split('{{wrap}}').join(el.CSS.wrap);
2145 4058 str = str.split('{{ele_id}}').join(el.id);
2146 4059
2147 4060 return str;
@@ -2182,8 +4095,9 @@
2182 4095 attr: [],
2183 4096 remove_attr: [],
2184 4097 css: [],
2185 4098 edit: [],
4099 + cssSel: '.p-'+el.id,
2186 4100 sel: '[pagelayer-id="'+el.id+'"]',
2187 4101 wrap: '[pagelayer-wrap-id="'+el.id+'"]'
2188 4102 };
2189 4103
@@ -2188,8 +4102,11 @@
2188 4102 };
2189 4103
2190 4104 // Create a reference
2191 4105 el.CSS = elCSS;
4106 +
4107 + // Make sure if we have the class selector
4108 + el.$.addClass('p-'+el.id);
2192 4109
2193 4110 //console.log(el.atts);
2194 4111
2195 4112 for(var i in pagelayer_tabs){
@@ -2203,10 +4120,10 @@
2203 4120
2204 4121 // pagelayer_data will return attributes even if they are BLANK e.g. attr=""
2205 4122 // Render doesnt consider BLANK values as values, and we are unsetting them now
2206 4123 // If in any situation you need to consider blank values, please handle in the JS / PHP function of the Shortcode
2207 - if(x in el.atts && el.atts[x].length < 1){
2208 - delete el.atts[x];
4124 + if(x in el.atts && pagelayer_length(el.atts[x]) < 1){
4125 + delete el.atts[x];
2209 4126 }
2210 4127
2211 4128 // Any editor ?
2212 4129 if('edit' in props[x]){
@@ -2212,8 +4129,59 @@
2212 4129 if('edit' in props[x]){
2213 4130 elCSS.edit.push({prop: x, sel: props[x]['edit']});
2214 4131 }
2215 4132
4133 + // Load permalink values
4134 + if(props[x]['type'] == 'link'){
4135 +
4136 + if('selector' in props[x] && typeof el.atts[x] == 'object'){
4137 + var tmp = {};
4138 +
4139 + // Link is required for check IF and IF-EXT in html
4140 + if(pagelayer_length(el.atts[x]['link']) < 1){
4141 + delete el.atts[x];
4142 + continue;
4143 + }
4144 +
4145 + if( 'target' in el.atts[x] && !pagelayer_empty(el.atts[x]['target']) ){
4146 + tmp = {'sel': props[x]['selector'], 'val': 'target="_blank"'};
4147 + elCSS['attr'].push(tmp);
4148 + }
4149 +
4150 + if( 'rel' in el.atts[x] && !pagelayer_empty(el.atts[x]['rel']) ){
4151 + tmp = {'sel': props[x]['selector'], 'val': 'rel="nofollow"'};
4152 + elCSS['attr'].push(tmp);
4153 + }
4154 +
4155 + if( 'attrs' in el.atts[x] && !pagelayer_empty(el.atts[x]['attrs']) ){
4156 +
4157 + var attrsVal = pagelayer_trim(el.atts[x]['attrs'].split(';'));
4158 +
4159 + attrsVal.forEach(function(item, index){
4160 +
4161 + var splitValue = item.split(/=(.*)/);
4162 + var attKey = pagelayer_trim(splitValue[0]);
4163 + var setAtt = '';
4164 +
4165 + // Validate the attrs name
4166 + if(attKey.length < 1 || pagelayer_empty(attKey.match(/^[a-z_]+[\w:.-]*$/i))){
4167 + return;
4168 + }
4169 +
4170 + if(splitValue.length < 2){
4171 + setAtt = attKey+'=""';
4172 + }else{
4173 + setAtt = attKey+'="'+splitValue[1]+'"';
4174 + }
4175 +
4176 + tmp = {'sel': props[x]['selector'], 'val': setAtt};
4177 + elCSS['attr'].push(tmp);
4178 +
4179 + });
4180 + }
4181 + }
4182 + }
4183 +
2216 4184 // Do we have a addClass ?
2217 4185 // We are checking before the element has a value so that we can add or remove the class
2218 4186 if('addClass' in props[x]){
2219 4187
@@ -2248,9 +4216,9 @@
2248 4216 }
2249 4217
2250 4218 }else{
2251 4219
2252 - var tmp = {'sel': tSel, 'val': addClasses[c]};
4220 + var tmp = {'sel': tSel, 'val': addClasses[c].replace('{{val}}', el.atts[x])};
2253 4221
2254 4222 // If the value is there
2255 4223 if(x in el.atts){
2256 4224 elCSS['classes'].push(tmp);
@@ -2303,8 +4271,9 @@
2303 4271 }
2304 4272
2305 4273 // Screen modes
2306 4274 var modes = {desktop: '', tablet: '_tablet', mobile: '_mobile'};
4275 + var desk_global = (props[x]['type'] == 'typography') ? pagelayer_is_global_typo(el.atts[x]) : '';
2307 4276
2308 4277 for(var m in modes){
2309 4278
2310 4279 var xm = x+modes[m];
@@ -2309,12 +4278,37 @@
2309 4278
2310 4279 var xm = x+modes[m];
2311 4280
2312 4281 // If the value is there
2313 - if(!(xm in el.atts)){
4282 + if(!(xm in el.atts) && pagelayer_empty(desk_global)){
2314 4283 continue;
2315 4284 }
2316 -
4285 +
4286 + var xm_val = el.atts[xm];
4287 +
4288 + // If is global color
4289 + if(props[x]['type'] == 'color'){
4290 + xm_val = pagelayer_parse_color(el.atts[xm]);
4291 + }
4292 +
4293 + // If is global font
4294 + if(props[x]['type'] == 'typography'){
4295 + xm_val = pagelayer_parse_typo(xm_val, false, desk_global, m);
4296 + }
4297 +
4298 + // If there is global gradient color
4299 + if(props[x]['type'] == 'gradient'){
4300 +
4301 + if(pagelayer_is_string(xm_val)){
4302 + xm_val = xm_val.split(',');
4303 + }
4304 +
4305 + for(key in xm_val){
4306 + xm_val[key] = pagelayer_parse_color(xm_val[key]);
4307 + }
4308 +
4309 + }
4310 +
2317 4311 for(var c in css){
2318 4312
2319 4313 // The selector
2320 4314 var tSel = jQuery.isNumeric(c) ? '{{element}}' : c;
@@ -2319,20 +4313,20 @@
2319 4313 // The selector
2320 4314 var tSel = jQuery.isNumeric(c) ? '{{element}}' : c;
2321 4315 var tmp = {
2322 4316 sel: tSel,
2323 - val: pagelayer_css_render(css[c], el.atts[xm], (props[x].sep || ',')),
4317 + val: pagelayer_css_render(css[c], xm_val, (props[x].sep || ',')),
2324 4318 };
2325 4319
2326 4320 // Is this a tablet
2327 4321 if(m == 'tablet'){
2328 - tmp.sel = '@media (max-width: 768px) and (min-width: 361px){'+tmp.sel;
4322 + tmp.sel = '@media (max-width: '+ pagelayer_settings['tablet_breakpoint'] +'px) and (min-width: '+ (pagelayer_settings['mobile_breakpoint'] +1) +'px){'+tmp.sel;
2329 4323 tmp.val = tmp.val+'}';
2330 4324 }
2331 4325
2332 4326 // Is this a mobile mode ?
2333 4327 if(m == 'mobile'){
2334 - tmp.sel = '@media (max-width: 360px){'+tmp.sel;
4328 + tmp.sel = '@media (max-width: '+ pagelayer_settings['mobile_breakpoint'] +'px){'+tmp.sel;
2335 4329 tmp.val = tmp.val+'}';
2336 4330 }
2337 4331
2338 4332 // Push to store
@@ -2350,9 +4344,16 @@
2350 4344 }
2351 4345
2352 4346 // If there is an HTML, then process it
2353 4347 if('html' in pagelayer_shortcodes[el.tag]){
4348 +
4349 + // Is there a function to render ?
4350 + var fn = window['pagelayer_render_'+jEle.attr('pagelayer-tag')];
2354 4351
4352 + if(typeof fn == 'function'){
4353 + fn(el);
4354 + }
4355 +
2355 4356 el.iHTML = jQuery('<div>'+pagelayer_shortcodes[el.tag]['html']+'</div>');
2356 4357
2357 4358 // Lets process the 'if-ext'
2358 4359 el.iHTML.find('[if-ext]').each(function (){
@@ -2380,16 +4381,9 @@
2380 4381 $j.remove();
2381 4382 }
2382 4383
2383 4384 });
2384 -
2385 - // Is there a function to render ?
2386 - var fn = window['pagelayer_render_'+jEle.attr('pagelayer-tag')];
2387 4385
2388 - if(typeof fn == 'function'){
2389 - fn(el);
2390 - }
2391 -
2392 4386 //console.log(el.atts);
2393 4387
2394 4388 // Parse the variables
2395 4389 var new_html = pagelayer_parse_vars(el.iHTML.html(), el);
@@ -2446,9 +4440,9 @@
2446 4440 for(var c in elCSS.edit){
2447 4441 var prop = elCSS.edit[c]['prop'];
2448 4442 var tSel = elCSS.edit[c]['sel'];
2449 4443 var node = tSel.length < 1 ? jEle : jEle.find(tSel);
2450 - node.attr('pagelayer-editable', prop);
4444 + node.attr({'pagelayer-editable': prop, 'contenteditable' : 'true'});
2451 4445 }
2452 4446
2453 4447 }
2454 4448
@@ -2492,9 +4486,9 @@
2492 4486
2493 4487 for(var c in elCSS.attr){
2494 4488 var tSel = elCSS.attr[c]['sel'].replace('{{element}}', '');
2495 4489 var node = tSel.length < 1 ? jEle : jEle.find(tSel);
2496 - var att = elCSS.attr[c]['val'].split('=');
4490 + var att = elCSS.attr[c]['val'].split(/=(.*)/);
2497 4491 att[1] = pagelayer_parse_vars(att[1], el);
2498 4492 att[1] = pagelayer_trim(att[1], '"');
2499 4493
2500 4494 // Is it the same val ?
@@ -2538,9 +4532,9 @@
2538 4532
2539 4533 // Loop
2540 4534 for(var c in elCSS.css){
2541 4535 var tSel = pagelayer_parse_el_vars(elCSS.css[c]['sel'], el);
2542 - var rule = pagelayer_parse_vars(elCSS.css[c]['val'], el);
4536 + var rule = elCSS.css[c]['val'];
2543 4537 if(tSel.length > 0){
2544 4538 rules.push(tSel+'{'+rule+'}');
2545 4539 }else{
2546 4540 rules.push(pagelayer_parse_el_vars(rule, el));
@@ -2549,15 +4543,16 @@
2549 4543
2550 4544 // CSS Selector overide
2551 4545 if(!pagelayer_empty(all_props['overide_css_selector'])){
2552 4546 for(var r in rules){
2553 - rules[r] = rules[r].split(el.CSS.sel).join(all_props['overide_css_selector']);
2554 - rules[r] = rules[r].split(el.CSS.wrap).join(all_props['overide_css_selector']);
4547 + var overide_css_selector = pagelayer_parse_el_vars(all_props['overide_css_selector'], el);
4548 + rules[r] = rules[r].split(el.CSS.cssSel).join(overide_css_selector);
4549 + rules[r] = rules[r].split(el.CSS.wrap).join(overide_css_selector);
2555 4550 }
2556 4551 }
2557 4552
2558 4553 // Set the style
2559 - style.html(rules.join("\n"));
4554 + style.html(pagelayer_parse_vars(rules.join("\n"), el));
2560 4555 //console.log(style);
2561 4556 }else{
2562 4557 style.remove();
2563 4558 }
@@ -2570,14 +4565,150 @@
2570 4565 }
2571 4566
2572 4567 // If the element have any parent
2573 4568 var par = pagelayer_get_parent(jEle);
4569 + var eleId = el.id;
4570 +
2574 4571 if(par){
4572 + eleId = par;
2575 4573 pagelayer_sc_render(pagelayer_ele_by_id(par));
2576 4574 }
2577 4575
4576 + // Render End trigger
4577 + pagelayer_trigger_action('pagelayer_sc_render_end', [el]);
4578 +
4579 + var gEle = pagelayer_ele_by_id(eleId);
4580 + var gId = pagelayer_get_global_id(gEle);
4581 +
4582 + pagelayer_el_dump_data(jEle);
4583 +
4584 + // If global id exist then update the global array and restup the all global element
4585 + if(!pagelayer_empty(gId) && !pagelayer_empty(pagelayer.global_render)){
4586 + if(!pagelayer_empty(pagelayer_global_widgets[gId])){
4587 + pagelayer_global_widgets[gId].$ = gEle[0].outerHTML;
4588 + pagelayer_global_widgets[gId]['is_dirty'] = true;
4589 + pagelayer_setup_global_widgets(gId, pagelayer_ele_by_id(eleId), true);
4590 + }else{
4591 + pagelayer_set_atts(gEle, 'global_id', '');
4592 + }
4593 + };
4594 +
2578 4595 };
2579 4596
4597 +// Is the given global color
4598 +function pagelayer_is_global_color(color){
4599 +
4600 + var color_key = color.substr(0, 1) == '$' ? color.substr(1) : '';
4601 +
4602 + // If global color not exist
4603 + if(!pagelayer_empty(color_key)){
4604 +
4605 + if(!(color_key in pagelayer_global_colors)){
4606 + color_key = 'primary';
4607 + }
4608 +
4609 + return color_key;
4610 + }
4611 +
4612 + return false;
4613 +
4614 +}
4615 +
4616 +// Is the given global color
4617 +function pagelayer_is_global_typo(value){
4618 +
4619 + var typo_key = '';
4620 +
4621 + // Backward compatibility
4622 + if(pagelayer_is_string(value) && value.substr(0, 1) == '$'){
4623 + typo_key = value.substr(1);
4624 + }
4625 +
4626 + if(typeof value == 'object' && 'global-font' in value){
4627 + typo_key = value['global-font'];
4628 + }
4629 +
4630 + // If global color not exist
4631 + if(!pagelayer_empty(typo_key) && !(typo_key in pagelayer_global_fonts)){
4632 + typo_key = 'primary';
4633 + }
4634 +
4635 + return typo_key;
4636 +
4637 +}
4638 +
4639 +// Parse typography and handle Backward compatibility
4640 +function pagelayer_parse_typo(value, noglobal, desk_global, mode){
4641 +
4642 + noglobal = noglobal || false;
4643 + mode = mode || 'desktop';
4644 + desk_global = desk_global || '';
4645 +
4646 + if(pagelayer_empty(value)){
4647 + value = {};
4648 + }
4649 +
4650 + // Backward compatibility for comma seperated val
4651 + if(pagelayer_is_string(value) && value.substr(0, 1) != '$'){
4652 + return value.split(',');
4653 + }
4654 +
4655 + var val = ['','','','','','','','','','',''];
4656 + 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'];
4657 +
4658 + var global_typo = pagelayer_is_global_typo(value);
4659 + var _desk_global = false;
4660 +
4661 + if(pagelayer_empty(global_typo)){
4662 + global_typo = desk_global;
4663 + _desk_global = true;
4664 + }
4665 +
4666 + // Apply global typo
4667 + for(var typo in typos){
4668 +
4669 + var typoKey = typos[typo];
4670 +
4671 + // Backspace compatibility for normal array
4672 + if(typeof value == 'object' && !pagelayer_empty(value[typo])){
4673 + val[typo] = value[typo];
4674 + }
4675 +
4676 + if(!pagelayer_empty(value[typoKey])){
4677 + val[typo] = value[typoKey];
4678 + }
4679 +
4680 + if(pagelayer_empty(global_typo) || !pagelayer_empty(val[typo]) || noglobal){
4681 + continue;
4682 + }
4683 +
4684 + var globalVal = pagelayer_global_fonts[global_typo]['value'];
4685 +
4686 + 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') ){
4687 + continue;
4688 + }
4689 +
4690 + val[typo] = 'var(--pagelayer-font-'+global_typo+'-'+typoKey+')';
4691 + }
4692 +
4693 + return val;
4694 +}
4695 +
4696 +// Parse color for global color
4697 +function pagelayer_parse_color(value, glob_var = true){
4698 +
4699 + var is_global = pagelayer_is_global_color(value);
4700 + if(pagelayer_empty(is_global)){
4701 + return value;
4702 + }
4703 +
4704 + if(pagelayer_empty(glob_var)){
4705 + return pagelayer_global_colors[is_global]['value'];
4706 + }
4707 +
4708 + return 'var(--pagelayer-color-'+is_global+')';
4709 +}
4710 +
2580 4711 // Is the given tag a group
2581 4712 function pagelayer_is_group(tag){
2582 4713
2583 4714 if('has_group' in pagelayer_shortcodes[tag] && !pagelayer_empty(pagelayer_shortcodes[tag]['has_group'])){
@@ -2588,10 +4719,10 @@
2588 4719
2589 4720 }
2590 4721
2591 4722 // Do action / event
2592 -function pagelayer_trigger_action(act){
2593 - jQuery(document).trigger(act);
4723 +function pagelayer_trigger_action(act, param = []){
4724 + jQuery(document).trigger(act, param);
2594 4725 }
2595 4726
2596 4727 // Perform a function on an action / event
2597 4728 function pagelayer_add_action(act, func){
@@ -2597,50 +4728,298 @@
2597 4728 function pagelayer_add_action(act, func){
2598 4729 jQuery(document).on(act, func);
2599 4730 }
2600 4731
4732 +// Create array of the contact from template params
4733 +function pagelayer_get_contact_templates(){
4734 +
4735 + var contacts = jQuery(pagelayer_editable+' [pagelayer-tag=pl_contact]');
4736 + var contacts_props = {};
4737 + if(contacts.length > 0){
4738 +
4739 + contacts.each(function(){
4740 +
4741 + var tmp = pagelayer_data(jQuery(this));
4742 + var con_allowed = ['to_email', 'from_email', 'cont_subject', 'cont_header', 'cont_body', 'cont_use_html'];
4743 +
4744 + if(pagelayer_empty(tmp.atts['contact_custom_templ'])) return true;
4745 +
4746 + // Define blank array
4747 + contacts_props[tmp.id] = {};
4748 +
4749 + for(var x in con_allowed){
4750 + var key = con_allowed[x];
4751 + if(!pagelayer_empty(tmp.atts[key])){
4752 + contacts_props[tmp.id][key] = tmp.atts[key];
4753 + }
4754 + }
4755 +
4756 + });
4757 + }
4758 +
4759 + return contacts_props;
4760 +}
4761 +
4762 +// Save data or meta of the post
4763 +function pagelayer_update_post_data(){
4764 +
4765 + var tag = 'pl_post_props';
4766 + var jEle = jQuery(pagelayer_editable+' [pagelayer-tag="'+tag+'"]');
4767 +
4768 + if(jEle.length < 1){
4769 + return;
4770 + }
4771 +
4772 + var tmp = pagelayer_data(jEle, true);
4773 + var all_props = pagelayer_shortcodes[tag];
4774 +
4775 + // Loop through all props
4776 + for(var i in pagelayer_tabs){
4777 +
4778 + var tab = pagelayer_tabs[i];
4779 +
4780 + for(var section in all_props[tab]){
4781 +
4782 + var props = section in pagelayer_shortcodes[tag] ? pagelayer_shortcodes[tag][section] : pagelayer_styles[section];
4783 +
4784 + for(var x in props){
4785 + //Set pagelayer POST data to send with save ajax
4786 + if(x in tmp['atts']){
4787 + pagelayer_ajax_post_data[x] = tmp['atts'][x];
4788 + }else if(x in pagelayer_ajax_post_data){
4789 + delete pagelayer_ajax_post_data[x];
4790 + }
4791 + }
4792 + }
4793 + }
4794 +}
4795 +
4796 +// Get the nav menu updated data
4797 +function pagelayer_get_nav_items(jEle, _content){
4798 +
4799 + _content = _content || false;
4800 +
4801 + var pagelayer_nav_items = {};
4802 +
4803 + jEle.find('[pagelayer-tag="pl_nav_menu_item"]').each(function(){
4804 + var cEle = jQuery(this),
4805 + postID = pagelayer_get_att(cEle, 'ID');
4806 +
4807 + if(!(postID in pagelayer_menus_items_ref)){
4808 + return;
4809 + }
4810 +
4811 + var ref_data = pagelayer_menus_items_ref[postID];
4812 +
4813 + if(!('pagelayer_content' in ref_data) && pagelayer_empty(ref_data['pagelayer_content'])){
4814 + ref_data['pagelayer_content'] = cEle;
4815 + }
4816 +
4817 + if(!('is_dirty' in ref_data) || pagelayer_empty(ref_data['is_dirty'])){
4818 + return;
4819 + }
4820 +
4821 + var content = '',
4822 + tmp = {};
4823 + tmp = Object.assign(tmp, ref_data);
4824 + pagelayer_nav_items[postID] = {};
4825 +
4826 + // Update Mega menu content
4827 + if(!pagelayer_empty(_content)){
4828 + var navItem = jQuery(ref_data['pagelayer_content'])[0].outerHTML;
4829 + var _navItem = jQuery(navItem);
4830 +
4831 + // If is not mega menu
4832 + if('menu_type' in tmp && tmp['menu_type'] != 'mega'){
4833 + _navItem.find('.pagelayer-menu-item-holder').empty();
4834 + }
4835 +
4836 + content = pagelayer_generate_sc(_navItem, true);
4837 + content = pagelayer_Base64.encode(content);
4838 +
4839 + // Send data to save
4840 + var allowed_post = ['title'];
4841 +
4842 + for(var key in allowed_post){
4843 +
4844 + var post_prop = allowed_post[key];
4845 +
4846 + if(!(post_prop in tmp)){
4847 + continue;
4848 + }
4849 +
4850 + pagelayer_nav_items[postID][post_prop] = tmp[post_prop]
4851 + }
4852 +
4853 + }else{
4854 + pagelayer_nav_items[postID] = tmp;
4855 + }
4856 +
4857 + // Delete the html content
4858 + delete tmp['pagelayer_content'];
4859 +
4860 + pagelayer_nav_items[postID]['_pagelayer_content'] = content;
4861 +
4862 + });
4863 +
4864 + return pagelayer_nav_items;
4865 +}
4866 +
4867 +// Save data or meta of the nav post
4868 +function pagelayer_update_nav_menu_data(){
4869 +
4870 + var tag = 'pl_wp_menu';
4871 +
4872 + pagelayer_ajax_post_data['pagelayer_nav_items'] = {};
4873 +
4874 + jQuery(pagelayer_editable+' [pagelayer-tag="'+tag+'"]').each(function(){
4875 +
4876 + var jEle = jQuery(this);
4877 + var menu_ID = pagelayer_get_att(jEle, 'nav_list');
4878 +
4879 + if(!pagelayer_empty(pagelayer_ajax_post_data['pagelayer_nav_items'][menu_ID])){
4880 + return;
4881 + }
4882 +
4883 + // Get the Current menu items
4884 + var items = pagelayer_get_nav_items(jEle, true);
4885 +
4886 + if(pagelayer_empty(items)){
4887 + return;
4888 + }
4889 +
4890 + pagelayer_ajax_post_data['pagelayer_nav_items'][menu_ID] = items;
4891 +
4892 + });
4893 +}
4894 +
4895 +// Save the customizer settings
4896 +function pagelayer_update_customizer_settings(){
4897 +
4898 + var tag = 'pl_customizer';
4899 + var jEle = jQuery(pagelayer_editable+' [pagelayer-tag="'+tag+'"]');
4900 +
4901 + if(jEle.length < 1){
4902 + return;
4903 + }
4904 +
4905 + var tmp = pagelayer_data(jEle, true);
4906 + pagelayer_ajax_post_data['pagelayer_customizer_options'] = JSON.stringify(tmp['atts']);
4907 +
4908 +}
4909 +
2601 4910 // Save the post
2602 4911 function pagelayer_save(){
2603 4912
4913 + // hiding and showing loading animation
4914 + pagelayer.$$('.pagelayer-update-text').hide();
4915 + pagelayer.$$('.pagelayer-update-loader').show();
4916 +
2604 4917 pagelayer_trigger_action('pagelayer_save');
2605 4918
2606 4919 var pagelayerajaxurl = pagelayer_ajax_url+'&action=pagelayer_save_content&postID='+pagelayer_postID;
2607 4920 var post = pagelayer_generate_sc(pagelayer_editable);//alert(post);return;
2608 4921
2609 - // Do we have page properties ?
2610 - var jEle = jQuery(pagelayer_editable+' [pagelayer-tag=pl_post_props]');
2611 - var props = {};
2612 - if(jEle.length > 0){
2613 - var tmp = pagelayer_data(jEle);
2614 - //console.log(props);
2615 - props = tmp.atts;
4922 + // Update data or meta of the post
4923 + pagelayer_update_post_data();
4924 +
4925 + // Update Customizer Settings
4926 + pagelayer_update_customizer_settings();
4927 +
4928 + // Update nav menu
4929 + pagelayer_update_nav_menu_data();
4930 +
4931 + if(pagelayer_empty(pagelayer.post_status) && !pagelayer_empty(pagelayer_ajax_post_data['post_status'])){
4932 + pagelayer.post_status = pagelayer_ajax_post_data['post_status'];
2616 4933 }
4934 +
4935 + // Do we have contact templates ?
4936 + var contacts_props = pagelayer_get_contact_templates();
2617 4937
2618 - jQuery.ajax({
2619 - type: "POST",
2620 - url: pagelayerajaxurl,
2621 - data: {
2622 - pagelayer_update_content : post,
4938 + // Do we have any global widget to save ?
4939 + var global_data = {};
4940 +
4941 + if(!pagelayer_empty(pagelayer_global_widgets)){
4942 + global_data = pagelayer_generate_sc_global_widget();
4943 + }
4944 +
4945 + var cancel = function(){
4946 + pagelayer.$$('.pagelayer-update-text').show();
4947 + pagelayer.$$('.pagelayer-update-loader').hide();
4948 + }
4949 +
4950 + var save = function(){
4951 + var post_data = {
4952 + pagelayer_update_content : pagelayer_Base64.encode(post),
2623 4953 pagelayer_nonce: pagelayer_ajax_nonce,
2624 - page_props: props
2625 - },
2626 - success: function(response, status, xhr){
2627 - //alert(data);
2628 - var obj = jQuery.parseJSON(response);
2629 - //alert(obj);
2630 - if(obj['error']){
2631 - alert(obj['error']);
2632 - }else{
2633 - pagelayer_isDirty = false;
2634 - alert(obj['success']);
2635 - pagelayer_get_revision();
4954 + global_widgets: global_data,
4955 + contacts: contacts_props,
4956 + post_status: pagelayer.post_status,
4957 + copyright: pagelayer_copyright
4958 + }
4959 +
4960 + if(!pagelayer_empty(pagelayer.cmode)){
4961 + post_data.cmode = pagelayer.cmode;
4962 + }
4963 +
4964 + post_data = Object.assign(pagelayer_ajax_post_data, post_data);
4965 +
4966 + jQuery.ajax({
4967 + type: "POST",
4968 + url: pagelayerajaxurl,
4969 + data: post_data,
4970 + success: function(response, status, xhr){
4971 + //alert(data);
4972 + var obj = jQuery.parseJSON(response);
4973 + //alert(obj);
4974 +
4975 + if('comment_alerts' in obj){
4976 + console.log("Alerts:", obj['comment_alerts']);
4977 + }
4978 +
4979 + if(obj['error']){
4980 + pagelayer_show_msg(obj['error'], 'error', 10000);
4981 + if('comment_errors' in obj){
4982 + console.log("Errors:", obj['comment_errors']);
4983 + }
4984 + }else{
4985 + pagelayer_show_msg(obj['success'], 'success', 10000);
4986 + pagelayer_get_revision();
4987 +
4988 + // Update the post status in the post_props, but first find if its actually there !
4989 + var jEle = jQuery(pagelayer_editable).find("[pagelayer-tag=pl_post_props]");
4990 + if(jEle.length > 0){
4991 + var id = pagelayer_id(jEle);
4992 + pagelayer_set_atts(jEle, 'post_status', obj['post_status']);
4993 + pagelayer_trigger_action('pagelayer_save_success', obj['post_status']);
4994 + }
4995 +
4996 + pagelayer_do_undirty();
4997 + }
4998 + },
4999 + error: function(jqXHR, textStatus, errorThrown){
5000 + console.log(errorThrown);
5001 + pagelayer_show_msg('An error occured while saving ! Status : '+textStatus+' and Error : '+errorThrown, 'error', 10000);
5002 + },
5003 + complete: function(xhr,status){
5004 + pagelayer.$$('.pagelayer-update-text').show();
5005 + pagelayer.$$('.pagelayer-update-loader').hide();
5006 +
5007 + if(!pagelayer_empty(pagelayer.post_status)){
5008 + pagelayer.$$('.pagelayer-props-modal .pagelayer-meta-iframe').attr('src', pagelayer_post_props );
5009 + pagelayer.post_status = '';
5010 + }
2636 5011 }
2637 - },
2638 - error: function(errorThrown){
2639 - console.log(errorThrown);
2640 - }
2641 - });
5012 + });
5013 + }
2642 5014
5015 + // If the content is empty
5016 + if(pagelayer_empty(post)){
5017 + pagelayer_confirmation_box(pagelayer_l('empty_post_content'), save, cancel);
5018 + return;
5019 + }
5020 +
5021 + save();
2643 5022 };
2644 5023
2645 5024 //Close the Editor
2646 5025 function pagelayer_close(){
@@ -2653,18 +5032,30 @@
2653 5032 }else{
2654 5033 window.top.location.href = pagelayer_returnURL;
2655 5034 }
2656 5035 };
5036 +
5037 +function pagelayer_htmlEntities(str) {
5038 + return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
5039 +}
2657 5040
2658 -// Generate Shortcode Post to save
2659 -function pagelayer_generate_sc(selector){
5041 +function pagelayer_serializeAttributes(attributes) {
5042 + return JSON.stringify(attributes) // Don't break HTML comments.
5043 + .replace(/--/g, "\\u002d\\u002d") // Don't break non-standard-compliant tools.
5044 + .replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026") // Bypass server stripslashes behavior which would unescape stringify's
5045 + // escaping of quotation mark.
5046 + // See: https://developer.wordpress.org/reference/functions/wp_kses_stripslashes/
5047 + .replace(/\\"/g, "\\u0022");
5048 +}
5049 +
5050 +// Generate blocks Post to save
5051 +function pagelayer_generate_sc(selector, selfEle){
2660 5052
5053 + selfEle = selfEle || false;
2661 5054 var txt = '';
2662 5055
2663 - jQuery(selector).children(".pagelayer-ele-wrap").each(function(){
5056 + var generate_sc_single = function(jEle){
2664 5057
2665 - var jEle = jQuery(this).children('.pagelayer-ele');
2666 -
2667 5058 // The ID
2668 5059 var id = jEle.attr('pagelayer-id');
2669 5060
2670 5061 // If there is an Add element wrapper
@@ -2674,14 +5065,26 @@
2674 5065
2675 5066 // Find the type of tag
2676 5067 var tag = jEle.attr('pagelayer-tag');
2677 5068 var final_tag = tag;
2678 - var closestEle = jQuery(this).closest('.pagelayer-col-holder');
5069 + var closestEle = jEle.closest('.pagelayer-col-holder');
2679 5070
5071 + // Skip to create shortcode to prevent save, allowed by tag
5072 + if('skip_save' in pagelayer_shortcodes[tag] && !pagelayer_empty(pagelayer_shortcodes[tag]['skip_save'])){
5073 + return;
5074 + }
5075 +
2680 5076 // Define inner row | Note : Commented as we now have a new widget of type inner_row
2681 5077 /*if(tag == 'pl_row' && closestEle.length > 0 && closestEle.closest(pagelayer_editable).length > 0){
2682 5078 final_tag = 'pl_inner_row';
2683 5079 }*/
5080 +
5081 + if(pagelayer_empty(tag)){
5082 + var err = 'Found an error in the content as the TAG was missing. The console will have more details.';
5083 + pagelayer_show_msg(err, 'error');
5084 + console.log(err);
5085 + console.log(jEle);
5086 + }
2684 5087
2685 5088 // Define inner column
2686 5089 if(tag == 'pl_col' && closestEle.length > 0 && closestEle.closest(pagelayer_editable).length > 0){
2687 5090 final_tag = 'pl_inner_col';
@@ -2693,44 +5096,33 @@
2693 5096 if('innerHTML' in pagelayer_shortcodes[tag]){
2694 5097 inner = pagelayer_shortcodes[tag]['innerHTML'];
2695 5098 }
2696 5099
5100 + // Data reference
5101 + var ref_data = pagelayer_el_data_ref(jEle);
5102 +
2697 5103 // Create the tag
2698 - var data = '['+final_tag;
5104 + var data = JSON.parse(JSON.stringify(ref_data['attr']));
2699 5105
2700 - // Get the attributes to store
2701 - jQuery.each(jEle[0].attributes, function(i, attrib){
2702 - var res = attrib.name.match(/^pagelayer-a-(.+)/i);
2703 - if(res && res[1] != inner){
2704 - //console.log(attrib.name+' '+res[1]);
2705 - data += ' '+res[1]+'="'+pagelayer_escapeHTML(attrib.value)+'"';
2706 - }
2707 - });
5106 + data['pagelayer-id'] = id;
5107 + data = pagelayer_serializeAttributes(data);
5108 +
5109 + var content = '';
2708 5110
2709 - data = data+']';
2710 -
2711 - // Add to the text
2712 - txt = txt+data+"\n";
2713 -
2714 5111 // Any internal function to handle the save ?
2715 5112 var func = window['pagelayer_tag_'+tag];
2716 5113 if(typeof func == 'function'){
2717 5114
2718 - var content = '';
2719 5115 content = func(jEle);
2720 5116
2721 - if(content.length > 0){
2722 - txt = txt+content;
2723 - }
2724 -
2725 5117 // If its a Row or Column or Group then it will have children
2726 5118 }else if(jEle.hasClass('pagelayer-row') || jEle.hasClass('pagelayer-col') || jEle.hasClass('pagelayer-inner_row') || pagelayer_is_group(tag)){
2727 5119
2728 - var sel = "[pagelayer-id="+id+"]";
5120 + var sel = jEle;
2729 5121
2730 5122 // Any holder which holds children ?
2731 5123 if('holder' in pagelayer_shortcodes[tag]){
2732 - sel = sel+' '+pagelayer_shortcodes[tag]['holder'];
5124 + sel = jEle.find(pagelayer_shortcodes[tag]['holder']);
2733 5125 }
2734 5126
2735 5127 // Select the top-most element
2736 5128 sel = jQuery(sel).first();
@@ -2738,22 +5130,27 @@
2738 5130 // Any child selector - Majorly for owl carousel
2739 5131 // NOTE : Child selector should be very specific with immediate child selection at all levels
2740 5132 var child_selector = false;
2741 5133 if('child_selector' in pagelayer_shortcodes[tag]){
2742 - sel = sel.find(pagelayer_shortcodes[tag]['child_selector']);
5134 + childSel = sel.find(pagelayer_shortcodes[tag]['child_selector']);
5135 +
5136 + if(childSel.length > 0){
5137 + sel = childSel;
5138 + }
2743 5139 }
2744 -
2745 - var childrens = pagelayer_generate_sc(sel);
2746 - if(childrens.length > 0){
2747 - txt = txt+childrens;
5140 +
5141 + if(jQuery(sel).children(".pagelayer-ele-wrap").length < 1){
5142 + content = jQuery(sel).html(); // Backward Compatibility
5143 + }else{
5144 + content = pagelayer_generate_sc(sel);
5145 + content = "\n"+content;
2748 5146 }
2749 5147
2750 5148 // Its a normal element so we might need to handle the content
2751 5149 }else{
2752 5150
2753 - var content = '';
2754 5151 if(inner.length > 0){
2755 - content = jEle.attr('pagelayer-a-'+inner);
5152 + content = pagelayer_get_att(jEle, inner);
2756 5153 if(!content){
2757 5154 content = '';
2758 5155 }
2759 5156 }else{
@@ -2759,74 +5156,45 @@
2759 5156 }else{
2760 5157 content = '';//jEle.html();
2761 5158 }
2762 5159
2763 - if(content.length > 0){
2764 - txt = txt+content;
2765 - }
2766 -
2767 5160 }
2768 5161
2769 - // Close the tag
2770 - txt = txt+"[/"+final_tag+"]\n";
5162 + // Leaving HTML and non-pagelayer supported content intact
5163 + if(final_tag == 'pl_missing'){
5164 + txt += content;
5165 + return;
5166 + }
2771 5167
2772 - });
5168 + if (pagelayer_empty(content)) {
5169 + txt += "<!-- ".concat(pagelayer_block_prefix, ":pagelayer/").concat(final_tag, " ").concat(data, " /-->\n");
5170 + }else{
5171 + txt += "<!-- ".concat(pagelayer_block_prefix, ":pagelayer/").concat(final_tag, " ").concat(data, " -->").concat(content, "<!-- /").concat(pagelayer_block_prefix, ":pagelayer/").concat(final_tag, " -->\n");
5172 + }
5173 +
5174 + };
2773 5175
5176 + // Are you an element for which to generate the codes ?
5177 + if(jQuery(selector).hasClass('pagelayer-ele') && selfEle){
5178 +
5179 + generate_sc_single(jQuery(selector));
5180 +
5181 + // The selector is the holder, so loop thru
5182 + }else{
5183 +
5184 + jQuery(selector).children(".pagelayer-ele-wrap").each(function(){
5185 +
5186 + var jEle = jQuery(this).children('.pagelayer-ele');
5187 + generate_sc_single(jEle);
5188 +
5189 + });
5190 +
5191 + }
5192 +
2774 5193 return txt;
2775 5194
2776 5195 };
2777 5196
2778 -// Escape charaters in attributes
2779 -var pagelayer_escapeChars = {
2780 - '\\]' : '#93',
2781 - '\\[' : '#91',
2782 - //'=' : '#61',
2783 - '<' : 'lt',
2784 - '>' : 'gt',
2785 - '"' : 'quot',
2786 - //'&' : 'amp',
2787 - '\'' : '#39'
2788 -};
2789 -
2790 -// To unescape
2791 -var pagelayer_unescapeChars = {
2792 - '#93' : ']',
2793 - '#91' : '[',
2794 - //'#61' : '=',
2795 - 'lt' : '<',
2796 - 'gt' : '>',
2797 - 'quot' : '"',
2798 - //'amp' : '&',
2799 - '#39' : '\''
2800 -};
2801 -
2802 -var pagelayer_escaperegex_S = '[';
2803 -for(var key in pagelayer_escapeChars) {
2804 - pagelayer_escaperegex_S += key;
2805 -}
2806 -pagelayer_escaperegex_S += ']';
2807 -
2808 -var pagelayer_escaperegex = new RegExp( pagelayer_escaperegex_S, 'g');
2809 -
2810 -// The function which escapes everything
2811 -function pagelayer_escapeHTML(str) {
2812 - return str.replace(pagelayer_escaperegex, function(m) {
2813 - if(m == '[' || m == ']') m = '\\'+m;
2814 - return '&' + pagelayer_escapeChars[m] + ';';
2815 - });
2816 -};
2817 -
2818 -// This will unescape everything
2819 -function pagelayer_unescapeHTML(str){
2820 - return str.replace(/\&([^;]+);/g, function (entity, entityCode) {
2821 - if(entityCode in pagelayer_unescapeChars){
2822 - return pagelayer_unescapeChars[entityCode];
2823 - }else{
2824 - return entity;
2825 - }
2826 - });
2827 -};
2828 -
2829 5197 // Show the required leftbar tab
2830 5198 function pagelayer_leftbar_tab(tab){
2831 5199 pagelayer.$$('.pagelayer-leftbar-tab').hide();
2832 5200 pagelayer.$$('#'+tab).show();
@@ -2853,17 +5221,27 @@
2853 5221
2854 5222 var html = '<div class="pagelayer-leftbar">'+
2855 5223 '<div class="pagelayer-leftbar-scroll">'+
2856 5224 '<div id="pagelayer-shortcodes" class="pagelayer-leftbar-tab pagelayer-shortcodes">'+
2857 - '<div class="pagelayer-leftbar-search">'+
2858 - '<i class="pli pli-search" /><input class="pagelayer-search-field" /><i class="pagelayer-sf-empty pli">&times;</i>'+
2859 - '</div>';
5225 + '<div class="pagelayer-widget-tabs">'+
5226 + '<div class="pagelayer-widget-tab" pagelayer-widget-tab="widgets" pagelayer-elpd-active-tab=1>Widgets</div>'+
5227 + '<div class="pagelayer-widget-tab pagelayer-settings" pagelayer-widget-tab="settings">Settings</div>'+
5228 + '<div class="pagelayer-widget-tab" pagelayer-widget-tab="global">Globals</div>'+
5229 + '</div>'+
5230 + '<div class="pagelayer-shortcodes-widget">'+
5231 + '<div class="pagelayer-leftbar-search">'+
5232 + '<i class="pli pli-search" ></i><input class="pagelayer-search-field" placeholder="Search Widget..." /><span class="pagelayer-sf-empty pli">&times;</span>'+
5233 + '</div>';
2860 5234
2861 5235 for(var x in pagelayer_groups){
2862 5236
2863 5237 // Title
2864 - html += '<div class="pagelayer-leftbar-group"><h5>'+x+'</h5>';
5238 + var group_title = x;
5239 + if (x === 'Basic') group_title = 'Atomic Elements';
5240 + else if (x === 'Common') group_title = 'General';
2865 5241
5242 + html += '<div class="pagelayer-leftbar-group pagelayer-group-name-'+x+'"><h5>'+group_title+'</h5>';
5243 +
2866 5244 // Indivdual icon
2867 5245 for(var y in pagelayer_groups[x]){
2868 5246
2869 5247 var sc = pagelayer_groups[x][y];
@@ -2893,13 +5271,16 @@
2893 5271
2894 5272 }
2895 5273
2896 5274 html += '</div>'+
5275 + '<div id="pagelayer-global-widget" class="pagelayer-hidden pagelayer-global-widget"></div>'+
5276 + '</div>'+
2897 5277 '<div id="pagelayer-elpd" class="pagelayer-leftbar-tab pagelayer-elpd"></div>'+
2898 5278 '<div id="pagelayer-options" class="pagelayer-leftbar-tab pagelayer-options"></div>'+
2899 5279 '<div id="pagelayer-history" class="pagelayer-leftbar-tab pagelayer-history"></div>'+
2900 5280 '<div id="pagelayer-post-settings" class="pagelayer-leftbar-tab pagelayer-post-settings"></div>'+
2901 5281 '<div id="pagelayer-navigator" class="pagelayer-leftbar-tab pagelayer-navigator"></div>'+
5282 + '<div id="pagelayer-general-options" class="pagelayer-leftbar-tab pagelayer-general-options"></div>'+
2902 5283 '</div>'+
2903 5284 '</div>';
2904 5285
2905 5286 pagelayer.$$('.pagelayer-leftbar-holder').prepend(html);
@@ -2948,30 +5329,153 @@
2948 5329 });
2949 5330 });
2950 5331
2951 5332 // On click Pagelayer setting icon
2952 - pagelayer.$$('.pagelayer-settings-icon').click(function(event){
2953 - pagelayer.$$('.pagelayer-elpd-header').show().find('.pagelayer-elpd-title').text('Post Settings');
2954 - pagelayer.$$('.pagelayer-logo').hide();
2955 - pagelayer_leftbar_tab('pagelayer-post-settings');
5333 + pagelayer.$$('.pagelayer-settings-icon, .pagelayer-settings').click(function(event){
2956 5334 pagelayer_active = {};
2957 5335
2958 5336 var pl_tag = jQuery(this).attr('pagelayer-tag') || 'pl_post_props';
5337 + var nModal = jQuery(this).attr('pagelayer-modal-none');
5338 +
2959 5339 pagelayer_post_settings(pl_tag);
5340 +
2960 5341 });
2961 5342
5343 + // Pagelayer post advance setting modal handler
5344 + var propsModal = pagelayer.$$('.pagelayer-props-modal');
5345 + propsModal.find('.pagelayer-props-modal-close').on('click', function(event){
5346 + propsModal.hide();
5347 + });
5348 +
5349 + propsModal.on('click', function(event){
5350 + var target = jQuery(event.target);
5351 +
5352 + if(target.closest('.pagelayer-props-modal-wrap').length > 0){
5353 + return;
5354 + }
5355 +
5356 + propsModal.hide();
5357 + });
5358 +
5359 +
5360 + // On click Pagelayer setting icon
5361 + var global_widget_list = function(){
5362 +
5363 + var gHtml = '';
5364 +
5365 + if(pagelayer_empty(pagelayer_pro)){
5366 + gHtml += '<div class="pagelayer-global-widget-pro">'+pagelayer.pro_txt+
5367 + '<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>'+
5368 + '</div>';
5369 +
5370 + pagelayer.$$('#pagelayer-global-widget').html(gHtml);
5371 + return;
5372 + }
5373 +
5374 + gHtml += '<div class="pagelayer-global-widget-shortcodes">'+
5375 + '<div class="pagelayer-leftbar-search">'+
5376 + '<i class="pli pli-search" ></i><input class="pagelayer-search-field" /><i class="pagelayer-sf-empty pli">&times;</i>'+
5377 + '</div>'+
5378 + '<div class="pagelayer-leftbar-group"><h5>'+pagelayer_l('global_widgets')+'</h5></div>'+
5379 + '</div>';
5380 +
5381 + if(pagelayer_empty(pagelayer_global_widgets)){
5382 + pagelayer_global_widgets = [];
5383 + gHtml += '<div class="pagelayer-leftbar-group"><h5>No global widgets found</h5></div>';
5384 + }
5385 +
5386 + // Indivdual icon
5387 + for(var y in pagelayer_global_widgets){
5388 + var wEle = jQuery(pagelayer_global_widgets[y]['$']);
5389 + var sc = pagelayer_tag( wEle );
5390 +
5391 + if(!(sc in pagelayer_shortcodes) || 'not_visible' in pagelayer_shortcodes[sc]){
5392 + continue;
5393 + }
5394 +
5395 + gHtml += '<div class="pagelayer-shortcode-drag" draggable="true" pagelayer-tag="'+sc+'" pagelayer-global-id="'+y+'">'+
5396 + '<div class="pagelayer-sc">'+
5397 + '<center class="pagelayer-shortcode-inner">';
5398 +
5399 + if('icon' in pagelayer_shortcodes[sc]){
5400 + gHtml += '<i class="pagelayer-shortcode '+pagelayer_shortcodes[sc]['icon']+'"></i>';
5401 + }else{
5402 + gHtml += '<i class="pagelayer-shortcode pli pagelayer-'+sc+'"></i>';
5403 + }
5404 +
5405 + gHtml += '</center>'+
5406 + '<span class="pagelayer-shortcode-text">'+pagelayer_global_widgets[y]['title']+'</span>'+
5407 + '</div>'+
5408 + '</div>';
5409 +
5410 + }
5411 +
5412 + pagelayer.$$('#pagelayer-global-widget').html(gHtml);
5413 + };
5414 +
5415 + // The widget tabs
5416 + pagelayer.$$('.pagelayer-widget-tab').on('click', function(){
5417 + var attr = 'pagelayer-elpd-active-tab';
5418 + pagelayer.$$('.pagelayer-widget-tab').each(function(){
5419 + jQuery(this).removeAttr(attr);
5420 + });
5421 + var cEle = jQuery(this);
5422 + cEle.attr(attr, 1);
5423 +
5424 + if(cEle.attr('pagelayer-widget-tab') == 'global'){
5425 + cEle.closest('#pagelayer-shortcodes').find('.pagelayer-shortcodes-widget').addClass('pagelayer-hidden');
5426 + cEle.closest('#pagelayer-shortcodes').find('.pagelayer-global-widget').removeClass('pagelayer-hidden');
5427 + // Trigger create global widgets
5428 + global_widget_list();
5429 + }else{
5430 + cEle.closest('#pagelayer-shortcodes').find('.pagelayer-shortcodes-widget').removeClass('pagelayer-hidden');
5431 + cEle.closest('#pagelayer-shortcodes').find('.pagelayer-global-widget').addClass('pagelayer-hidden');
5432 + }
5433 + });
5434 +
2962 5435 // On click search empty
2963 5436 pagelayer.$$('.pagelayer-leftbar-search>.pagelayer-sf-empty').click(function(){
2964 5437 pagelayer.$$('.pagelayer-search-field').val('').trigger('input');
2965 5438 });
2966 5439
5440 + // Pagelayer General options
5441 + pagelayer.$$('.pagelayer-options-icon ').click(function(){
5442 + pagelayer.$$('.pagelayer-elpd-header').show().find('.pagelayer-elpd-title').text(pagelayer_l('general_options'));
5443 + pagelayer.$$('.pagelayer-logo').hide();
5444 +
5445 + // Setup General options
5446 + pagelayer_setup_general_options();
5447 +
5448 + pagelayer_leftbar_tab('pagelayer-general-options');
5449 + pagelayer_active = {};
5450 + });
5451 +
5452 + // Hide color and typography global list
5453 + pagelayer.$$('.pagelayer-leftbar-table').on('click', function(e){
5454 +
5455 + var closest = jQuery(e.target).closest('.pagelayer-elp-color-global, .pagelayer-elp-global-icon, .pagelayer-global-color-list, .pagelayer-global-font-list');
5456 + var list = pagelayer.$$('.pagelayer-global-color-list, .pagelayer-global-font-list');
5457 +
5458 + if(closest.length > 0 ){
5459 + var lEle = closest.closest('.pagelayer-elp-color-div-holder').find('.pagelayer-global-color-list');
5460 + var lFont = closest.closest('.pagelayer-form-item').find('.pagelayer-global-font-list');
5461 +
5462 + list = list.not(lFont);
5463 + list = list.not(lEle);
5464 + }
5465 +
5466 + list.not(closest).slideUp();
5467 +
5468 + });
2967 5469 };
2968 5470
2969 5471 // Post setting holder
2970 -function pagelayer_post_settings(pl_tag){
5472 +function pagelayer_post_settings(pl_tag, to_click){
2971 5473
5474 + to_click = to_click == -1 ? false : true;
5475 +
2972 5476 // Is there a post settings ?
2973 - var jEle = jQuery(pagelayer_editable+' [pagelayer-tag='+ pl_tag +']');
5477 + var jEle = jQuery(pagelayer_editable+' [pagelayer-tag="'+ pl_tag +'"]');
2974 5478
2975 5479 // Could not find
2976 5480 if(jEle.length < 1){
2977 5481 jEle = pagelayer_create_sc(pl_tag);
@@ -2977,13 +5481,18 @@
2977 5481 jEle = pagelayer_create_sc(pl_tag);
2978 5482 var id = pagelayer_id(jEle);
2979 5483 jQuery(pagelayer_editable).prepend(jEle);
2980 5484 pagelayer_element_setup('[pagelayer-id='+id+']', true);
5485 +
5486 + // Dont mark as dirty as post_props is not editing anything
5487 + pagelayer_do_undirty();
2981 5488 }
2982 5489
2983 - jEle.click();
5490 + if(to_click){
5491 + jEle.click();
5492 + }
2984 5493
2985 - return;
5494 + return jEle;
2986 5495 }
2987 5496
2988 5497 // Get the closest element and method
2989 5498 function pagelayer_near_by_ele(id, sc){
@@ -3009,9 +5518,9 @@
3009 5518 var pEle_id = pagelayer_id(jQuery('[pagelayer-wrap-id="'+id+'"]').closest('.pagelayer-ele'));
3010 5519
3011 5520 // Get the parent element tag
3012 5521 var pEle_tag = pagelayer_tag(jQuery('[pagelayer-id="'+pEle_id+'"]'));
3013 - var holder = pagelayer_shortcodes[pEle_tag]['holder'] || '';
5522 + var holder = '>'+ pagelayer_shortcodes[pEle_tag]['holder'] || '';
3014 5523 args = {'method' : 'prepend', 'cEle' : '[pagelayer-id="'+pEle_id+'"] '+ holder+' '};
3015 5524
3016 5525 }
3017 5526
@@ -3023,8 +5532,9 @@
3023 5532
3024 5533 // Push the action data in the pagelayer_history_obj object
3025 5534 function pagelayer_history_action_push(args){
3026 5535
5536 + var currentTime = new Date();
3027 5537 var history_obj_len = pagelayer_history_obj['action_data'].length;
3028 5538
3029 5539 // If the history_obj_len is less then 1 then set the data in array 0 position
3030 5540 if(history_obj_len < 1){
@@ -3034,8 +5544,9 @@
3034 5544
3035 5545 // Remove the second array element if the history_obj_len greater then 100
3036 5546 if(history_obj_len > 100){
3037 5547 pagelayer_history_obj['action_data'].splice(1, 1);
5548 + pagelayer_history_obj['current_active_item_id'] = pagelayer_history_obj['action_data'].length - 1;
3038 5549 }
3039 5550
3040 5551 // Get current active history action id
3041 5552 var action_id = parseInt(pagelayer_history_obj['current_active_item_id']) || 0;
@@ -3044,22 +5555,45 @@
3044 5555 var del_ele = history_obj_len - action_id - 1;
3045 5556 pagelayer_history_obj['action_data'].splice(action_id + 1, del_ele);
3046 5557
3047 5558 // Check if the same attr set as current active history
3048 - if(args.action == "Edited" && history_obj_len > 1){
5559 + if(args.action == "Edited" && history_obj_len > 1 && currentTime - pagelayer.history_lastTime < 1000){
3049 5560 var atts = pagelayer_history_obj['action_data'][action_id] || '';
3050 - if(atts['atts'] == args['atts']){
5561 + if(atts['atts'] == args['atts'] && atts['pl_id'] == args['pl_id'] && pagelayer_empty(atts['sub_actions_group']) ){
3051 5562 args['oldVal'] = atts['oldVal'];
3052 5563 pagelayer_history_obj['action_data'][action_id] = args;
3053 5564 pagelayer_history_setup();
5565 +
5566 + // Set the last history time
5567 + pagelayer.history_lastTime = currentTime;
3054 5568 return true;
3055 5569 }
3056 5570 }
3057 -
5571 +
5572 + // If the action time within 200 millisecond then it count as sub-actions
5573 + if(currentTime - pagelayer.history_lastTime < 200 && history_obj_len > 1){
5574 +
5575 + var cur_action_data = pagelayer_history_obj['action_data'][action_id];
5576 + var sub_actions_len = cur_action_data['sub_actions_group'] || '';
5577 +
5578 + if( !('attrType' in cur_action_data && cur_action_data['attrType'] == 'tmp_attr' && 'attrType' in args && args['attrType'] == 'a_attr') ) {
5579 + // If the sub_actions_len is less then 1 then set the data in array 0 position
5580 + if(sub_actions_len.length < 1){
5581 + pagelayer_history_obj['action_data'][action_id]['sub_actions_group'] = [args];
5582 + }else{
5583 + pagelayer_history_obj['action_data'][action_id]['sub_actions_group'].push(args);
5584 + }
5585 +
5586 + return true;
5587 + }
5588 + }
5589 +
3058 5590 pagelayer_history_obj['action_data'].push(args);
3059 5591 pagelayer_history_obj['current_active_item_id'] = pagelayer_history_obj['action_data'].length - 1;
3060 5592 pagelayer_history_setup();
3061 5593
5594 + // Set the last history time
5595 + pagelayer.history_lastTime = currentTime;
3062 5596 }
3063 5597
3064 5598 // Setup pagelayer history
3065 5599 function pagelayer_history_setup(force){
@@ -3176,14 +5710,45 @@
3176 5710 success: function(response, status, xhr){
3177 5711
3178 5712 var obj = jQuery.parseJSON(response);
3179 5713 if(obj['error']){
3180 - alert(obj['error']);
5714 + pagelayer_show_msg(obj['error'] , 'error');
3181 5715 }else{
5716 +
5717 + // Get the current post_name and post_status
5718 + var props = jQuery(pagelayer_editable).find('.pagelayer-post_props');
5719 + var post_name = '', post_status = '';
5720 +
5721 + if(props.length > 0){
5722 + post_name = pagelayer_get_att(props, 'post_name');
5723 + post_status = pagelayer_get_att(props, 'post_status');
5724 + }
5725 +
5726 + // Set content
3182 5727 jQuery(pagelayer_editable).html(obj['content']);
3183 - alert(obj['success']);
3184 - pagelayer_element_setup();
5728 +
5729 + // Add previous post_name and post_status
5730 + var props_new = jQuery(pagelayer_editable).find('.pagelayer-post_props');
5731 + if(props_new.length > 0){
5732 +
5733 + if(pagelayer_empty(post_name)){
5734 + post_name = pagelayer_default_params.pl_post_props.post_name;
5735 + }
5736 +
5737 + if(pagelayer_empty(post_status)){
5738 + post_status = pagelayer_default_params.pl_post_props.post_status;
5739 + }
5740 +
5741 + var tmp = {};
5742 + tmp['post_name'] = post_name;
5743 + tmp['post_status'] = post_status;
5744 + pagelayer_set_atts(props_new, tmp);
5745 + }
5746 +
5747 + // Need to pass true to render table
5748 + pagelayer_element_setup('.pagelayer-ele', true);
3185 5749 pagelayer_add_widget();
5750 + pagelayer_show_msg(obj['success'], 'success');
3186 5751 }
3187 5752 }
3188 5753 });
3189 5754 });
@@ -3203,11 +5768,11 @@
3203 5768 success: function(response, status, xhr){
3204 5769
3205 5770 var obj = jQuery.parseJSON(response);
3206 5771 if(obj['error']){
3207 - alert(obj['error']);
5772 + pagelayer_show_msg(obj['error'], 'error');
3208 5773 }else{
3209 - alert(obj['success']);
5774 + pagelayer_show_msg(obj['success'], 'success');
3210 5775 rEle.hide();
3211 5776 }
3212 5777
3213 5778 }
@@ -3240,9 +5805,9 @@
3240 5805 });
3241 5806 });
3242 5807 }
3243 5808
3244 -// Get evisions Handler
5809 +// Get revisions Handler
3245 5810 function pagelayer_get_revision(){
3246 5811
3247 5812 jQuery.ajax({
3248 5813 url: pagelayer_ajax_url+'&action=pagelayer_get_revision&postID='+pagelayer_postID,
@@ -3254,9 +5819,9 @@
3254 5819 success: function(response, status, xhr){
3255 5820 var obj = jQuery.parseJSON(response);
3256 5821
3257 5822 if(!pagelayer_empty(obj['error'])){
3258 - alert(obj['error']);
5823 + pagelayer_show_msg(obj['error'], 'error');
3259 5824 }else{
3260 5825 pagelayer_revision_obj = obj;
3261 5826 pagelayer_history_setup(true);
3262 5827 }
@@ -3335,9 +5900,13 @@
3335 5900 // Re-setup the element
3336 5901 var resetup_ele = function(history_array){
3337 5902 jQuery(history_array.cEle.cEle)[history_array.cEle.method](history_array.html);
3338 5903 pagelayer_element_setup('[pagelayer-id='+history_array.pl_id+'], [pagelayer-id='+history_array.pl_id+'] .pagelayer-ele', true);
3339 - pagelayer_empty_col(jQuery('[pagelayer-id="'+history_array.pl_id+'"]').closest('.pagelayer-col-holder'));
5904 +
5905 + var rEle = jQuery('[pagelayer-id="'+history_array.pl_id+'"]');
5906 + pagelayer_empty_col(rEle.closest('.pagelayer-col-holder'));
5907 +
5908 + pagelayer_do_dirty(rEle);
3340 5909 };
3341 5910
3342 5911 // Re-setup the element attr
3343 5912 var reset_ele_attr = function(hEle, atts, val, attrType){
@@ -3370,12 +5939,57 @@
3370 5939 if(!pagelayer_empty(pCol)){
3371 5940 pagelayer_empty_col(pCol);
3372 5941 pagelayer_empty_col(pagelayer_wrap_by_id(id).closest('.pagelayer-col-holder'));
3373 5942 }
3374 - }
5943 +
5944 + pagelayer_do_dirty(eWrap);
5945 + };
3375 5946
5947 + // Undo actions
5948 + var pagelayer_undo_action = function(history_array){
5949 + var action = history_array.action;
5950 + var id = history_array.pl_id;
5951 +
5952 + if(action == "Edited"){
5953 + hEle = jQuery('[pagelayer-id="'+id+'"]');
5954 + reset_ele_attr(hEle, history_array.atts, history_array.oldVal, history_array.attrType);
5955 + }else if(action == "Added"){
5956 + delete_ele(id);
5957 + }else if(action == "Deleted"){
5958 + resetup_ele(history_array);
5959 + }else if(action == "Copied"){
5960 + delete_ele(id);
5961 + }else if(action == "Moved"){
5962 + pagelayer_move_ele(id, history_array.before_loc);
5963 + }
5964 + };
5965 +
5966 + // Redo actions
5967 + var pagelayer_redo_action = function(history_array){
5968 + var action = history_array.action;
5969 + var id = history_array.pl_id;
5970 +
5971 + if(action == "Edited"){
5972 + hEle = jQuery('[pagelayer-id="'+id+'"]');
5973 + reset_ele_attr(hEle, history_array.atts, history_array.newVal, history_array.attrType);
5974 + }else if(action == "Added"){
5975 + resetup_ele(history_array);
5976 +
5977 + if(history_array.tag != "pl_row" && history_array.tag != "pl_col" ){
5978 + // Ensure the column is not empty
5979 + pagelayer_empty_col(history_array.cEle.cEle);
5980 + }
5981 + }else if(action == "Deleted"){
5982 + delete_ele(id);
5983 + }else if(action == "Copied"){
5984 + resetup_ele(history_array);
5985 + }else if(action == "Moved"){
5986 + pagelayer_move_ele(id, history_array.after_loc);
5987 + }
5988 + };
5989 +
3376 5990 if(prev_item_id > current_item_id){
3377 -
5991 +
3378 5992 // All Actions for undo here
3379 5993 var i = parseInt(prev_item_id);
3380 5994
3381 5995 for(i; i > current_item_id; i--){
@@ -3380,28 +5994,31 @@
3380 5994
3381 5995 for(i; i > current_item_id; i--){
3382 5996
3383 5997 var history_array = pagelayer_history_obj['action_data'][i];
3384 - var action = history_array.action;
3385 - var id = history_array.pl_id;
5998 + var sub_actions_group = history_array['sub_actions_group'] || '';
3386 5999
3387 - if(action == "Edited"){
3388 - hEle = jQuery('[pagelayer-id="'+id+'"]');
3389 - reset_ele_attr(hEle, history_array.atts, history_array.oldVal, history_array.attrType);
3390 - }else if(action == "Added"){
3391 - delete_ele(id);
3392 - }else if(action == "Deleted"){
3393 - resetup_ele(history_array);
3394 - }else if(action == "Copied"){
3395 - delete_ele(id);
3396 - }else if(action == "Moved"){
3397 - pagelayer_move_ele(id, history_array.before_loc);
6000 + // If it has sub-actions
6001 + if(!pagelayer_empty(sub_actions_group)){
6002 + var j = sub_actions_group.length;
6003 + for(j--; j >= 0; j--){
6004 + pagelayer_undo_action(sub_actions_group[j]);
6005 + }
3398 6006 }
3399 6007
6008 + // Main action
6009 + pagelayer_undo_action(history_array);
6010 +
6011 + // Activate the current element and scroll it into viewport
6012 + var jEle = jQuery('[pagelayer-id="'+history_array.pl_id+'"]');
6013 + if(jEle.length > 0){
6014 + pagelayer_set_active(jEle);
6015 + pagelayer_scroll_to_viewport(jEle, 0);
6016 + }
3400 6017 }
3401 6018
3402 6019 }else{
3403 -
6020 +
3404 6021 // All Actions for redo here
3405 6022 var i = parseInt(prev_item_id)+1;
3406 6023
3407 6024 for(i; i <= current_item_id; i++){
@@ -3406,29 +6023,25 @@
3406 6023
3407 6024 for(i; i <= current_item_id; i++){
3408 6025
3409 6026 var history_array = pagelayer_history_obj['action_data'][i];
3410 - var action = history_array.action;
3411 - var id = history_array.pl_id;
6027 + var sub_actions_group = history_array['sub_actions_group'] || '';
6028 + // Main action
6029 + pagelayer_redo_action(history_array);
3412 6030
3413 - if(action == "Edited"){
3414 - hEle = jQuery('[pagelayer-id="'+id+'"]');
3415 - reset_ele_attr(hEle, history_array.atts, history_array.newVal, history_array.attrType);
3416 - }else if(action == "Added"){
3417 - resetup_ele(history_array);
3418 -
3419 - if(history_array.tag != "pl_row" && history_array.tag != "pl_col" ){
3420 - // Ensure the column is not empty
3421 - pagelayer_empty_col(history_array.cEle.cEle);
6031 + // If it has sub-actions
6032 + if(!pagelayer_empty(sub_actions_group)){
6033 + for(var x in sub_actions_group){
6034 + pagelayer_redo_action(sub_actions_group[x]);
3422 6035 }
3423 - }else if(action == "Deleted"){
3424 - delete_ele(id);
3425 - }else if(action == "Copied"){
3426 - resetup_ele(history_array);
3427 - }else if(action == "Moved"){
3428 - pagelayer_move_ele(id, history_array.after_loc);
3429 6036 }
3430 6037
6038 + // Activate the current element and scroll it into viewport
6039 + var jEle = jQuery('[pagelayer-id="'+history_array.pl_id+'"]');
6040 + if(jEle.length > 0){
6041 + pagelayer_set_active(jEle);
6042 + pagelayer_scroll_to_viewport(jEle, 0);
6043 + }
3431 6044 }
3432 6045 }
3433 6046
3434 6047 };
@@ -3439,29 +6052,48 @@
3439 6052 alert(prefix+error);
3440 6053 };
3441 6054
3442 6055 function pagelayer_bottombar(){
3443 - var holder = pagelayer.$$('.pagelayer-bottombar-holder');
3444 - var html = '<div class="pagelayer-bottombar">'+
3445 - '<div class="pagelayer-bottombar-rightbuttons">'+
3446 - '<button data-tlite="Save Changes" class="pagelayer-update-button pagelayer-success-btn">Update</button>'+
3447 - '<button data-tlite="Close and Return to Admin Panel" class="pagelayer-close-button">Close</button>'+
3448 - '<div class="pagelayer-mode-wrapper">'+
3449 - '<div class="pagelayer-mode-buttons-wrapper">'+
3450 - '<i class="screen-mode pli pli-desktop" pagelayer-mode-data="desktop"></i>'+
3451 - '<i class="screen-mode pli pli-tablet" pagelayer-mode-data="tablet"></i>'+
3452 - '<i class="screen-mode pli pli-mobile" pagelayer-mode-data="mobile"></i>'+
3453 - '</div>'+
6056 + var holder = pagelayer.$$('.pagelayer-iframe-top-bar');
6057 + pagelayer.$$('.pagelayer-iframe-top-bar').show();
6058 +
6059 + // Get post title
6060 + var post_title = (typeof pagelayer_post !== 'undefined' && pagelayer_post.post_title) ? pagelayer_post.post_title : 'Page';
6061 +
6062 + var html = '<div class="pagelayer-top-header-bar">'+
6063 + '<div class="pagelayer-header-left">'+
6064 + '<span class="pagelayer-header-document-title">Editing: <span class="pagelayer-header-post-name">' + post_title + '</span></span>'+
6065 + '</div>'+
6066 + '<div class="pagelayer-header-center">'+
6067 + '<div class="pagelayer-device-selectors">'+
6068 + '<i class="screen-mode pli pli-desktop" pagelayer-mode-data="desktop" data-tlite="Desktop View"></i>'+
6069 + '<i class="screen-mode pli pli-tablet" pagelayer-mode-data="tablet" data-tlite="Tablet View"></i>'+
6070 + '<i class="screen-mode pli pli-mobile" pagelayer-mode-data="mobile" data-tlite="Mobile View"></i>'+
3454 6071 '</div>'+
3455 - '<i class="pagelayer-mode-button pli pli-desktop"></i>'+
3456 - '<span data-tlite="Preview Changes"><i class="pagelayer-preview pli pli-eye"></i></span>'+
3457 - '<span data-tlite="History and Revisions"><i class="pagelayer-history-icon pli pli-history"></i></span>'+
3458 - '<span data-tlite="navigator"><i class="pagelayer-navigator-icon pli pli-tree"></i></span>'+
3459 - //'<span data-tlite="Close and Return to Admin Panel"><i class="pagelayer-close-button fa fa-close"></i></span>'+
3460 6072 '</div>'+
6073 + '<div class="pagelayer-header-right">'+
6074 + '<span data-tlite="'+pagelayer_l('preview_changes')+'" class="pagelayer-header-icon-wrap"><i class="pagelayer-preview pli pli-eye"></i></span>'+
6075 + '<span data-tlite="'+pagelayer_l('historyand_revisions')+'" class="pagelayer-header-icon-wrap"><i class="pagelayer-history-icon pli pli-history"></i></span>'+
6076 + '<span data-tlite="'+pagelayer_l('navigator')+'" class="pagelayer-header-icon-wrap"><i class="pagelayer-navigator-icon pli pli-tree"></i></span>'+
6077 + '<div class="pagelayer-header-divider"></div>'+
6078 + '<button data-tlite="Save Changes" class="pagelayer-update-button pagelayer-success-btn">'+
6079 + '<span class="pagelayer-update-loader">'+
6080 + '<span></span>'+
6081 + '<span></span>'+
6082 + '<span></span>'+
6083 + '</span>'+
6084 + '<span class="pagelayer-update-text">Update</span>'+
6085 + '</button>'+
6086 + '<button data-tlite="Close Editor" class="pagelayer-close-button"><i class="pli pli-cross"></i></button>'+
6087 + '</div>'+
3461 6088 '</div>';
3462 6089
3463 6090 holder.html(html);
6091 +
6092 + // Add active class on load
6093 + var current_mode = pagelayer.screen_mode || 'desktop';
6094 + holder.find('.screen-mode[pagelayer-mode-data="' + current_mode + '"]').addClass('active');
6095 +
3464 6096 holder.find('.pagelayer-update-button').on('click', function(){
3465 6097 pagelayer_save();
3466 6098 pagelayer_history_setup();// Setup history tab after update
3467 6099 });
@@ -3468,20 +6100,18 @@
3468 6100
3469 6101 holder.find('.pagelayer-close-button').on('click', function(){
3470 6102 pagelayer_close();
3471 6103 });
6104 +
3472 6105 holder.find('.screen-mode').on('click', function(){
3473 6106 var screen_mode = jQuery(this).attr('pagelayer-mode-data');
3474 6107 pagelayer_set_screen_mode(screen_mode);
3475 - holder.find('.pagelayer-mode-buttons-wrapper').toggle();
6108 + holder.find('.screen-mode').removeClass('active');
6109 + jQuery(this).addClass('active');
3476 6110 });
3477 6111
3478 - holder.find('.pagelayer-mode-button').on('click', function(){
3479 - holder.find('.pagelayer-mode-buttons-wrapper').toggle();
3480 - });
3481 -
3482 - holder.find('.pagelayer-history-icon').click(function(){
3483 - pagelayer.$$('.pagelayer-elpd-header').show().find('.pagelayer-elpd-title').text('Pagelayer History');
6112 + holder.find('.pagelayer-history-icon').closest('.pagelayer-header-icon-wrap').click(function(){
6113 + pagelayer.$$('.pagelayer-elpd-header').show().find('.pagelayer-elpd-title').text(pagelayer_l('pagelayer_history'));
3484 6114 pagelayer.$$('.pagelayer-logo').hide();
3485 6115 pagelayer_leftbar_tab('pagelayer-history');
3486 6116 pagelayer_active = {};
3487 6117 pagelayer_history_setup();
@@ -3486,10 +6116,10 @@
3486 6116 pagelayer_active = {};
3487 6117 pagelayer_history_setup();
3488 6118 });
3489 6119
3490 - holder.find('.pagelayer-navigator-icon').click(function(){
3491 - pagelayer.$$('.pagelayer-elpd-header').show().find('.pagelayer-elpd-title').text('Pagelayer Navigator');
6120 + holder.find('.pagelayer-navigator-icon').closest('.pagelayer-header-icon-wrap').click(function(){
6121 + pagelayer.$$('.pagelayer-elpd-header').show().find('.pagelayer-elpd-title').text(pagelayer_l('pagelayer_navigator'));
3492 6122 pagelayer.$$('.pagelayer-logo').hide();
3493 6123
3494 6124 // If the navigator tab visible, then don't setup
3495 6125 if(!pagelayer.$$('#pagelayer-navigator').is(':visible')){
@@ -3519,9 +6149,9 @@
3519 6149 url: pagelayer_ajax_url+'&action=pagelayer_create_post_autosave&postID='+pagelayer_postID,
3520 6150 type: 'POST',
3521 6151 data: {
3522 6152 'pagelayer_nonce': pagelayer_ajax_nonce,
3523 - 'pagelayer_post_content': post
6153 + 'pagelayer_post_content': pagelayer_Base64.encode(post)
3524 6154 },
3525 6155 success: function(data) {
3526 6156 var data = JSON.parse(data);
3527 6157
@@ -3526,9 +6156,9 @@
3526 6156 var data = JSON.parse(data);
3527 6157
3528 6158 // If there is some error
3529 6159 if(!pagelayer_empty(data['error']) || pagelayer_empty(data['id'])){
3530 - alert('Unable to set preview for some reason');
6160 + pagelayer_show_msg('Unable to set preview for some reason', 'error');
3531 6161 return;
3532 6162 }
3533 6163
3534 6164 var url = data['url']+'&preview_id='+pagelayer_postID+'&preview_nonce='+
@@ -3548,8 +6178,102 @@
3548 6178 ///////////////////////////////
3549 6179 // Miscellaneuos Functions
3550 6180 ///////////////////////////////
3551 6181
6182 +// Setup General options
6183 +function pagelayer_setup_general_options(){
6184 +
6185 + var holder = pagelayer.$$('.pagelayer-general-options');
6186 +
6187 + if(holder.children().length > 0){
6188 + return;
6189 + }
6190 +
6191 + // TODO: To create this HTML get Array form php
6192 + var html = '<div class="pagelayer-options-sections">'+
6193 + '<h5>'+ pagelayer_l('general_options') +'</h5>'+
6194 + '<div class="pagelayer-option-holder pagelayer-open-customizer">'+
6195 + '<i class="fas fa-paint-brush"></i>'+
6196 + '<span>'+ pagelayer_l('customize') +'</span>'+
6197 + '</div>'+
6198 + '</div>'+
6199 + '<div class="pagelayer-options-sections">'+
6200 + '<h5>'+ pagelayer_l('navigator_options') +'</h5>'+
6201 + '<div class="pagelayer-option-holder pagelayer-options-history-icon">'+
6202 + '<i class="pli pli-history"></i>'+
6203 + '<span>'+ pagelayer_l('historyand_revisions') +'</span>'+
6204 + '</div>'+
6205 + '<div class="pagelayer-option-holder pagelayer-options-navigator-icon">'+
6206 + '<i class="pli pli-tree"></i>'+
6207 + '<span>'+ pagelayer_l('navigator') +'</span>'+
6208 + '</div>'+
6209 + '<div class="pagelayer-option-holder pagelayer-options-preview">'+
6210 + '<i class="pli pli-eye"></i>'+
6211 + '<span>'+ pagelayer_l('preview_changes') +'</span>'+
6212 + '</div>'+
6213 + '</div>'+
6214 + '<div class="pagelayer-options-sections">'+
6215 + '<h5>'+ pagelayer_l('tools') +'</h5>'+
6216 + '<div class="pagelayer-option-holder pagelayer-open-help">'+
6217 + '<i class="fas fa-question"></i>'+
6218 + '<span>'+ pagelayer_l('help') +'</span>'+
6219 + '</div>'+
6220 + '<div class="pagelayer-option-holder pagelayer-open-keyboard-shortcuts">'+
6221 + '<i class="far fa-keyboard"></i>'+
6222 + '<span>'+ pagelayer_l('keyboard_shortcuts') +'</span>'+
6223 + '</div>'+
6224 + '</div>';
6225 +
6226 + holder.html(html);
6227 +
6228 + // Open customizer settings
6229 + holder.find('.pagelayer-open-customizer').click(function(){
6230 + window.open(pagelayer_customizer_url+'&autofocus%5Bpanel%5D=pagelayer_settings', '_blank');
6231 + });
6232 +
6233 + // Open help / support link
6234 + holder.find('.pagelayer-open-help').click(function(){
6235 + window.open(pagelayer_support_url, '_blank');
6236 + });
6237 +
6238 + // Show Pagelayer History
6239 + holder.find('.pagelayer-options-history-icon').click(function(){
6240 + pagelayer.$$('.pagelayer-iframe-top-bar .pagelayer-history-icon').click();
6241 + });
6242 +
6243 + // Show Pagelayer Navigator
6244 + holder.find('.pagelayer-options-navigator-icon').click(function(){
6245 + pagelayer.$$('.pagelayer-iframe-top-bar .pagelayer-navigator-icon').click();
6246 + });
6247 +
6248 + // Show Pagelayer Preview
6249 + holder.find('.pagelayer-options-preview').click(function(){
6250 + pagelayer.$$('.pagelayer-iframe-top-bar .pagelayer-preview').click();
6251 + });
6252 +
6253 + // Show keyboard shortcut modal
6254 + holder.find('.pagelayer-open-keyboard-shortcuts').click(function() {
6255 +
6256 + var modal = pagelayer.$$('.pagelayer-shortcuts-modal');
6257 + modal.css('display','flex');
6258 +
6259 + modal.find('.pagelayer-editor-modal-close-icon').unbind('click');
6260 + modal.find('.pagelayer-editor-modal-close-icon').click(function(){
6261 + modal.hide();
6262 + });
6263 +
6264 + modal.unbind('click');
6265 + modal.on('click', function(e){
6266 +
6267 + if(e.target != this) {
6268 + return;
6269 + }
6270 +
6271 + modal.hide();
6272 + });
6273 + });
6274 +}
6275 +
3552 6276 // Setup navigator
3553 6277 function pagelayer_navigator_setup(){
3554 6278
3555 6279 var navigator_ele = pagelayer.$$('#pagelayer-navigator'),
@@ -3697,29 +6421,29 @@
3697 6421 var scrolled = parentEle || jQuery('html, body');
3698 6422 timeout = timeout || 500;
3699 6423 parentEle = parentEle || jQuery(window);
3700 6424
3701 - setTimeout(function () {
3702 - var parentHeight = parentEle.height(),
3703 - parentScrollTop = parentEle.scrollTop(),
3704 - elementTop = jEle.offset().top,
3705 - topToCheck = elementTop - parentScrollTop;
6425 + setTimeout(function(){
6426 + var parentHeight = parentEle.height(),
6427 + parentScrollTop = parentEle.scrollTop(),
6428 + elementTop = jEle.offset().top,
6429 + topToCheck = elementTop - parentScrollTop;
3706 6430
3707 - if (topToCheck > 0 && topToCheck < parentHeight) {
3708 - return;
3709 - }
6431 + if (topToCheck > 0 && topToCheck < parentHeight) {
6432 + return;
6433 + }
3710 6434
3711 - var scrolling = elementTop - parentHeight / 2;
3712 - scrolled.stop(true).animate({
3713 - scrollTop: scrolling
3714 - }, 1000);
3715 - }, timeout);
6435 + var scrolling = elementTop - parentHeight / 2;
6436 + scrolled.stop(true).animate({
6437 + scrollTop: scrolling
6438 + }, 1000);
6439 + }, timeout);
3716 6440 }
3717 6441
3718 6442 // Generates a random string of "n" characters
3719 6443 function pagelayer_randstr(n, special){
3720 - var text = '';
3721 - var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
6444 + var text = '';
6445 + var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
3722 6446
3723 6447 special = special || 0;
3724 6448 if(special){
3725 6449 possible = possible + '&#$%@';
@@ -3724,79 +6448,28 @@
3724 6448 if(special){
3725 6449 possible = possible + '&#$%@';
3726 6450 }
3727 6451
3728 - for(var i=0; i < n; i++){
3729 - text += possible.charAt(Math.floor(Math.random() * possible.length));
3730 - }
6452 + for(var i=0; i < n; i++){
6453 + text += possible.charAt(Math.floor(Math.random() * possible.length));
6454 + }
3731 6455
3732 - return text;
6456 + return text;
3733 6457 };
3734 6458
3735 -function pagelayer_update_site_title(val){
3736 - if(!pagelayer_empty(val)){
3737 - var site_name = jQuery('.pagelayer-wp-title').attr('pagelayer-a-site_name');
3738 - if(!pagelayer_empty(site_name)){
3739 - var site_title = jQuery.ajax({
3740 - url: pagelayer_ajax_url+'&action=pagelayer_fetch_site_title',
3741 - type: 'post',
3742 - async: false
3743 - }).responseText;
3744 -
3745 - if(site_title != site_name){
3746 - var site_title = jQuery.ajax({
3747 - url: pagelayer_ajax_url+'&action=pagelayer_update_site_title',
3748 - type: 'post',
3749 - data: {'site_title': site_name},
3750 - async: false
3751 - }).responseText;
3752 - }
3753 - }
3754 - }
6459 +function pagelayer_randInt(max) {
6460 + return Math.floor(Math.random() * Math.floor(max));
3755 6461 }
3756 6462
3757 -function pagelayer_trim(str, charlist){
3758 - // discuss at: http://locutus.io/php/trim/
3759 -
3760 - if(typeof str != 'string'){
3761 - return str;
3762 - }
3763 -
3764 - var whitespace = [' ', '\n', '\r', '\t', '\f', '\x0b', '\xa0', '\u2000', '\u2001', '\u2002', '\u2003', '\u2004', '\u2005', '\u2006', '\u2007', '\u2008', '\u2009', '\u200a', '\u200b', '\u2028', '\u2029', '\u3000' ].join('')
3765 - var l = 0
3766 - var i = 0
3767 - str += ''
3768 -
3769 - if (charlist) {
3770 - whitespace = (charlist + '').replace(/([[\]().?/*{}+$^:])/g, '$1')
3771 - }
3772 -
3773 - l = str.length
3774 - for (i = 0; i < l; i++) {
3775 - if (whitespace.indexOf(str.charAt(i)) === -1) {
3776 - str = str.substring(i)
3777 - break
3778 - }
3779 - }
3780 -
3781 - l = str.length
3782 - for (i = l - 1; i >= 0; i--) {
3783 - if (whitespace.indexOf(str.charAt(i)) === -1) {
3784 - str = str.substring(0, i + 1)
3785 - break
3786 - }
3787 - }
3788 -
3789 - return whitespace.indexOf(str.charAt(0)) === -1 ? str : ''
3790 -};
3791 -
3792 6463 // Convert the regular URL of a Video to a Embed URL
3793 -function pagelayer_video_url(src){
3794 -
6464 +function pagelayer_video_url(src, no_url){
6465 +
6466 + no_url = no_url || false;
3795 6467 var youtubeRegExp = /youtube\.com|youtu\.be/;
3796 6468 var vimeoRegExp = /vimeo\.com/;
3797 6469 var match = '';
3798 6470 var videoId = '';
6471 + var vid_params = {};
3799 6472
3800 6473 if (youtubeRegExp.exec(src)) {
3801 6474 match = 'youtube';
3802 6475 } else if (vimeoRegExp.exec(src)) {
@@ -3823,9 +6496,15 @@
3823 6496 } else if (youtube.exec(src)) {
3824 6497 videoId = src.split('.be/');
3825 6498 }
3826 6499
3827 - return '//youtube.com/embed/'+videoId[1];
6500 + vid_params = {
6501 + type : 'youtube',
6502 + src : '//www.youtube.com/embed/'+videoId[1],
6503 + id : videoId[1]
6504 + };
6505 +
6506 + pagelayer_yt_api_register();
3828 6507
3829 6508 break;
3830 6509
3831 6510 case 'vimeo':
@@ -3838,23 +6517,51 @@
3838 6517 } else if (vimeoRegExp.exec(src)) {
3839 6518 videoId = src.split('.com/');
3840 6519 }
3841 6520
3842 - return '//player.vimeo.com/video/'+videoId[1];
6521 + vid_params = {
6522 + type : 'vimeo',
6523 + src : '//player.vimeo.com/video/'+videoId[1],
6524 + id : videoId[1]
6525 + };
3843 6526
3844 6527 break;
3845 6528 default:
3846 - return src;
6529 + vid_params = {
6530 + type : 'local',
6531 + src : src
6532 + };
6533 +
3847 6534 }
6535 +
6536 + if(!no_url){
6537 + return vid_params.src;
6538 + }
6539 +
6540 + return vid_params;
3848 6541 };
3849 6542
6543 +// Youtube API Register
6544 +function pagelayer_yt_api_register(){
6545 +
6546 + if(jQuery('#pagelayer-youtube-script-js').length > 0){
6547 + return;
6548 + }
6549 +
6550 + jQuery('body').append('<script src="https://www.youtube.com/iframe_api" id="pagelayer-youtube-script-js"></script>');
6551 +
6552 +}
6553 +
3850 6554 // Add widget section
3851 6555 function pagelayer_add_widget(){
3852 6556
3853 6557 html='<div class="pagelayer-add-widget-area">'+
3854 - '<button class="pagelayer-add-button pagelayer-add-section"><i class="pagelayer-add-row fa fa-file-text"></i> &nbsp;Add New Section</button>'+
3855 - '<button class="pagelayer-add-button pagelayer-add-row"><i class="pagelayer-add-row fa fa-plus-circle"></i> &nbsp;Add New Row</button>'+
3856 - '<p>Click here to add new row OR drag widgets</p>'+
6558 + '<div class="pagelayer-add-buttons-container">'+
6559 + '<button type="button" class="pagelayer-add-circle-btn pagelayer-add-circle-plus" title="Add New Row"><i class="fas fa-plus"></i></button>'+
6560 + '<button type="button" class="pagelayer-add-circle-btn pagelayer-add-circle-folder pagelayer-add-section" title="Add Template"><i class="fas fa-folder"></i></button>'+
6561 + '<button type="button" class="pagelayer-add-circle-btn pagelayer-add-circle-ai pagelayer-add-ai" title="Build with AI"><i class="fas fa-magic"></i></button>'+
6562 + '</div>'+
6563 + '<p class="pagelayer-add-widget-text">Click here to add new row OR drag widgets</p>'+
3857 6564 '</div>';
3858 6565
3859 6566 jQuery(pagelayer_editable).append(html);
3860 6567
@@ -3860,27 +6567,38 @@
3860 6567
3861 6568 var add_area = jQuery('.pagelayer-add-widget-area');
3862 6569
3863 6570 // Add a code before this
3864 - var add_sc = function(tag){
6571 + var add_sc = function(tag, global_id = ''){
3865 6572
6573 + var attr = '';
6574 + if(!pagelayer_empty(global_id)){
6575 + attr = ' pagelayer-global-id="'+global_id+'" ';
6576 + }
6577 +
3866 6578 // Create Row
3867 - var row = jQuery('<div pagelayer-tag="pl_row"></div>');
6579 + var row = jQuery('<div pagelayer-tag="pl_row" '+((tag == 'pl_row') ? attr : '') +'></div>');
3868 6580 add_area.before(row);
3869 6581 var row_id = pagelayer_onadd(row, false);
3870 6582 var rEle = pagelayer_ele_by_id(row_id);
3871 6583
3872 - if(tag == 'pl_row'){
6584 + if(tag == 'pl_row' && !pagelayer_empty(global_id)){
3873 6585 rEle.click();
3874 6586 return row_id;
3875 6587 }
3876 6588
3877 6589 // Create Column
3878 - var col = jQuery('<div pagelayer-tag="pl_col"></div>');
6590 + var col = jQuery('<div pagelayer-tag="pl_col" '+((tag == 'pl_col') ? attr : '') +'></div>');
3879 6591 rEle.find('.pagelayer-row-holder').append(col);
3880 6592 var col_id = pagelayer_onadd(col, false);
3881 6593 var cEle = pagelayer_ele_by_id(col_id);
3882 6594
6595 +
6596 + if(tag == 'pl_row'){
6597 + rEle.click();
6598 + return row_id;
6599 + }
6600 +
3883 6601 if(tag == 'pl_col'){
3884 6602 cEle.click();
3885 6603 return col_id;
3886 6604 }
@@ -3885,31 +6603,66 @@
3885 6603 return col_id;
3886 6604 }
3887 6605
3888 6606 // Create element
3889 - var ele = jQuery('<div pagelayer-tag="'+tag+'"></div>');
6607 + var ele = jQuery('<div pagelayer-tag="'+tag+'" '+attr+'></div>');
3890 6608 cEle.find('.pagelayer-col-holder').append(ele);
6609 + //console.log(ele);
3891 6610 var id = pagelayer_onadd(ele);
3892 -
6611 + //console.log(id);
6612 + //console.log(col_id);
6613 + var eEle = pagelayer_ele_by_id(col_id);
6614 + //console.log(eEle);
3893 6615 // Ensure the column is not empty
3894 6616 pagelayer_empty_col(cEle.find('.pagelayer-col-holder'));
3895 6617
6618 + if(tag == 'pl_inner_row' && pagelayer_empty(global_id)){
6619 + // Create Column
6620 + var in_col = jQuery('<div pagelayer-tag="pl_col"></div>');
6621 + eEle.find('.pagelayer-row-holder').append(in_col);
6622 + var in_col_id = pagelayer_onadd(in_col, false);
6623 + }
6624 +
3896 6625 return id;
3897 6626
3898 6627 }
3899 6628
3900 - // Handle Click
3901 - add_area.on('click', function(e){
6629 + // Handle Click on Plus Button
6630 + add_area.find('.pagelayer-add-circle-plus').on('click', function(e){
3902 6631 e.stopPropagation();
3903 6632 add_sc('pl_col');
3904 6633 });
3905 6634
3906 - // Handle Click
6635 + // Handle Click on Template/Folder Button
3907 6636 add_area.find('.pagelayer-add-section').on('click', function(e){
3908 6637 e.stopPropagation();
3909 6638 pagelayer_add_section_area();// Setup and show sections modal
3910 6639 });
3911 6640
6641 + // Handle Click on Build with AI Button
6642 + add_area.find('.pagelayer-add-ai, .pagelayer-add-circle-ai').on('click', function(e){
6643 + e.stopPropagation();
6644 + if(typeof PagelayerAI !== 'undefined' && PagelayerAI.showPanel){
6645 + PagelayerAI.showPanel();
6646 + } else if(typeof window.parent !== 'undefined' && typeof window.parent.PagelayerAI !== 'undefined' && window.parent.PagelayerAI.showPanel){
6647 + window.parent.PagelayerAI.showPanel();
6648 + } else if(jQuery('.pagelayer-ai-topbar-btn').length > 0){
6649 + jQuery('.pagelayer-ai-topbar-btn').trigger('click');
6650 + } else if(window.parent && window.parent.jQuery && window.parent.jQuery('.pagelayer-ai-topbar-btn').length > 0){
6651 + window.parent.jQuery('.pagelayer-ai-topbar-btn').trigger('click');
6652 + }
6653 + });
6654 +
6655 +
6656 +
6657 + // Background click fallback (adds column if clicked outside circles)
6658 + add_area.on('click', function(e){
6659 + if(e.target === this || jQuery(e.target).hasClass('pagelayer-add-widget-text')){
6660 + e.stopPropagation();
6661 + add_sc('pl_col');
6662 + }
6663 + });
6664 +
3912 6665 // Handle Drag over
3913 6666 add_area.on('dragover', function(e){
3914 6667 //console.log(e)
3915 6668 add_area.addClass('pagelayer-add-widget-drag');
@@ -3929,8 +6682,9 @@
3929 6682 add_area.removeClass('pagelayer-add-widget-drag');
3930 6683 jQuery('.pagelayer-is-dragging').removeClass('pagelayer-is-dragging');
3931 6684
3932 6685 var tag = e.originalEvent.dataTransfer.getData('tag');
6686 + var global_id = e.originalEvent.dataTransfer.getData('global_id');
3933 6687
3934 6688 // Is it an existing element ?
3935 6689 if(tag.length < 1){
3936 6690 return false;
@@ -3939,12 +6693,29 @@
3939 6693 e.preventDefault();
3940 6694
3941 6695 //console.log(tag);
3942 6696
3943 - add_sc(tag);
6697 + add_sc(tag, global_id);
3944 6698 });
3945 6699 };
3946 6700
6701 +// Is the element in view while scrolling
6702 +function pagelayer_isElementInView(elem, holder, partial) {
6703 + partial = partial || true;
6704 + var container = jQuery(holder);
6705 + var contHeight = container.height();
6706 + var contTop = container.scrollTop();
6707 + var contBottom = contTop + contHeight ;
6708 +
6709 + var elemTop = jQuery(elem).offset().top - container.offset().top;
6710 + var elemBottom = elemTop + jQuery(elem).height();
6711 +
6712 + var isTotal = (elemTop >= 0 && elemBottom <=contHeight);
6713 + var isPart = ((elemTop < 0 && elemBottom > 0 ) || (elemTop > 0 && elemTop <= container.height())) && partial;
6714 +
6715 + return isTotal || isPart ;
6716 +}
6717 +
3947 6718 // Append section modal into body
3948 6719 function pagelayer_add_section_area(){
3949 6720
3950 6721 var body = pagelayer.$$('body');
@@ -3958,16 +6729,36 @@
3958 6729 var section_modal = '<div class="pagelayer-add-section-modal-container">'+
3959 6730 '<div class="pagelayer-add-section-modal-holder">'+
3960 6731 '<div class="pagelayer-add-section-modal">'+
3961 6732 '<div class="pagelayer-add-section-modal-header">'+
3962 - '<i class="pagelayer-add-section-modal-close">&times;</i>'+
3963 - '<span>Add Sections</span>'+
6733 + '<div>Add Sections</div>'+
6734 + '<div class="pagelayer-section-type-div">Type : '+
6735 + '<select name="type" id="pagelayer-section-type">'+
6736 + '<option value="section">Sections</option>'+
6737 + '<option value="header">Headers</option>'+
6738 + '<option value="footer">Footers</option>'+
6739 + '<option value="page">Pages</option>'+
6740 + '</select>'+
6741 + '</div>'+
6742 + '<div class="pagelayer-add-section-modal-close">&times;</div>'+
3964 6743 '</div>'+
3965 - '<div class="pagelayer-add-section-modal-body">'+
6744 + '<div class="pagelayer-add-section-modal-row">'+
6745 + '<div class="pagelayer-add-section-modal-left">'+
6746 + '<div class="pagelayer-section-search-div">'+
6747 + '<i class="pli pli-search" ></i><input class="pagelayer-section-search" /><span class="pagelayer-sf-empty pli">&times;</span>'+
6748 + '</div>'+
6749 + '<div class="pagelayer-section-tags-holder"></div>'+
6750 + '</div>'+
6751 + '<div class="pagelayer-section-modal-body-holder">'+
6752 + '<div class="pagelayer-add-section-modal-body"></div>'+
6753 + '</div>'+
3966 6754 '</div>'+
3967 6755 '<div class="pagelayer-add-section-modal-overlay" style="display:none;">'+
3968 6756 '<div class="pagelayer-section-wait">'+
3969 - '<i class="fa fa-spinner fa-spin"></i><br/><span>Please wait a moment</span>'+
6757 + '<div class="pagelayer-loader">'+
6758 + '<div class="pagelayer-percent-parent"></div>'+
6759 + '</div><br/>'+
6760 + '<span>Please wait a moment</span>'+
3970 6761 '</div>'+
3971 6762 '</div>'+
3972 6763 '</div>'+
3973 6764 '</div>'+
@@ -3982,8 +6773,19 @@
3982 6773 mEle.find('.pagelayer-add-section-modal-close').on('click', function(){
3983 6774 mEle.hide();
3984 6775 });
3985 6776
6777 + // Search Empty
6778 + mEle.find('.pagelayer-sf-empty').on('click', function(){
6779 + mEle.find('.pagelayer-section-search').val('');
6780 + });
6781 +
6782 + // On select section type
6783 + mEle.find('#pagelayer-section-type').on('change', function(){
6784 + var val = jQuery(this).val();
6785 + pagelayer_add_sections_list_setup(val);
6786 + });
6787 +
3986 6788 // Append the list items into modal body
3987 6789 pagelayer_add_sections_list_setup();
3988 6790
3989 6791 mEle.show();// Show the modal
@@ -3993,45 +6795,216 @@
3993 6795 // Append section list into modal body
3994 6796 function pagelayer_add_sections_list_setup(type){
3995 6797
3996 6798 var mEle = pagelayer.$$('.pagelayer-add-section-modal-container');
6799 + var body = mEle.find('.pagelayer-add-section-modal-body');
3997 6800 var add_area = jQuery('.pagelayer-add-widget-area');
3998 6801 type = type || 'section';
3999 6802
4000 - var default_content = '<div style="display:inline-block;position:absolute;top:0;left:0;right:0;text-align:center;"><h1>Coming Soon</h1>'+
4001 - '<span>We will soon add some pre-defined '+type+' layouts which you can add to your post with just one click !</span>'+
4002 - '</div>';
6803 + // Find the number of cols
6804 + var body_width = jQuery(window.parent).width();
6805 + var num_cols = 3;
6806 + if(body_width >= 1500){
6807 + num_cols = 4;
6808 + }else if(body_width >= 992){
6809 + num_cols = 3;
6810 + }else if(body_width >= 768){
6811 + num_cols = 2;
6812 + }else if(body_width >= 360){
6813 + num_cols = 1;
6814 + }
6815 + //console.log(num_cols+' - '+body_width);
4003 6816
4004 - // Set coming soon
4005 - mEle.find('.pagelayer-add-section-modal-body').html(default_content);
4006 - return;
6817 + var viewer = '<div class="pagelayer-section-is-visible"></div>';
6818 + var selected_tags = {};
6819 + var result_set = {};
4007 6820
6821 + // Setup the scroll
6822 + mEle.find('.pagelayer-section-tags-holder').slimScroll({
6823 + height: 'calc(100vh - 150px)',
6824 + railVisible: false,
6825 + alwaysVisible: true,
6826 + color: '#000',
6827 + size: '5px',
6828 + });
6829 +
4008 6830 // Create list of items
4009 6831 var pagelayer_section_list = function(){
4010 6832
4011 - var section_html = '';
4012 - var data = pagelayer_add_section_data[type];
6833 + // List the tags
6834 + if(!pagelayer_empty(pagelayer_add_section_data[type]['tags'])){
6835 + var tags_html = '';
6836 + var tags = pagelayer_add_section_data[type]['tags'];
6837 + for(var k in tags){
6838 + tags_html += '<span class="pagelayer-section-tags" tag="'+k+'">'+k+' ('+tags[k].length+')</span>';
6839 + }
6840 + mEle.find('.pagelayer-section-tags-holder').html(tags_html);
6841 +
6842 + // Handle tag click
6843 + mEle.find('.pagelayer-section-tags').unbind('click');
6844 + mEle.find('.pagelayer-section-tags').on('click', function(e){
6845 +
6846 + var search = mEle.find('.pagelayer-section-search');
6847 +
6848 + // Blank the search
6849 + if(search.val().length > 0){
6850 + search.val('');
6851 + selected_tags = {};
6852 + }
6853 +
6854 + // Fill the selected_tags
6855 + tEle = jQuery(this);
6856 + var tag = tEle.attr('tag')
6857 +
6858 + if(tEle.attr('on') == '1'){
6859 + delete selected_tags[tag];
6860 + tEle.removeAttr('on');
6861 + }else{
6862 + tEle.attr('on', 1);
6863 + selected_tags[tag] = 1;
6864 + }
6865 +
6866 + // Filter
6867 + pagelayer_section_filter(false, 1);
6868 +
6869 + });
6870 + }
4013 6871
4014 - // Get data form pagelayer_add_section_data object to create list
4015 - for(var section in data['list']){
6872 + // Fill in the result
6873 + result_set = { ...pagelayer_add_section_data[type]['list']};
6874 +
6875 + show_result();
6876 +
6877 + };
6878 +
6879 + // How the result and setup scroll
6880 + var show_result = function(){
6881 +
6882 + var html = '';
6883 + for(var i = 0; i < num_cols; i++){
6884 + html += '<div class="pagelayer-section-holder" pagelayer-section-type="'+type+'" num="'+i+'"></div>';
6885 + }
6886 +
6887 + // Blank the body
6888 + body.html(html+viewer);
6889 +
6890 + mEle.find('.pagelayer-section-modal-body-holder').unbind('scroll');
6891 + mEle.find('.pagelayer-section-modal-body-holder').on('scroll', pagelayer_section_body_scroll);
6892 + pagelayer_section_body_scroll();
6893 + }
6894 +
6895 + var scroll_accessed = false;
6896 +
6897 + // Section body ON scroll
6898 + var pagelayer_section_body_scroll = function(){
6899 +
6900 + // Check if there is anything to display in the first place, as we do delete pagelayer_add_section_data
6901 + if(pagelayer_empty(result_set)){
6902 + return;
6903 + }
6904 +
6905 + var tester = mEle.find('.pagelayer-section-is-visible');
6906 + var modal = mEle.find('.pagelayer-section-modal-body-holder');
6907 +
6908 + // If we have scroll
6909 + if(!pagelayer_isElementInView(tester, modal) || scroll_accessed){
6910 + return;
6911 + }
6912 +
6913 + scroll_accessed = true;
6914 +
6915 + var html = '';
6916 + var i = 0;
6917 +
6918 + // Loop result_set
6919 + for(var id in result_set){
4016 6920
4017 - var id = data['list'][section];
6921 + if(i >= (num_cols * 5)){
6922 + break;
6923 + }
4018 6924
4019 - section_html += '<div class="pagelayer-section-item" pagelayer-add-section-id="'+ id +'">'+
4020 - '<img src="'+ data['image_url'] + id +'.png" alt="Pagelayer code screenshot">'+
6925 + var col = i % num_cols;
6926 + //console.log(col);
6927 +
6928 + i++;
6929 +
6930 + var pro = 0;
6931 +
6932 + // Is it pro ?
6933 + if(!pagelayer_empty(result_set[id]) && pagelayer_empty(pagelayer_pro)){
6934 + pro = 1;
6935 + }
6936 +
6937 + html = '<div class="pagelayer-section-item" pagelayer-section-type="'+type+'" pagelayer-add-section-id="'+id+'">'+
6938 + '<img src="'+ pagelayer_add_section_data[type]['image_url'] + id +'/screenshot.jpg" alt="Pagelayer code screenshot" />'+
6939 + (pro ? '<div class="pagelayer-section-pro-req">Pro</div><div class="pagelayer-section-pro-txt">'+pagelayer.pro_txt+'</div>' : '')+
4021 6940 '</div>';
4022 6941
6942 + body.find('.pagelayer-section-holder[num='+col+']').append(html);
6943 +
6944 + delete result_set[id];
6945 +
4023 6946 }
4024 -
4025 - // Create items list
4026 - mEle.find('.pagelayer-add-section-modal-body').html(section_html);
6947 +
6948 + //console.log(result_set);
6949 +
4027 6950 mEle.find('.pagelayer-section-item').unbind('click');
4028 6951 mEle.find('.pagelayer-section-item').on('click', function(e){
4029 6952 pagelayer_section_item_clickable(jQuery(this));
4030 6953 });
4031 6954
4032 - };
6955 + scroll_accessed = false;
6956 +
6957 + }
4033 6958
6959 + // If we have searched something / or clicked tags
6960 + var pagelayer_section_filter = function(event, not_input){
6961 +
6962 + var txt = mEle.find('.pagelayer-section-search').val();
6963 + var tags = pagelayer_add_section_data[type]['tags'];
6964 +
6965 + // Searched anything
6966 + if(!pagelayer_empty(txt) || pagelayer_empty(not_input)){
6967 +
6968 + // Blank the tags
6969 + selected_tags = {};
6970 +
6971 + mEle.find('.pagelayer-section-tags').removeAttr('on');
6972 +
6973 + for(var k in tags){
6974 + if(k.search(txt) >= 0){
6975 + selected_tags[k] = 1;
6976 + mEle.find('.pagelayer-section-tags[tag="'+k+'"]').attr('on', 1);
6977 + }
6978 + }
6979 +
6980 + }
6981 +
6982 + var new_result = {};
6983 + var new_length = 0;
6984 +
6985 + // Filter the content
6986 + for(var t in selected_tags){
6987 +
6988 + for(var i in tags[t]){
6989 + new_length++;
6990 + new_result[tags[t][i]] = tags[t][i];
6991 + }
6992 +
6993 + }
6994 +
6995 + // Copy the result
6996 + result_set = {...new_result};
6997 + //console.log(type);console.log(selected_tags);console.log(result_set);
6998 +
6999 + show_result();
7000 +
7001 + }
7002 +
7003 + // On search change
7004 + mEle.find('.pagelayer-section-search').unbind('input');
7005 + mEle.find('.pagelayer-section-search').on('input', pagelayer_section_filter);
7006 +
4034 7007 // On click items
4035 7008 var pagelayer_section_item_clickable = function(jEle){
4036 7009
4037 7010 var section_id = jEle.attr('pagelayer-add-section-id');
@@ -4040,8 +7013,12 @@
4040 7013 if(pagelayer_empty(section_id)){
4041 7014 return false;
4042 7015 }
4043 7016
7017 + if(jEle.find('.pagelayer-section-pro-req').length > 0){
7018 + return false;
7019 + }
7020 +
4044 7021 // Show the overlay
4045 7022 mEle.find('.pagelayer-add-section-modal-overlay').show();
4046 7023
4047 7024 // Do shortcode the content
@@ -4052,25 +7029,42 @@
4052 7029 'pagelayer_nonce': pagelayer_ajax_nonce,
4053 7030 'pagelayer_section_id': section_id,
4054 7031 'pagelayer-live': 1
4055 7032 },
4056 - success: function(data) {
7033 + success: function(data) {
4057 7034
4058 - var data = JSON.parse(data);
4059 - var cEle = jQuery(data['code']);
4060 -
4061 - // Add section before add widget area
4062 - add_area.before(cEle);
4063 -
4064 - // We need to it setup
4065 - cEle.each(function(){
4066 - var pl_id = pagelayer_id(jQuery(this));
7035 + try{
4067 7036
4068 - if(!pagelayer_empty(pl_id)){
4069 - pagelayer_element_setup('[pagelayer-id="'+pl_id+'"], [pagelayer-id='+pl_id+'] .pagelayer-ele', true);
7037 + var data = JSON.parse(data);
7038 +
7039 + if(!pagelayer_empty(data['error'])){
7040 + pagelayer_show_msg('Error getting the section', 'error');
7041 + mEle.find('.pagelayer-add-section-modal-overlay').hide();
7042 + mEle.hide();
7043 + return;
4070 7044 }
4071 - });
7045 +
7046 + var cEle = jQuery(data['code']);
7047 +
7048 + // Add section before add widget area
7049 + add_area.before(cEle);
7050 +
7051 + // We need to it setup
7052 + cEle.each(function(){
7053 + var pl_id = pagelayer_id(jQuery(this));
7054 +
7055 + if(!pagelayer_empty(pl_id)){
7056 + pagelayer_element_setup('[pagelayer-id="'+pl_id+'"], [pagelayer-id='+pl_id+'] .pagelayer-ele', true);
7057 + }
7058 + });
4072 7059
7060 + }catch(e){
7061 + pagelayer_show_msg('Error getting the section', 'error');
7062 + mEle.find('.pagelayer-add-section-modal-overlay').hide();
7063 + mEle.hide();
7064 + return;
7065 + }
7066 +
4073 7067 },
4074 7068 complete: function(){
4075 7069 mEle.find('.pagelayer-add-section-modal-overlay').hide();
4076 7070 mEle.hide();
@@ -4079,9 +7073,12 @@
4079 7073 }
4080 7074
4081 7075 // Load the data if not there
4082 7076 if(!(type in pagelayer_add_section_data)){
4083 -
7077 +
7078 + // Show the loading
7079 + mEle.find('.pagelayer-add-section-modal-overlay').show();
7080 +
4084 7081 // Get the sections list data and append it
4085 7082 jQuery.ajax({
4086 7083 url: pagelayer_api_url+'/library.php?give='+type,
4087 7084 type: 'post',
@@ -4097,8 +7094,14 @@
4097 7094
4098 7095 // Create the Type
4099 7096 pagelayer_section_list(type);
4100 7097
7098 + // Hide the loading
7099 + mEle.find('.pagelayer-add-section-modal-overlay').hide();
7100 +
7101 + },
7102 + complete: function(){
7103 + mEle.find('.pagelayer-add-section-modal-overlay').hide();
4101 7104 }
4102 7105 });
4103 7106
4104 7107 // We have the data, so show it
@@ -4106,15 +7109,66 @@
4106 7109 pagelayer_section_list(type);
4107 7110 }
4108 7111 }
4109 7112
7113 +// Upload an image
7114 +function pagelayer_upload_image(fileName, blob, pagelayer_ajax_func){
7115 +
7116 + var formData = new FormData();
7117 + formData.append('action', 'upload-attachment');
7118 + formData.append('_ajax_nonce', pagelayer_media_ajax_nonce);
7119 + formData.append('async-upload', blob, fileName);
7120 +
7121 + jQuery.ajax({
7122 + url:pagelayer_ajax_url,
7123 + data: formData,// the formData function is available in almost all new browsers.
7124 + type:"post",
7125 + contentType:false,
7126 + processData:false,
7127 + cache:false,
7128 + beforeSend: function( xhr ) {
7129 + if(typeof pagelayer_ajax_func.beforeSend == 'function'){
7130 + pagelayer_ajax_func.beforeSend(xhr);
7131 + }
7132 + },
7133 + xhr: function() {
7134 + var xhr = new window.XMLHttpRequest();
7135 + if(typeof pagelayer_ajax_func.uploadProgress == 'function'){
7136 + xhr = pagelayer_ajax_func.uploadProgress(xhr);
7137 + }
7138 + return xhr;
7139 + },
7140 + error:function(err){
7141 + //console.error(err);
7142 + pagelayer_show_msg('Unable to upload image for some reason.', 'error');
7143 + },
7144 + success:function(response){
7145 + var obj = jQuery.parseJSON(response);
7146 + if(typeof pagelayer_ajax_func.success == 'function'){
7147 + pagelayer_ajax_func.success(obj);
7148 + }
7149 + },
7150 + complete:function(xhr){
7151 + if(typeof pagelayer_ajax_func.complete == 'function'){
7152 + pagelayer_ajax_func.complete(xhr);
7153 + }
7154 + }
7155 + });
7156 +};
7157 +
4110 7158 // On editable area image paste handler
4111 7159 function pagelayer_editable_paste_handler(pasteEvent, pagelayer_ajax_func){
7160 + var items,
7161 + is_Paste = (pasteEvent.type == 'paste' ? true : false),
7162 + mustPreventDefault = false,
7163 + reader;
4112 7164
4113 7165 try {
4114 - var items = (pasteEvent.originalEvent || pasteEvent).clipboardData.items,
4115 - mustPreventDefault = false,
4116 - reader;
7166 + if(is_Paste){
7167 + items = (pasteEvent.originalEvent || pasteEvent).clipboardData.items;
7168 + }else{
7169 + items = [pasteEvent];
7170 + }
4117 7171
4118 7172 for (var i = items.length - 1; i >= 0; i -= 1) {
4119 7173
4120 7174 if (items[i].type.match(/^image\//)) {
@@ -4120,71 +7174,49 @@
4120 7174 if (items[i].type.match(/^image\//)) {
4121 7175
4122 7176 reader = new FileReader();
4123 7177 /* jshint -W083 */
4124 - reader.onloadend = function (event) {
7178 + reader.onloadend = function(event) {
4125 7179
4126 7180 var src = event.target.result;
4127 7181
4128 - if( src.indexOf('data:image') === 0 ) {
7182 + if(src.indexOf('data:image') === 0 ) {
4129 7183
4130 7184 var block = src.split(";");
4131 7185 var contentType = block[0].split(":")[1];
4132 7186 var realData = block[1].split(",")[1];
4133 - var fileName = "image."+contentType.split("/")[1];
7187 + if(is_Paste){
7188 + var fileName = "image."+contentType.split("/")[1];
7189 + }else{
7190 + var fileName = items[0]['name'];
7191 + }
4134 7192
4135 7193 // Convert it to a blob to upload
4136 7194 var blob = pagelayer_b64toBlob(realData, contentType);
4137 7195
4138 - var formData = new FormData();
4139 - formData.append('action', 'upload-attachment');
4140 - formData.append('_ajax_nonce', pagelayer_media_ajax_nonce);
4141 - formData.append('async-upload', blob, fileName);
7196 + pagelayer_upload_image(fileName, blob, pagelayer_ajax_func);
4142 7197
4143 - jQuery.ajax({
4144 - url:pagelayer_ajax_url,
4145 - data: formData,// the formData function is available in almost all new browsers.
4146 - type:"post",
4147 - contentType:false,
4148 - processData:false,
4149 - cache:false,
4150 - beforeSend: function( xhr ) {
4151 - if(typeof pagelayer_ajax_func.beforeSend == 'function'){
4152 - pagelayer_ajax_func.beforeSend(xhr);
4153 - }
4154 - },
4155 - error:function(err){
4156 - //console.error(err);
4157 - alert("Unable to upload image for some reason.");
4158 - },
4159 - success:function(response){
4160 - var obj = jQuery.parseJSON(response);
4161 - if(typeof pagelayer_ajax_func.success == 'function'){
4162 - pagelayer_ajax_func.success(obj);
4163 - }
4164 - },
4165 - complete:function(xhr){
4166 - if(typeof pagelayer_ajax_func.complete == 'function'){
4167 - pagelayer_ajax_func.complete(xhr);
4168 - }
4169 - }
4170 - });
4171 -
4172 7198 }
4173 7199
4174 7200 };
4175 7201 /* jshint +W083 */
4176 - reader.readAsDataURL(items[i].getAsFile());
7202 + if(is_Paste){
7203 + reader.readAsDataURL(items[i].getAsFile());
7204 + }else{
7205 + reader.readAsDataURL(items[i]);
7206 + }
4177 7207 mustPreventDefault = true;
4178 7208 }
4179 7209 }
4180 7210
4181 - if(mustPreventDefault){
7211 + if(mustPreventDefault && is_Paste){
4182 7212 pasteEvent.stopPropagation();
4183 7213 pasteEvent.preventDefault();
4184 7214 }
4185 7215
4186 - }catch(err){}
7216 + }catch(err){
7217 + console.log(err);
7218 + }
4187 7219
4188 7220 return mustPreventDefault;
4189 7221
4190 7222 }
@@ -4226,11 +7258,925 @@
4226 7258
4227 7259 // Tooltip Setup for Editor
4228 7260 function pagelayer_tooltip_setup(){
4229 7261 //pagelayer.$$('[data-tlite]').each(function(){pagelayer_tlite.show(jQuery(this).get(0));});return;
4230 - pagelayer.$$('[data-tlite]').on('hover', function(){
7262 + pagelayer.$$('[data-tlite]').hover(function(){
4231 7263 pagelayer_tlite.show(jQuery(this).get(0));
4232 - }).on('mouseleave', function(){
7264 + }, function(){
4233 7265 pagelayer_tlite.hide(jQuery(this).get(0));
4234 7266 });
4235 7267
7268 +};
7269 +
7270 +// Pagelayer Messages
7271 +function pagelayer_show_msg(msg, state, time){
7272 +
7273 + time = time || 5000;
7274 + state = !pagelayer_empty(state) ? 'pagelayer-editor-msg-state-'+state : '';
7275 + var nholder = pagelayer.$$('.pagelayer-editor-notice');
7276 + var mEle = jQuery('<div class="pagelayer-editor-msg '+state+'">'+msg+' <span class="pli pli-cross pagelayer-notice-x"></span></div>');
7277 +
7278 + nholder.append(mEle);
7279 +
7280 + mEle.find('.pagelayer-notice-x').on('click', function(){
7281 + mEle.css({opacity: 0});
7282 + setTimeout(function(){
7283 + mEle.css({transition: 'none'});
7284 + mEle.slideUp(function(){
7285 + mEle.remove();
7286 + });
7287 + }, 900);
7288 + });
7289 +
7290 + setTimeout(function(){
7291 + mEle.find('.pagelayer-notice-x').click();
7292 + }, time);
7293 +
4236 7294 }
7295 +
7296 +// Pagelayer confirmation box
7297 +function pagelayer_confirmation_box(message, yesCallback, noCallback, yesText, noText) {
7298 +
7299 + yesText = yesText || pagelayer_l('Yes');
7300 + noText = noText || pagelayer_l('No');
7301 +
7302 + var dialog = jQuery('<div class="pagelayer-confirm-box-holder">'+
7303 + '<div class="pagelayer-confirm-box" style="border-radius:5px">'+
7304 + '<div class="pagelayer-confirmation-msg">'+ message +'</div>'+
7305 + '<center>'+
7306 + '<span class="pagelayer-btnyes button button-pagelayer">'+ yesText +'</span>&nbsp;&nbsp;&nbsp;'+
7307 + '<span class="pagelayer-btnno button button-pagelayer">'+ noText +'</span>'+
7308 + '</center>'+
7309 + '</div>'+
7310 + '</div>');
7311 +
7312 + pagelayer.$$('body').append(dialog);
7313 +
7314 + dialog.find('.pagelayer-btnyes').on('click', function() {
7315 + dialog.remove();
7316 + if(typeof yesCallback == 'function'){
7317 + yesCallback();
7318 + }
7319 + });
7320 + dialog.find('.pagelayer-btnno').on('click', function() {
7321 + dialog.remove();
7322 + if(typeof noCallback == 'function'){
7323 + noCallback();
7324 + }
7325 + });
7326 + dialog.show();
7327 +}
7328 +
7329 +function pagelayer_trim(str, charlist){
7330 + // discuss at: http://locutus.io/php/trim/
7331 +
7332 + if(typeof str != 'string'){
7333 + return str;
7334 + }
7335 +
7336 + var whitespace = [' ', '\n', '\r', '\t', '\f', '\x0b', '\xa0', '\u2000', '\u2001', '\u2002', '\u2003', '\u2004', '\u2005', '\u2006', '\u2007', '\u2008', '\u2009', '\u200a', '\u200b', '\u2028', '\u2029', '\u3000' ].join('');
7337 + var l = 0;
7338 + var i = 0;
7339 + str += '';
7340 +
7341 + if (charlist) {
7342 + whitespace = (charlist + '').replace(/([[\]().?/*{}+$^:])/g, '$1');
7343 + }
7344 +
7345 + l = str.length;
7346 + for (i = 0; i < l; i++) {
7347 + if (whitespace.indexOf(str.charAt(i)) === -1) {
7348 + str = str.substring(i);
7349 + break;
7350 + }
7351 + }
7352 +
7353 + l = str.length;
7354 + for (i = l - 1; i >= 0; i--) {
7355 + if (whitespace.indexOf(str.charAt(i)) === -1) {
7356 + str = str.substring(0, i + 1);
7357 + break;
7358 + }
7359 + }
7360 +
7361 + return whitespace.indexOf(str.charAt(0)) === -1 ? str : '';
7362 +};
7363 +
7364 +function pagelayer_ucwords(str) {
7365 + return (str + '').replace(/^([a-z])|\s+([a-z])/g, function ($1) {
7366 + return $1.toUpperCase();
7367 + });
7368 +}
7369 +
7370 +// Check length for string and object
7371 +function pagelayer_length(mixed_var) {
7372 +
7373 + var length = 0;
7374 + var undef, key, i, len;
7375 + var emptyValues = [undef, null, false];
7376 +
7377 + for(i = 0, len = emptyValues.length; i < len; i++) {
7378 + if (mixed_var === emptyValues[i]) {
7379 + return length;
7380 + }
7381 + }
7382 +
7383 + // Is array, object or jQuery object?
7384 + if(typeof mixed_var === 'object'){
7385 +
7386 + // If is jQuery object
7387 + if( mixed_var.hasOwnProperty('length')){
7388 + return mixed_var.length;
7389 + }
7390 +
7391 + for (key in mixed_var) {
7392 + // TODO: should we check for own properties only?
7393 + //if ( .hasOwnProperty(key)) {
7394 + length++;
7395 + //}
7396 + }
7397 +
7398 + return length;
7399 + }
7400 +
7401 + length = String(mixed_var).length;
7402 +
7403 + return length;
7404 +};
7405 +
7406 +// Create Widget list dropdown
7407 +function pagelayer_create_widget_tooltip(){
7408 +
7409 + var html = '<div class="pagelayer-widget-tooltip">'+
7410 + '<div class="pagelayer-widget-search-holder">'+
7411 + '<div class="pagelayer-widget-search">'+
7412 + '<i class="pli pli-search" ></i><input class="pagelayer-search-field" /><span class="pagelayer-sf-empty pli">&times;</span>'+
7413 + '</div>'+
7414 + '</div>';
7415 +
7416 + for(var x in pagelayer_groups){
7417 +
7418 + // Title
7419 + html += '<div class="pagelayer-widget-group pagelayer-group-name-'+x+'"><h5>'+x+'</h5>';
7420 +
7421 + // Indivdual icon
7422 + for(var y in pagelayer_groups[x]){
7423 +
7424 + var sc = pagelayer_groups[x][y];
7425 +
7426 + if(!(sc in pagelayer_shortcodes) || 'not_visible' in pagelayer_shortcodes[sc]){
7427 + continue;
7428 + }
7429 +
7430 + html += '<div class="pagelayer-shortcode-holder" pagelayer-tag="'+sc+'">'+
7431 + '<div class="pagelayer-pointer pagelayer-sc">'+
7432 + '<center class="pagelayer-shortcode-inner">';
7433 +
7434 + if('icon' in pagelayer_shortcodes[sc]){
7435 + html += '<i class="pagelayer-shortcode '+pagelayer_shortcodes[sc]['icon']+'"></i>';
7436 + }else{
7437 + html += '<i class="pagelayer-shortcode pli pagelayer-'+sc+'"></i>';
7438 + }
7439 +
7440 + html += '</center>'+
7441 + '<span class="pagelayer-pointer pagelayer-shortcode-text">'+pagelayer_shortcodes[sc]['name']+'</span>'+
7442 + '</div>'+
7443 + '</div>';
7444 +
7445 + }
7446 +
7447 + html += '</div>';
7448 +
7449 + }
7450 +
7451 + html += '</div>';
7452 +
7453 + pagelayer.$$('body').append(html);
7454 +
7455 + var wdHolder = pagelayer.$$('.pagelayer-widget-tooltip');
7456 +
7457 + // Hide the ones which are not supposed to be shown
7458 + wdHolder.find('.pagelayer-search-field').on('input', function(){
7459 +
7460 + var val = jQuery(this).val();
7461 + var re = new RegExp(val, 'i');
7462 +
7463 + // Show only the required tags
7464 + wdHolder.find('.pagelayer-widget-group').each(function(){
7465 +
7466 + var group = jQuery(this);
7467 + var res = group.find('[pagelayer-tag]');
7468 + var hidden = 0;
7469 +
7470 + res.each(function(){
7471 +
7472 + var tEle = jQuery(this);
7473 + if(tEle.find('.pagelayer-shortcode-text').html().match(re)){
7474 + tEle.show();
7475 + }else{
7476 + hidden += 1;
7477 + tEle.hide();
7478 + }
7479 +
7480 + });
7481 +
7482 + // Hide the whole group
7483 + if(hidden == res.length){
7484 + group.hide();
7485 + }else{
7486 + group.show();
7487 + }
7488 +
7489 + });
7490 +
7491 + wdHolder.find('.pagelayer-shortcode-holder:visible').first().trigger('widget_active');
7492 +
7493 + });
7494 +
7495 + // On click search empty
7496 + wdHolder.find('.pagelayer-widget-search>.pagelayer-sf-empty').click(function(){
7497 + wdHolder.find('.pagelayer-search-field').val('').trigger('input');
7498 + });
7499 +
7500 + // Register widget active event
7501 + wdHolder.find('.pagelayer-shortcode-holder').on('widget_active', function(){
7502 + var activeEle = jQuery(this);
7503 + wdHolder.find('.pagelayer-list-widget-active').removeClass('pagelayer-list-widget-active');
7504 +
7505 + if(!activeEle.hasClass('pagelayer-list-widget-active')){
7506 + activeEle.addClass('pagelayer-list-widget-active');
7507 + }
7508 +
7509 + activeEle[0].scrollIntoView({behavior: "smooth", block: "end"});
7510 + });
7511 +
7512 + pagelayer.gDocument.on('mousedown.pagelayer_wdlist', function(e){
7513 + var target = jQuery(e.target);
7514 +
7515 + if(target.closest('.pagelayer-widget-tooltip').is(wdHolder)){
7516 + return;
7517 + }
7518 +
7519 + wdHolder.find('.pagelayer-shortcode-holder:visible').first().trigger('widget_active');
7520 +
7521 + wdHolder.hide();
7522 + jQuery('.pagelayer-show-wiget-list').removeClass('pagelayer-show-wiget-list');
7523 + jQuery(window).off('scroll.pagelayer_wdlist resize.pagelayer_wdlist');
7524 + });
7525 +
7526 +}
7527 +
7528 +// Show Widget list dropdown
7529 +function pagelayer_show_widget_list(jEle, val){
7530 +
7531 + val = val || '';
7532 + jEle = jQuery(jEle);
7533 +
7534 + var wEle = pagelayer.$$('.pagelayer-widget-tooltip'),
7535 + winH = jQuery(window).height(),
7536 + iframe = pagelayer.$$('#pagelayer-iframe'),
7537 + iframeTop = iframe.offset().top,
7538 + iframeLeft = iframe.offset().left,
7539 + style = {},
7540 + wTop = 'auto',
7541 + wBottom = 'auto',
7542 + wLeft = '';
7543 + wHeight = '';
7544 +
7545 + searchField = wEle.find('.pagelayer-search-field');
7546 + searchField.val(val);
7547 + searchField.trigger('input');
7548 +
7549 + // Add widget show class
7550 + if(jEle.hasClass('pagelayer-shortcode-plus')){
7551 + jEle.parent('.pagelayer-ele-overlay').addClass('pagelayer-show-wiget-list');
7552 + }
7553 +
7554 + var bounds = jEle[0].getBoundingClientRect();
7555 +
7556 + wEle.removeClass('pagelayer-widget-list-tooltip');
7557 + wLeft = (bounds.left + iframeLeft) - wEle.width() / 2;
7558 +
7559 + // In list view?
7560 + if(jEle.closest('[pagelayer-editable]').length > 0){
7561 + wEle.addClass('pagelayer-widget-list-tooltip');
7562 + var selection = window.getSelection();
7563 + var range = selection.getRangeAt(0);
7564 + wLeft = (range.getBoundingClientRect().left + iframeLeft) - wEle.width() / 2;
7565 + }
7566 +
7567 + wEle.closest('.pagelayer-widget-tooltip').show();
7568 + wEle.find('.pagelayer-shortcode-holder:visible').first().trigger('widget_active');
7569 +
7570 + // Hide Widget list
7571 + if(jEle.closest('[pagelayer-editable]').length > 0 && wEle.find('.pagelayer-widget-group:visible').length < 1){
7572 + pagelayer.gDocument.trigger('mousedown.pagelayer_wdlist');
7573 + return;
7574 + }else{
7575 + searchField.focus().select();
7576 + }
7577 +
7578 + var docW = iframeLeft + iframe.width() - 30;
7579 +
7580 + // Prevent to hide on left or right
7581 + if(docW < wLeft + wEle.width()){
7582 + wLeft = docW - wEle.width();
7583 + }else if(iframeLeft > wLeft){
7584 + wLeft = iframeLeft;
7585 + }
7586 +
7587 + if(winH / 2 < bounds.top + 10){
7588 + wBottom = winH - bounds.top + 10;
7589 + wHeight = bounds.top - 10;
7590 + }else{
7591 + wTop = bounds.bottom + iframeTop + 10;
7592 + wHeight = winH - bounds.bottom - 10;
7593 + }
7594 +
7595 + style['left'] = wLeft;
7596 + style['top'] = wTop;
7597 + style['bottom'] = wBottom;
7598 + style['max-height'] = '';
7599 +
7600 + if(wHeight < 350){
7601 + style['max-height'] = wHeight;
7602 + }
7603 +
7604 + wEle.css(style);
7605 +
7606 + jQuery(window).off('scroll.pagelayer_wdlist resize.pagelayer_wdlist');
7607 + jQuery(window).on('scroll.pagelayer_wdlist resize.pagelayer_wdlist', function(){
7608 + var _val = wEle.find('.pagelayer-search-field').val();
7609 + pagelayer_show_widget_list(jEle, _val);
7610 + });
7611 +
7612 + wEle.find('.pagelayer-shortcode-holder').off('click');
7613 + wEle.find('.pagelayer-shortcode-holder').on('click', function(e){
7614 +
7615 + var tag = jQuery(this).attr('pagelayer-tag');
7616 + var mWrap = jEle.closest('.pagelayer-ele-wrap[pagelayer-wrap-id]');
7617 + var mTag = pagelayer_tag(mWrap);
7618 +
7619 + var ele = jQuery('<div pagelayer-tag="'+tag+'"></div>');
7620 +
7621 + // Is col?
7622 + if(mTag == 'pl_col'){
7623 + var colHolder = mWrap.find('>.pagelayer-col > .pagelayer-col-holder');
7624 + colHolder.append(ele);
7625 + pagelayer_empty_col(colHolder);
7626 + }else{
7627 + mWrap.after(ele);
7628 + }
7629 +
7630 + // Replace widget
7631 + if(jEle.closest('[pagelayer-editable]').length > 0){
7632 + pagelayer_delete_element(mWrap.find('>.pagelayer-ele'));
7633 + }
7634 +
7635 + var eleId = pagelayer_onadd(ele, false);
7636 + var eEle = pagelayer_ele_by_id(eleId);
7637 +
7638 + // Create Column
7639 + if( tag == 'pl_inner_row' ){
7640 + var in_col = jQuery('<div pagelayer-tag="pl_col"></div>');
7641 + eEle.find('>.pagelayer-row-holder').append(in_col);
7642 + var in_col_id = pagelayer_onadd(in_col, false);
7643 + }
7644 +
7645 + eEle.click();
7646 +
7647 + // Hide Widget list
7648 + pagelayer.gDocument.trigger('mousedown.pagelayer_wdlist');
7649 + });
7650 +
7651 +}
7652 +
7653 +// Set Selection By Character Offsets
7654 +function pagelayer_setCaret(containerEl, start, end){
7655 +
7656 + end = end || start;
7657 +
7658 + // Refered from http://jsfiddle.net/zQUhV/47/
7659 + if(window.getSelection && document.createRange){
7660 +
7661 + var charIndex = 0, range = document.createRange();
7662 + range.setStart(containerEl, 0);
7663 + range.collapse(true);
7664 + var nodeStack = [containerEl], node, foundStart = false, stop = false;
7665 +
7666 + while (!stop && (node = nodeStack.pop())) {
7667 + if (node.nodeType == 3) {
7668 + var nextCharIndex = charIndex + node.length;
7669 + if (!foundStart && start >= charIndex && start <= nextCharIndex) {
7670 + range.setStart(node, start - charIndex);
7671 + foundStart = true;
7672 + }
7673 + if (foundStart && end >= charIndex && end <= nextCharIndex) {
7674 + range.setEnd(node, end - charIndex);
7675 + stop = true;
7676 + }
7677 + charIndex = nextCharIndex;
7678 + } else {
7679 + var i = node.childNodes.length;
7680 + while (i--) {
7681 + nodeStack.push(node.childNodes[i]);
7682 + }
7683 + }
7684 + }
7685 +
7686 + var sel = window.getSelection();
7687 + sel.removeAllRanges();
7688 + sel.addRange(range);
7689 +
7690 + } else if (document.selection) {
7691 + var textRange = document.body.createTextRange();
7692 + textRange.moveToElementText(containerEl);
7693 + textRange.collapse(true);
7694 + textRange.moveEnd("character", end);
7695 + textRange.moveStart("character", start);
7696 + textRange.select();
7697 + }
7698 +}
7699 +
7700 +// Set Selection By Character Offsets
7701 +function pagelayer_content_line(containerEl){
7702 +
7703 + var lines = [], charIndex = 0, range = document.createRange();
7704 + range.setStart(containerEl, 0);
7705 + range.collapse(true);
7706 + var bounding = range.getBoundingClientRect();
7707 + var nodeStack = [containerEl], node, prevX = bounding.x, nextStart = 0;
7708 +
7709 + while(node = nodeStack.pop()){
7710 + if (node.nodeType == 3) {
7711 + for(var i = 1; i <= node.length; i++){
7712 + range.setStart(node, i);
7713 + range.setEnd(node, i);
7714 + bounding = range.getBoundingClientRect();
7715 + charIndex ++;
7716 +
7717 + if(prevX > bounding.x){
7718 + lines.push({start:nextStart, end:charIndex - 1});
7719 + nextStart = charIndex;
7720 + }
7721 + prevX = bounding.x;
7722 + }
7723 + } else {
7724 + var i = node.childNodes.length;
7725 + while(i--){
7726 + nodeStack.push(node.childNodes[i]);
7727 + }
7728 + }
7729 + }
7730 +
7731 + // Push last line
7732 + if(nextStart != charIndex || nextStart == 0){
7733 + lines.push({start:nextStart, end:charIndex});
7734 + }
7735 +
7736 + return lines;
7737 +}
7738 +
7739 +//http://jsfiddle.net/TjXEG/900/
7740 +function pagelayer_getCaretCharacterOffsetWithin(element){
7741 + var caretOffset = 0;
7742 + var doc = element.ownerDocument || element.document;
7743 + var win = doc.defaultView || doc.parentWindow;
7744 + var sel;
7745 + if( typeof win.getSelection != "undefined" ){
7746 + sel = win.getSelection();
7747 + if (sel.rangeCount > 0) {
7748 + var range = win.getSelection().getRangeAt(0);
7749 + var preCaretRange = range.cloneRange();
7750 + preCaretRange.selectNodeContents(element);
7751 + preCaretRange.setEnd(range.endContainer, range.endOffset);
7752 + caretOffset = preCaretRange.toString().length;
7753 + }
7754 + }else if( (sel = doc.selection) && sel.type != "Control" ){
7755 + var textRange = sel.createRange();
7756 + var preCaretTextRange = doc.body.createTextRange();
7757 + preCaretTextRange.moveToElementText(element);
7758 + preCaretTextRange.setEndPoint("EndToEnd", textRange);
7759 + caretOffset = preCaretTextRange.text.length;
7760 + }
7761 + return caretOffset;
7762 +}
7763 +
7764 +// ==========================================================================
7765 +// PAGELAYER UX IMPROVEMENTS
7766 +// ==========================================================================
7767 +
7768 +var pagelayer_is_command_palette_open = false;
7769 +
7770 +function pagelayer_ux_improvements_init() {
7771 + // Setup global shortcuts inside Parent Window and Iframe Document
7772 + var setupShortcuts = function(doc) {
7773 + jQuery(doc).on('keydown', function(e) {
7774 + // Command Palette: Ctrl+K
7775 + if (e.key === 'k' && (e.ctrlKey || e.metaKey)) {
7776 + e.preventDefault();
7777 + pagelayer_toggle_command_palette();
7778 + }
7779 + });
7780 + };
7781 +
7782 + setupShortcuts(document);
7783 + if (pagelayer.gDocument) {
7784 + setupShortcuts(pagelayer.gDocument);
7785 + }
7786 +
7787 + // Hook selection callback to refresh Navigator if it is open in the right sidebar
7788 + pagelayer_add_action('pagelayer_element_clicked', function(jEle) {
7789 + if (jEle && jEle.length > 0) {
7790 + var isNavigatorOpen = pagelayer.$$('body').hasClass('pagelayer-right-sidebar-open') && pagelayer.$$('#pagelayer-navigator').is(':visible');
7791 + if (isNavigatorOpen) {
7792 + var newId = pagelayer_id(jEle);
7793 + if (newId) {
7794 + pagelayer_active.el = pagelayer_active.el || {};
7795 + pagelayer_active.el.id = newId;
7796 + }
7797 + pagelayer_navigator_setup();
7798 + }
7799 + }
7800 + });
7801 +
7802 + // Redirect Navigator & History/Revisions tabs to a new small right sidebar
7803 + window.pagelayer_close_right_sidebar = function() {
7804 + var sidebar = pagelayer.$$('.pagelayer-right-sidebar');
7805 + if (sidebar.length > 0) {
7806 + sidebar.css('right', '-300px');
7807 + pagelayer.$$('body').removeClass('pagelayer-right-sidebar-open');
7808 + pagelayer.$$('.pagelayer-navigator-icon, .pagelayer-history-icon').closest('.pagelayer-header-icon-wrap').removeClass('active');
7809 + pagelayer.$$('#pagelayer-navigator').hide();
7810 + pagelayer.$$('#pagelayer-history').hide();
7811 + }
7812 + };
7813 +
7814 + window.pagelayer_open_right_sidebar = function(tab) {
7815 + var sidebar = pagelayer.$$('.pagelayer-right-sidebar');
7816 + if (sidebar.length === 0) {
7817 + var sidebarHtml =
7818 + '<div class="pagelayer-right-sidebar">' +
7819 + '<div class="pagelayer-right-sidebar-header">' +
7820 + '<h4 class="pagelayer-right-sidebar-title"></h4>' +
7821 + '<button class="pagelayer-right-sidebar-close"><i class="pli pli-cross"></i></button>' +
7822 + '</div>' +
7823 + '<div class="pagelayer-right-sidebar-content">' +
7824 + '</div>' +
7825 + '</div>';
7826 + pagelayer.$$('body').append(sidebarHtml);
7827 + sidebar = pagelayer.$$('.pagelayer-right-sidebar');
7828 +
7829 + sidebar.find('.pagelayer-right-sidebar-close').on('click', function() {
7830 + window.pagelayer_close_right_sidebar();
7831 + });
7832 + }
7833 +
7834 + var isDark = pagelayer.$$('body').hasClass('pagelayer-dark');
7835 + if (isDark) {
7836 + sidebar.addClass('pagelayer-dark');
7837 + } else {
7838 + sidebar.removeClass('pagelayer-dark');
7839 + }
7840 +
7841 + pagelayer.$$('.pagelayer-navigator-icon, .pagelayer-history-icon').closest('.pagelayer-header-icon-wrap').removeClass('active');
7842 +
7843 + var title = '';
7844 + var iconClass = '';
7845 + if (tab === 'pagelayer-navigator') {
7846 + title = pagelayer_l('pagelayer_navigator') || 'Navigator';
7847 + iconClass = '.pagelayer-navigator-icon';
7848 + } else {
7849 + title = pagelayer_l('pagelayer_history') || 'History & Revisions';
7850 + iconClass = '.pagelayer-history-icon';
7851 + }
7852 +
7853 + sidebar.find('.pagelayer-right-sidebar-title').text(title);
7854 +
7855 + var isVisible = pagelayer.$$('body').hasClass('pagelayer-right-sidebar-open');
7856 + var targetContainer = pagelayer.$$('#' + tab);
7857 + if (isVisible && targetContainer.length > 0 && targetContainer.is(':visible')) {
7858 + window.pagelayer_close_right_sidebar();
7859 + return;
7860 + }
7861 +
7862 + pagelayer.$$(iconClass).closest('.pagelayer-header-icon-wrap').addClass('active');
7863 + sidebar.find('.pagelayer-right-sidebar-content').children().hide();
7864 +
7865 + if (targetContainer.parent().hasClass('pagelayer-right-sidebar-content') === false) {
7866 + sidebar.find('.pagelayer-right-sidebar-content').append(targetContainer);
7867 + }
7868 +
7869 + targetContainer.show().css({'height': '100%', 'position': 'static'});
7870 + sidebar.css('right', '0px');
7871 + pagelayer.$$('body').addClass('pagelayer-right-sidebar-open');
7872 + };
7873 +
7874 + var original_pagelayer_leftbar_tab = window.pagelayer_leftbar_tab;
7875 + window.pagelayer_leftbar_tab = function(tab) {
7876 + if (tab === 'pagelayer-navigator' || tab === 'pagelayer-history') {
7877 + window.pagelayer_open_right_sidebar(tab);
7878 + } else {
7879 + // Do not hide navigator or history tab if they are in the right sidebar
7880 + pagelayer.$$('.pagelayer-leftbar-tab').not('#pagelayer-navigator, #pagelayer-history').hide();
7881 + pagelayer.$$('#'+tab).show();
7882 + }
7883 + };
7884 +
7885 + var bindIcons = function() {
7886 + var $historyIcon = pagelayer.$$('.pagelayer-history-icon');
7887 + $historyIcon.off('click');
7888 + $historyIcon.closest('.pagelayer-header-icon-wrap').off('click').on('click', function(e) {
7889 + e.stopPropagation();
7890 + window.pagelayer_open_right_sidebar('pagelayer-history');
7891 + pagelayer_history_setup();
7892 + });
7893 +
7894 + var $navigatorIcon = pagelayer.$$('.pagelayer-navigator-icon');
7895 + $navigatorIcon.off('click');
7896 + $navigatorIcon.closest('.pagelayer-header-icon-wrap').off('click').on('click', function(e) {
7897 + e.stopPropagation();
7898 + var targetContainer = pagelayer.$$('#pagelayer-navigator');
7899 + if (!targetContainer.is(':visible')) {
7900 + pagelayer_navigator_setup();
7901 + }
7902 + window.pagelayer_open_right_sidebar('pagelayer-navigator');
7903 + });
7904 + };
7905 +
7906 + bindIcons();
7907 + setInterval(bindIcons, 3000);
7908 +}
7909 +
7910 +// Toggle Command Palette Modal (Figma / Bricks style search palette)
7911 +function pagelayer_toggle_command_palette() {
7912 + var modal = pagelayer.$$('.pagelayer-command-palette-modal');
7913 + if (modal.length > 0) {
7914 + if (modal.is(':visible')) {
7915 + modal.hide();
7916 + pagelayer_is_command_palette_open = false;
7917 + } else {
7918 + modal.show().find('.pagelayer-cmd-input').focus().val('');
7919 + pagelayer_is_command_palette_open = true;
7920 + pagelayer_render_command_palette_results('');
7921 + }
7922 + return;
7923 + }
7924 +
7925 + // Create modal in parent window
7926 + var modalHtml = '<div class="pagelayer-command-palette-modal" style="position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: rgba(15, 23, 42, 0.4); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); z-index: 99999; display: flex; align-items: center; justify-content: center; font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;">' +
7927 + '<div class="pagelayer-cmd-container" style="width: 550px; background: #ffffff; border-radius: 12px; box-shadow: 0 20px 25px -5px rgba(0,0,0,0.1), 0 10px 10px -5px rgba(0,0,0,0.04); display: flex; flex-direction: column; overflow: hidden; border: 1px solid #e2e8f0; max-height: 450px;">' +
7928 + '<div class="pagelayer-cmd-search-bar" style="display: flex; align-items: center; padding: 14px 18px; border-bottom: 1px solid #f1f5f9; gap: 12px;">' +
7929 + '<i class="fas fa-search" style="color: #64748b; font-size: 16px;"></i>' +
7930 + '<input type="text" class="pagelayer-cmd-input" placeholder="Search widgets, actions, settings..." style="flex: 1; border: none; outline: none; font-size: 15px; color: #0f172a; padding: 0; background: transparent;" />' +
7931 + '<span style="font-size: 11px; background: #f1f5f9; color: #64748b; padding: 2px 6px; border-radius: 4px; border: 1px solid #cbd5e1;">ESC</span>' +
7932 + '</div>' +
7933 + '<div class="pagelayer-cmd-results" style="flex: 1; overflow-y: auto; padding: 8px 0; max-height: 380px;">' +
7934 + '</div>' +
7935 + '</div>' +
7936 + '</div>';
7937 +
7938 + pagelayer.$$('body').append(modalHtml);
7939 + modal = pagelayer.$$('.pagelayer-command-palette-modal');
7940 + pagelayer_is_command_palette_open = true;
7941 +
7942 + // Add dark mode support to command palette
7943 + if (pagelayer.$$('body').hasClass('pagelayer-dark')) {
7944 + modal.find('.pagelayer-cmd-container').css({ 'background': '#0b0f19', 'border-color': '#1e293b', 'color': '#f8fafc' });
7945 + modal.find('.pagelayer-cmd-search-bar').css({ 'border-bottom-color': '#1e293b' });
7946 + modal.find('.pagelayer-cmd-input').css({ 'color': '#f8fafc' });
7947 + modal.find('span').css({ 'background': '#1e293b', 'color': '#cbd5e1', 'border-color': '#334155' });
7948 + }
7949 +
7950 + modal.on('click', function(e) {
7951 + if (e.target === this) {
7952 + modal.hide();
7953 + pagelayer_is_command_palette_open = false;
7954 + }
7955 + });
7956 +
7957 + modal.find('.pagelayer-cmd-input').on('input', function() {
7958 + var q = jQuery(this).val();
7959 + pagelayer_render_command_palette_results(q);
7960 + });
7961 +
7962 + modal.find('.pagelayer-cmd-input').on('keydown', function(e) {
7963 + var results = modal.find('.pagelayer-cmd-item');
7964 + var active = modal.find('.pagelayer-cmd-item.active');
7965 +
7966 + if (e.key === 'ArrowDown') {
7967 + e.preventDefault();
7968 + if (active.length === 0 || active.is(':last-child')) {
7969 + results.removeClass('active').first().addClass('active').get(0).scrollIntoView({ block: 'nearest' });
7970 + } else {
7971 + active.removeClass('active').next().addClass('active').get(0).scrollIntoView({ block: 'nearest' });
7972 + }
7973 + } else if (e.key === 'ArrowUp') {
7974 + e.preventDefault();
7975 + if (active.length === 0 || active.is(':first-child')) {
7976 + results.removeClass('active').last().addClass('active').get(0).scrollIntoView({ block: 'nearest' });
7977 + } else {
7978 + active.removeClass('active').prev().addClass('active').get(0).scrollIntoView({ block: 'nearest' });
7979 + }
7980 + } else if (e.key === 'Enter') {
7981 + e.preventDefault();
7982 + if (active.length > 0) {
7983 + active.click();
7984 + }
7985 + } else if (e.key === 'Escape') {
7986 + modal.hide();
7987 + pagelayer_is_command_palette_open = false;
7988 + }
7989 + });
7990 +
7991 + modal.find('.pagelayer-cmd-input').focus();
7992 + pagelayer_render_command_palette_results('');
7993 +}
7994 +
7995 +function pagelayer_render_command_palette_results(query) {
7996 + var modal = pagelayer.$$('.pagelayer-command-palette-modal');
7997 + var resultsContainer = modal.find('.pagelayer-cmd-results');
7998 + resultsContainer.empty();
7999 +
8000 + query = query.toLowerCase().trim();
8001 + var items = [];
8002 +
8003 + // 1. Gather all shortcodes/widgets
8004 + var addedWidgets = {};
8005 +
8006 + // First, gather from pagelayer_groups to prioritize standard draggable widgets
8007 + for (var group in pagelayer_groups) {
8008 + for (var index in pagelayer_groups[group]) {
8009 + var key = pagelayer_groups[group][index];
8010 + if (addedWidgets[key]) continue;
8011 +
8012 + var sc = pagelayer_shortcodes[key];
8013 + if (!sc || !sc.name || 'not_visible' in sc) continue;
8014 +
8015 + if (query === '' || sc.name.toLowerCase().indexOf(query) > -1 || key.toLowerCase().indexOf(query) > -1) {
8016 + items.push({
8017 + type: 'widget',
8018 + title: sc.name,
8019 + subtitle: 'Add Widget',
8020 + key: key,
8021 + icon: sc.icon || '',
8022 + action: (function(k) {
8023 + return function() {
8024 + pagelayer_insert_widget(k);
8025 + };
8026 + })(key)
8027 + });
8028 + addedWidgets[key] = true;
8029 + }
8030 + }
8031 + }
8032 +
8033 + // Fallback to scan raw shortcodes to capture any miscellaneous widgets not categorized in sidebar groups
8034 + for (var key in pagelayer_shortcodes) {
8035 + if (addedWidgets[key]) continue;
8036 +
8037 + var sc = pagelayer_shortcodes[key];
8038 + if (!sc || !sc.name || 'not_visible' in sc) continue;
8039 +
8040 + if (query === '' || sc.name.toLowerCase().indexOf(query) > -1 || key.toLowerCase().indexOf(query) > -1) {
8041 + items.push({
8042 + type: 'widget',
8043 + title: sc.name,
8044 + subtitle: 'Add Widget',
8045 + key: key,
8046 + icon: sc.icon || '',
8047 + action: (function(k) {
8048 + return function() {
8049 + pagelayer_insert_widget(k);
8050 + };
8051 + })(key)
8052 + });
8053 + addedWidgets[key] = true;
8054 + }
8055 + }
8056 +
8057 + // 2. Gather editor actions
8058 + var actions = [
8059 + { title: 'Undo Last Edit', subtitle: 'History Action', icon: 'fas fa-undo', search: 'undo ctrl+z back', action: function() { pagelayer_do_history('undo'); } },
8060 + { title: 'Redo Edit', subtitle: 'History Action', icon: 'fas fa-redo', search: 'redo ctrl+y', action: function() { pagelayer_do_history('redo'); } },
8061 + { title: 'Switch to Desktop View', subtitle: 'Screen Mode', icon: 'fas fa-desktop', search: 'desktop screen responsive preview', action: function() { pagelayer_set_screen_mode('desktop'); } },
8062 + { title: 'Switch to Tablet View', subtitle: 'Screen Mode', icon: 'fas fa-tablet-alt', search: 'tablet screen responsive preview', action: function() { pagelayer_set_screen_mode('tablet'); } },
8063 + { title: 'Switch to Mobile View', subtitle: 'Screen Mode', icon: 'fas fa-mobile-alt', search: 'mobile screen responsive preview phone', action: function() { pagelayer_set_screen_mode('mobile'); } },
8064 + { title: 'Open Revisions & History', subtitle: 'Revision History', icon: 'fas fa-history', search: 'history revisions undo changes', action: function() { pagelayer.$$('.pagelayer-history-icon').click(); } },
8065 + { title: 'Save Page Changes', subtitle: 'Update Page', icon: 'fas fa-save', search: 'save update publish commit ctrl+s', action: function() { pagelayer.$$('.pagelayer-update-button').click(); } },
8066 + { title: 'Open Navigator / Elements Tree', subtitle: 'Navigator Panel', icon: 'fas fa-sitemap', search: 'navigator tree hierarchy layers structure outline', action: function() { pagelayer.$$('.pagelayer-navigator-icon').click(); } }
8067 + ];
8068 +
8069 + actions.forEach(function(act) {
8070 + if (query === '' || act.title.toLowerCase().indexOf(query) > -1 || act.search.indexOf(query) > -1) {
8071 + items.push({
8072 + type: 'action',
8073 + title: act.title,
8074 + subtitle: act.subtitle,
8075 + icon: act.icon,
8076 + action: act.action
8077 + });
8078 + }
8079 + });
8080 +
8081 + if (items.length === 0) {
8082 + resultsContainer.html('<div style="text-align: center; color: #64748b; padding: 24px 0; font-size: 14px;">No results found. Try another query.</div>');
8083 + return;
8084 + }
8085 +
8086 + var slice = items.slice(0, 100);
8087 + var isDark = pagelayer.$$('body').hasClass('pagelayer-dark');
8088 +
8089 + slice.forEach(function(item, idx) {
8090 + var iconClass = '';
8091 + if (item.type === 'widget') {
8092 + if (item.icon) {
8093 + iconClass = 'pagelayer-shortcode ' + item.icon;
8094 + } else {
8095 + iconClass = 'pagelayer-shortcode pli pagelayer-' + item.key;
8096 + }
8097 + } else {
8098 + iconClass = item.icon;
8099 + }
8100 + var itemHtml = jQuery('<div class="pagelayer-cmd-item ' + (idx === 0 ? 'active' : '') + '" style="display: flex; align-items: center; padding: 10px 18px; cursor: pointer; transition: background 0.15s, color 0.15s; gap: 14px; font-size: 14px;">' +
8101 + '<div class="pagelayer-cmd-icon" style="width: 28px; height: 28px; background: ' + (isDark ? '#1e293b' : '#f1f5f9') + '; border-radius: 6px; display: flex; align-items: center; justify-content: center; color: #2563eb; font-size: 16px;"><i class="' + iconClass + '"></i></div>' +
8102 + '<div style="flex: 1; display: flex; flex-direction: column;">' +
8103 + '<span style="font-weight: 500; color: ' + (isDark ? '#f8fafc' : '#0f172a') + ';">' + item.title + '</span>' +
8104 + '<span style="font-size: 11px; color: #64748b;">' + item.subtitle + '</span>' +
8105 + '</div>' +
8106 + '</div>');
8107 +
8108 + var hoverBg = isDark ? '#1e293b' : '#f8fafc';
8109 +
8110 + itemHtml.hover(function() {
8111 + modal.find('.pagelayer-cmd-item').removeClass('active');
8112 + jQuery(this).addClass('active');
8113 + });
8114 +
8115 + itemHtml.on('click', function() {
8116 + modal.hide();
8117 + pagelayer_is_command_palette_open = false;
8118 + item.action();
8119 + });
8120 +
8121 + resultsContainer.append(itemHtml);
8122 + });
8123 +
8124 + var styleTag = pagelayer.$$('head #pagelayer-cmd-palette-styles');
8125 + if (styleTag.length === 0) {
8126 + pagelayer.$$('head').append('<style id="pagelayer-cmd-palette-styles">' +
8127 + '.pagelayer-cmd-item.active { background: ' + (isDark ? '#1e293b !important' : '#f1f5f9 !important') + '; }' +
8128 + '</style>');
8129 + }
8130 +}
8131 +
8132 +// Programmatic widget placement
8133 +function pagelayer_insert_widget(tag) {
8134 + var active = pagelayer_active.el;
8135 + var parentCol = null;
8136 + var target = null;
8137 + var method = 'append';
8138 +
8139 + if (active && active.$) {
8140 + var tag_active = pagelayer_tag(active.$);
8141 + if (tag_active === 'pl_col') {
8142 + parentCol = active.$.find('>.pagelayer-col-holder');
8143 + method = 'append';
8144 + } else if (tag_active === 'pl_row' || tag_active === 'pl_inner_row') {
8145 + parentCol = active.$.find('.pagelayer-col-holder').first();
8146 + method = 'append';
8147 + } else {
8148 + target = active.$.closest('.pagelayer-ele-wrap');
8149 + method = 'after';
8150 + }
8151 + } else {
8152 + parentCol = jQuery(pagelayer_editable).find('.pagelayer-col-holder').first();
8153 + method = 'append';
8154 + }
8155 +
8156 + if ((!parentCol || parentCol.length === 0) && (!target || target.length === 0)) {
8157 + var row = jQuery('<div pagelayer-tag="pl_row"></div>');
8158 + jQuery(pagelayer_editable).append(row);
8159 + var rowId = pagelayer_onadd(row, false);
8160 + var rEle = pagelayer_ele_by_id(rowId);
8161 +
8162 + var col = jQuery('<div pagelayer-tag="pl_col"></div>');
8163 + rEle.find('.pagelayer-row-holder').append(col);
8164 + var colId = pagelayer_onadd(col, false);
8165 + var cEle = pagelayer_ele_by_id(colId);
8166 + parentCol = cEle.find('.pagelayer-col-holder');
8167 + method = 'append';
8168 + }
8169 +
8170 + var ele = jQuery('<div pagelayer-tag="' + tag + '"></div>');
8171 + if (method === 'append') {
8172 + parentCol.append(ele);
8173 + pagelayer_empty_col(parentCol);
8174 + } else {
8175 + target.after(ele);
8176 + pagelayer_empty_col(target.closest('.pagelayer-col-holder'));
8177 + }
8178 +
8179 + var newId = pagelayer_onadd(ele, true);
8180 + pagelayer_do_dirty(ele);
8181 +}
8182 +