PluginProbe
Page Builder: Pagelayer – Drag and Drop website builder / 2.1.4
Page Builder: Pagelayer – Drag and Drop website builder v2.1.4
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 1.0.5 All 129 releases
pagelayer / js / pagelayer-editor.js

pagelayer-editor.js in Page Builder: Pagelayer – Drag and Drop website builder 2.1.4, at js/pagelayer-editor.js

8,168 lines 221.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /*
2 PAGELAYER
3 http://pagelayer.com/
4 (c) Pagelayer Team
5 */
6
7 pagelayer = {
8 $: jQuery,
9 $$ : function(select){
10 return jQuery(select, window.parent.document);
11 },
12 gDocument : jQuery(window.parent.document).add(document),
13 p : this,
14 copy_selected: '',
15 mouse: {x: -1, y: -1},
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
24 }
25
26 var pagelayer_history_obj = {}, pagelayer_revision_obj = {};
27 var pagelayer_add_section_data = {};
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
97 // Lets start
98 jQuery(document).ready(pagelayer_start);
99
100 // Function to load the codes
101 function pagelayer_start(){
102
103 pagelayer.loading = 1;
104 console.log('['+pagelayer_brand+'] Starting Pagelayer');
105
106 // Prevent the click Insite editor
107 pagelayer_prevent_click();
108
109 // Set the title of the parent window
110 try{ pagelayer.$$('head').append(pagelayer.$('title')[0].outerHTML); }catch(e){};
111
112 pagelayer.blank_img = pagelayer_url+'/images/default-image.png';
113
114 pagelayer_shortcodes['pl_inner_row'] = JSON.parse(JSON.stringify(pagelayer_shortcodes['pl_row']));
115 pagelayer_shortcodes['pl_inner_row']['name'] = 'Inner Row';
116 pagelayer_groups['grid'].push('pl_inner_row');
117
118 // Removing post props options
119 pagelayer_setting_post_props();
120
121 // Make the Topbar
122 pagelayer_bottombar();
123
124 // Make the Leftbar
125 pagelayer_leftbar();
126
127 // Make widget list toolbar
128 pagelayer_create_widget_tooltip();
129
130 // Add widget section
131 pagelayer_add_widget();
132
133 // Setup the ELPD
134 pagelayer_elpd_setup();
135
136 // Dump the data we have
137 pagelayer_element_dump_data();
138
139 // Setup the properties of the elements
140 pagelayer_element_setup();
141
142 // An image to show for drag
143 jQuery('body').append('<img src="'+pagelayer_url+'/images/drag-ghost.png" class="pagelayer-drag-show" />');
144
145 // Setup the grid drag
146 pagelayer_setup_drag();
147
148 // Set left bar draggable
149 pagelayer_make_leftbar_movable();
150
151 // Set to desktop
152 pagelayer_set_screen_mode('desktop');
153
154 // Create list of fonts
155 pagelayer_fonts = pagelayer_l('pl_fonts_list');
156
157 // Set up right click
158 pagelayer_left_click();
159 pagelayer_right_click();
160
161 // Setup pagelayer history handle
162 pagelayer_history_obj['action_data'] = [];
163 pagelayer_history_setup(true);
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
171 // Do any actions here
172 pagelayer_trigger_action('pagelayer_setup_history');
173
174 // Editor Tooltips
175 pagelayer_tooltip_setup();
176
177 // Load Fonts
178 for(var x in pagelayer_loaded_icons){
179 var item = pagelayer_loaded_icons[x];
180 jQuery.when(
181 pagelayer_get_stored_data(pagelayer_url+'/fonts/'+item+'.json', pagelayer_ver)
182 ).then(function(){
183 pagelayer_icons[item] = JSON.parse(pagelayer_get_stored_data(pagelayer_url+'/fonts/'+item+'.json', pagelayer_ver));
184 });
185 };
186
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 }
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
431 // The jQuery Object of the ELPD
432 var pagelayer_elpd;
433
434 // Store data values
435 function pagelayer_get_stored_data(url, version){
436 var name = 'pagelayer_'+url;
437 var data = {};
438 var force = false;
439
440 // Try to parse the data
441 try{
442 data = JSON.parse(localStorage.getItem(name));
443
444 if(data['version'] !== version){
445 force = true;
446 }
447
448 }catch(e){
449 force = true;
450 }
451
452 // Force download
453 if(force){
454 return jQuery.ajax({
455 url: url,
456 type: 'GET',
457 dataType: 'text',
458 success:function(newData){
459 var data = {};
460 data['version'] = version;
461 data['val'] = newData;
462 localStorage.setItem(name, JSON.stringify(data));
463 }
464 });
465 }
466
467 return data['val'];
468
469 }
470
471 function pagelayer_closest_corner(jEle){
472 var corners = [];
473 var w = jEle.outerWidth();
474 var h = jEle.outerHeight();
475 var topleft = jEle.offset();
476
477 // 0 - Top Left
478 corners.push(topleft);
479
480 // 1 - Top Right
481 corners.push({top: topleft.top, left: topleft.left+w});
482
483 // 2 - Bottom Right
484 corners.push({top: topleft.top+h, left: topleft.left+w});
485
486 // 3 - Bottom Left
487 corners.push({top: topleft.top+h, left: topleft.left});
488
489 //console.log(corners);
490
491 // Calculate the closest to the mouse
492 var distances = {};
493 for(var c in corners){
494 var dist = Math.hypot(pagelayer.mouse.x - corners[c].left, pagelayer.mouse.y - corners[c].top);
495 distances[c] = dist;
496 }
497 //console.log(distances);
498
499 var corner = Object.keys(distances).sort(function(a,b){return distances[a]-distances[b]})[0];
500 //console.log(corner);
501
502 return corner;
503
504 };
505
506 // Make left bar draggable
507 function pagelayer_make_leftbar_movable(){
508 var pl_iframe = pagelayer.$$('.pagelayer-iframe'),
509 pl_leftbar = pagelayer.$$('.pagelayer-leftbar-table');
510
511 // On mouse down in pagelayer-topbar-holder
512 pagelayer.$$('.pagelayer-topbar-mover').on('mousedown', function(e){
513 e = e || window.event;
514 e.preventDefault();
515
516 // Get leftbar position
517 var orig_eleX = pl_leftbar.offset().left;
518 var orig_eleY = pl_leftbar.offset().top;
519
520 // Get the mouse cursor position at startup:
521 var posX = e.clientX;
522 var posY = e.clientY;
523
524 // The variable needs to be empty.
525 var newMethod = '',
526 change = true;
527
528 var leftbar_mousemove = function(e){
529 e = e || window.event;
530
531 if(change){
532 // Add class to leftbar
533 pl_leftbar.addClass('pagelayer-leftbar-moving');
534
535 // Add left-right overlay
536 pl_iframe.before('<div class="pagelayer-leftbar-move pagelayer-moveto-left"></div>');
537 pl_iframe.after('<div class="pagelayer-leftbar-move pagelayer-moveto-right"></div>');
538 pagelayer.$$('body').addClass('pagelayer-overflow-hidden');
539 change = false;
540 }
541
542 // calculate the new cursor position and set the element left-top position
543 var top = orig_eleY + (e.clientY - posY);
544 var left = orig_eleX + (e.clientX - posX);
545
546 // set the element's new position:
547 pl_leftbar.css({'top': top +'px','left': left +'px'});
548 pagelayer.$$('.pagelayer-leftbar-toggle').hide();
549
550 // Make a copy of new method
551 var _newMethod = newMethod;
552 newMethod = '';
553
554 // Get near by corner
555 var offleft = pl_iframe.offset().left;
556
557 if(offleft + 100 > e.clientX){
558 newMethod = 'before';
559 }else if(offleft+pl_iframe.outerWidth()- 100 < e.clientX){
560 newMethod = 'after';
561 }
562
563 if(_newMethod != newMethod){
564 pagelayer.$$('.pagelayer-leftbar-move').css({'width' :'', 'opacity': '0.33'});
565
566 if(newMethod == 'after'){
567 pagelayer.$$('.pagelayer-moveto-right').animate({'width' :'60px', 'opacity': '0.66'}, 200);
568 pl_leftbar.addClass('pagelayer-rightbar');
569 }else if(newMethod == 'before'){
570 pagelayer.$$('.pagelayer-moveto-left').animate({'width' : '60px', 'opacity': '0.66'}, 200);
571 pl_leftbar.removeClass('pagelayer-rightbar');
572 }
573 }
574
575 };
576
577 var leftbar_mouseup = function(e){
578
579 // Remove events
580 pagelayer.gDocument.off('mousemove', leftbar_mousemove);
581 pagelayer.gDocument.off('mouseup', leftbar_mouseup);
582
583 // Remove class to leftbar
584 pagelayer.$$('.pagelayer-leftbar-move').remove();
585
586 var windowHeight = jQuery(window).height();
587
588 if(pl_leftbar.offset().top < 0){
589 pl_leftbar.css({'top': '10px'});
590 }else if( (windowHeight - e.clientY) < 10){
591 pl_leftbar.css({'top': ''+windowHeight - 40+'px'});
592 }
593
594 if( !pagelayer_empty(newMethod)){
595 pl_leftbar.removeClass('pagelayer-leftbar-moving');
596 pl_leftbar.removeAttr('style');
597 pagelayer.$$('.pagelayer-leftbar-toggle').show();
598 pagelayer.$$('body').removeClass('pagelayer-overflow-hidden');
599 pl_iframe[newMethod](pl_leftbar);
600 }
601
602 // make change true
603 change = true;
604 };
605
606 pagelayer.gDocument.on('mouseup', leftbar_mouseup);
607 pagelayer.gDocument.on('mousemove', leftbar_mousemove);
608
609 });
610
611 }
612
613 // Make rows and cols draggable
614 function pagelayer_setup_drag(){
615
616 // The object to show as drag
617 var shower = jQuery('.pagelayer-drag-show');
618
619 // Delete any prospect
620 var clear_prospect = function(){
621 jQuery('.pagelayer-drag-prospect').remove();
622
623 // Shows the wrap as active
624 jQuery('.pagelayer-drag-ele-hover').removeClass('pagelayer-drag-ele-hover');
625 }
626
627 // Reset the complete drag stuff
628 var reset_dragging = function(){
629 pagelayer.dragging = false;
630 pagelayer.drag_is_new = false;
631 pagelayer.drag_mouse = {x: 0, y: 0};
632 reset_on_drag();
633 }
634
635 // Reset the element on you were last
636 var reset_on_drag = function(){
637 pagelayer.drag_closest = false;
638 pagelayer.drag_closest_corner = null;
639 }
640
641 // Scroll by
642 var scrollPx = 7;
643 var scrollDist = 30;
644
645 // If we are too close too the window edge, then scroll
646 var handle_scroll = function(e){
647
648 var windowHeight = jQuery(window).height();
649 var windowWidth = jQuery(window).width();
650
651 // Are we to close to the top or bottom
652 if(e.clientY < scrollDist){
653 window.scrollBy(0, -scrollPx);
654 }else if((windowHeight - e.clientY) < scrollDist){
655 window.scrollBy(0, scrollPx);
656 }
657
658 // Are we to close to the top or bottom
659 if(e.clientX < scrollDist){
660 window.scrollBy(-scrollPx, 0);
661 }else if((windowWidth - e.clientX) < scrollDist){
662 window.scrollBy(scrollPx, 0);
663 }
664
665 }
666
667 // SET the values
668 reset_dragging();
669
670 var ondragover = function(e) {
671 //console.log(e);
672
673 pagelayer.mouse.x = parseInt(e.pageX);
674 pagelayer.mouse.y = parseInt(e.pageY);
675 //console.log(pagelayer.mouse);
676
677 // Are we dragging ?
678 if(pagelayer.dragging){
679
680 //console.log(e);
681
682 e.preventDefault();
683 //e.stopPropagation();
684
685 // The wrap of the element being dragged
686 var wrap = pagelayer.dragging;
687
688 // New addition
689 var is_new = pagelayer.drag_is_new;
690 var ele;
691 var tag = pagelayer_tag(wrap);
692 var id = pagelayer_id(wrap);
693
694 // If existing element then add we are dragging
695 if(!is_new){
696
697 // Start Dragging
698 if(!wrap.hasClass('pagelayer-is-dragging')){
699 wrap.addClass('pagelayer-is-dragging');
700 }
701
702 //shower.hide();
703
704 ele = document.elementFromPoint(e.clientX, e.clientY);
705 //console.log(ele);
706
707 // Drag the show object
708 //shower.show();
709 //var offset = {top: (e.pageY-10)+'px', left: (e.pageX-10)+'px'}
710 //shower.css(offset);
711
712 }else{
713 ele = document.elementFromPoint(e.clientX, e.clientY);
714 }
715 //console.log(e);
716
717 // Have we moved more than 5px;
718 var dist = Math.hypot(pagelayer.mouse.x - pagelayer.drag_mouse.x, pagelayer.mouse.y - pagelayer.drag_mouse.y);
719 //console.log(dist);
720 /*if(dist && dist < 5){
721 return false;
722 }*/
723
724 // Handle the scroll
725 handle_scroll(e);
726
727 // Find the closest wrap
728 var onWrap;
729
730 // If we are a column, we can be over another column or row
731 if(tag == 'pl_col'){
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 }
745 //console.log(pagelayer_id(onWrap));
746
747 // If we are a row, we can be over another row or a column
748 }else if(tag == 'pl_row'){
749 onWrap = jQuery(ele).closest('.pagelayer-wrap-row');
750 //console.log(pagelayer_id(onWrap));
751
752 // For inner row we restrict to 1 level only
753 }else if(tag == 'pl_inner_row'){
754
755 var ele_wrap = jQuery(ele).parents('.pagelayer-wrap-col');
756 if(
757 (ele_wrap.length == 1 && !jQuery(ele).hasClass('pagelayer-wrap-col')) ||
758 (ele_wrap.length == 0 && jQuery(ele).hasClass('pagelayer-wrap-col'))
759 ){
760 onWrap = jQuery(ele).closest('.pagelayer-wrap-ele,.pagelayer-wrap-col,.pagelayer-wrap-inner-row');
761 }else{
762 onWrap = jQuery(ele).closest('.pagelayer-wrap-inner-row');
763 }
764 // For every other element, we can be over a col or ele
765 }else{
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 }
829 }
830 //console.log(onWrap);
831
832 // If we find nothing
833 if(pagelayer_empty(onWrap) || onWrap.length < 1){
834 clear_prospect();// Clear existing prospects
835 reset_on_drag();// Also reset the last on item
836 return false;
837 }
838
839 /*// If the columns more than 12 inside the row then return - As of now not enabled the below code
840 if(tag == 'pl_col'){
841 var _onTag = pagelayer_tag(onWrap);
842 var colEles;
843
844 // Is on col
845 if(_onTag == 'pl_col'){
846 colEles = onWrap.closest('.pagelayer-row-holder').children('.pagelayer-ele-wrap');
847 }else{
848 colEles = onWrap.find('.pagelayer-row-holder').first().children('.pagelayer-ele-wrap');
849 }
850
851 // If the columns more than 12
852 if(colEles.length >= 12){
853 return false;
854 }
855 }*/
856
857 // Get the ID
858 var onId = pagelayer_id(onWrap);
859 var onEle = pagelayer_ele_by_id(onId);
860
861 // Do we have a parent ?
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
869 onId = pOnId;
870 onEle = pagelayer_ele_by_id(pOnId);
871 onWrap = pagelayer_wrap_by_id(pOnId);
872 have_parent(onEle);
873
874 }
875
876 // Do we have a parent ?
877 have_parent(onEle);
878
879 var changed = false;
880
881 // Was it the same ID like the one we were on before
882 if(pagelayer.drag_closest != onId){
883 pagelayer.drag_closest = onId;
884 changed = true;
885 }
886 //console.log(onId+' '+pagelayer.drag_closest)
887
888 var req_corners = {0: 'top', 1: 'top', 2: 'bottom', 3: 'bottom'};
889
890 // For columns we redefine the top and bottom
891 if(tag == 'pl_col'){
892 req_corners[1] = 'bottom';
893 req_corners[3] = 'top';
894 }
895
896 // Determine the previous and next
897 var next = wrap.next('.pagelayer-ele-wrap');
898 var prev = wrap.prev('.pagelayer-ele-wrap');
899
900 if(next.length == 1 && pagelayer_id(next) == onId){
901 req_corners = {0: 'bottom', 1: 'bottom', 2: 'bottom', 3: 'bottom'};
902 }
903
904 if(prev.length == 1 && pagelayer_id(prev) == onId){
905 req_corners = {0: 'top', 1: 'top', 2: 'top', 3: 'top'};
906 }
907
908 // Which corner are we closest to ?
909 var corner_num = pagelayer_closest_corner(onWrap);
910 var corner = req_corners[corner_num];
911
912 //console.log(corner+' != '+pagelayer.drag_closest_corner)
913 if(corner != pagelayer.drag_closest_corner){
914 pagelayer.drag_closest_corner = corner;
915 changed = true;
916 }
917
918 //console.log(changed);
919
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')){
922 clear_prospect();// Clear existing prospects
923 reset_on_drag();// Also reset the last on item
924 return false;
925 }
926
927 // Then lets start showing
928 if(changed){
929
930 // Record the mouse points
931 pagelayer.drag_mouse.x = parseInt(e.pageX);
932 pagelayer.drag_mouse.y = parseInt(e.pageY);
933
934 // Clear any existing prospect
935 clear_prospect();
936
937 // Add new prospect
938 var prospect = '<div class="pagelayer-drag-prospect" pagelayer-corner="'+corner+'"></div>';
939
940 if(corner == 'bottom'){
941 onWrap.append(prospect);
942 }else if(corner == 'top'){
943 onWrap.prepend(prospect);
944 }
945
946 prospect = jQuery('.pagelayer-drag-prospect')
947 var animate_props = {height: '5px'};
948
949 // For column add a special class
950 if(tag == 'pl_col'){
951 prospect.addClass('pagelayer-drag-prospect-col');
952 animate_props['width'] = '5px';
953
954 // Adjust the left and right
955 var css = {};
956 css[(corner == 'bottom' ? 'right' : 'left')] = '0px';
957 prospect.css(css);
958 }
959
960 // Animate the prospect
961 prospect.animate(animate_props, 200);
962
963 // Highlight the wrap via overlay
964 onWrap.children('.pagelayer-ele-overlay').addClass('pagelayer-drag-ele-hover');
965
966 }
967
968 }
969 }
970
971 // When mouse is pressed down
972 var ondragstart = function(e){
973
974 //console.log(e);
975
976 // Target
977 var tEle = jQuery(e.target);
978 var wrap = tEle.closest('.pagelayer-ele-wrap');
979 //console.log(jEle[0]);
980
981 // Is it an existing element ?
982 if(wrap.length < 1){
983 return false;
984 }
985
986 // Do we have a parent ?
987 var id = pagelayer_id(wrap);
988 var jEle = pagelayer_ele_by_id(id);
989 var pId = pagelayer_get_parent(jEle);
990
991 if(pId){
992 wrap = pagelayer_wrap_by_id(pId);
993 }
994
995 //e.preventDefault();
996
997 var tag = pagelayer_tag(wrap);
998
999 e.originalEvent.dataTransfer.setData('Text', 1);
1000 var img = document.createElement('img');
1001 img.src = shower.attr('src');
1002 e.originalEvent.dataTransfer.setDragImage(img, 32, 32);
1003
1004 pagelayer.dragging = wrap;
1005
1006 }
1007
1008 // When mouse is pressed down
1009 var ondrop = function(e){
1010
1011 //console.log(e);
1012
1013 // Stop dragging ?
1014 if(pagelayer.dragging){
1015
1016 e.preventDefault();
1017
1018 var wrap = pagelayer.dragging;
1019 var tag = pagelayer_tag(wrap);
1020 var gId = wrap.attr('pagelayer-global-id');
1021 var fromEl = wrap.parent();
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
1029 wrap.removeClass('pagelayer-is-dragging');
1030
1031 // Find any prospect
1032 var prospect = jQuery('.pagelayer-drag-prospect');
1033 //console.log(prospect[0]);
1034
1035 // It should be exactly 1
1036 if(prospect.length == 1){
1037
1038 var onWrap = prospect.parent();
1039 var onId = pagelayer_id(onWrap);
1040 var onTag = pagelayer_tag(onWrap);
1041 var dropped;
1042 var corner = prospect.attr('pagelayer-corner');
1043 var method = (corner == 'top') ? 'before' : 'after';
1044 var before_loc; // Location before the drop
1045
1046 // Create the element if it needs to be created
1047 if(pagelayer.drag_is_new){
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 }
1054
1055 // Move the object
1056 }else{
1057
1058 // Get near by element before move
1059 before_loc = pagelayer_near_by_ele(pagelayer_id(wrap), tag);
1060
1061 dropped = wrap;
1062 dropped.detach();
1063 }
1064
1065 // If I am a column or row, then I go only before or after my same type !
1066 if((onTag == 'pl_col' || onTag == 'pl_row') && onTag == tag){
1067
1068 // If I am a column and I am on a row
1069 // OR I am a normal element and I am on column
1070 }else if((tag == 'pl_col' && (onTag == 'pl_row' || onTag == 'pl_inner_row')) || onTag == 'pl_col'){
1071 // We need to find the holder and add the prospect there
1072 var holder = pagelayer_shortcodes[onTag]['holder'];
1073 onWrap = onWrap.children('.pagelayer-ele').children(holder);
1074 method = (corner == 'top') ? 'prepend' : 'append';
1075 }
1076
1077 // Attach or shift the element
1078 onWrap[method](dropped);
1079 //console.log(dropped);
1080
1081 // Trigger the onadd
1082 if(pagelayer.drag_is_new){
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 }
1091
1092 // Existing elements
1093 }else{
1094 id = pagelayer_id(wrap);
1095
1096 // Save in action history
1097 pagelayer_history_action_push({
1098 'title' : pagelayer_shortcodes[tag]['name'],
1099 'action' : 'Moved',
1100 'pl_id' : id,
1101 'before_loc' : before_loc,
1102 'after_loc' : {'method' : method, 'cEle' : onWrap}
1103 });
1104
1105 pagelayer_do_dirty(pagelayer_ele_by_id(id));
1106 }
1107
1108 // Defining the variables as needed
1109 var jEle = pagelayer_ele_by_id(id);
1110 wrap = pagelayer_wrap_by_id(id);
1111 var toEl = wrap.parent();
1112
1113 // Column number handle
1114 if(tag == 'pl_col'){
1115
1116 var row_holder = jEle.parent().closest('.pagelayer-row-holder');
1117
1118 // Renumber the col where you are going
1119 pagelayer_renumber_col(row_holder);
1120
1121 // Renumber the old columns as well
1122 if(!pagelayer.drag_is_new){
1123 var from_row = fromEl.closest('.pagelayer-row-holder');
1124 pagelayer_renumber_col(from_row);
1125 }
1126 }
1127
1128 // Handle the empty col
1129 if(tag != 'pl_col'){
1130
1131 pagelayer_empty_col(toEl.closest('.pagelayer-col-holder'));
1132
1133 if(!pagelayer.drag_is_new){
1134 pagelayer_empty_col(fromEl.closest('.pagelayer-col-holder'));
1135 }
1136
1137 }
1138
1139 }
1140
1141 // Clear prospect
1142 clear_prospect();
1143 }
1144
1145 reset_dragging();
1146
1147 }
1148
1149 // Add the events for inner content - as we are using the drag API
1150 jQuery(document).on('dragstart', ondragstart);
1151 jQuery(document).on('dragover', ondragover);
1152 jQuery(document).on('drop', ondrop);
1153
1154 // For addition of new elements
1155 pagelayer.$$('.pagelayer-leftbar').on('dragstart', function(e){
1156 //console.log(e);
1157
1158 var tEle = jQuery(e.target);
1159 var jEle = tEle.closest('.pagelayer-shortcode-drag');
1160 var global_id = jEle.attr('pagelayer-global-id');
1161
1162 // Is it an existing element ?
1163 if(jEle.length < 1){
1164 return false;
1165 }
1166
1167 e.originalEvent.dataTransfer.setData('tag', pagelayer_tag(jEle));
1168
1169 if(!pagelayer_empty(global_id)){
1170 e.originalEvent.dataTransfer.setData( 'global_id', global_id );
1171 }
1172
1173 pagelayer.dragging = jEle;
1174 pagelayer.drag_is_new = true;
1175
1176 });
1177
1178 // Handle editable content by removing drag
1179 var onmousedown = function(e){
1180
1181 var tEle = jQuery(e.originalEvent.explicitOriginalTarget);
1182
1183 if(tEle.closest('[pagelayer-editable]').length > 0){
1184 //console.log('Is Editable MouseDown');
1185 tEle.parents('[draggable]').attr('draggable', 'false');
1186 }
1187
1188 }
1189
1190 // Handle editable content by adding drag that was removed
1191 var onmouseup = function(e){
1192 jQuery(document).find('[draggable=false]').attr('draggable', 'true');
1193 }
1194
1195 // Handle editable contents by temprarily removing drag
1196 jQuery(document).on('mousedown', onmousedown);
1197 jQuery(document).on('mouseup', onmouseup);
1198
1199 };
1200
1201 // Handle empty col
1202 // selector should be col holder
1203 function pagelayer_empty_col(selector){
1204
1205 // Loop through
1206 jQuery(selector).each(function(){
1207
1208 var jEle = jQuery(this);// jEle is the COL HOLDER
1209
1210 // Are we a col ?
1211 if(!jEle.hasClass('pagelayer-col-holder')){
1212 return;
1213 }
1214
1215 // Column is becoming blank, so show add ele
1216 if(jEle.children().length < 1){
1217 //from.addClass('pagelayer-empty-col');
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>');
1219 //var h = jEle.parent().parent().children('.pagelayer-ele-overlay').height();
1220 //jEle.children('.pagelayer-add-ele').height(h);
1221
1222 // Any add ele sign with non-empty columns here ?
1223 }else if(jEle.children('.pagelayer-add-ele').length > 0 && jEle.children().length > 1){
1224 jEle.children('.pagelayer-add-ele').remove();
1225 }
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
1235 });
1236
1237 };
1238
1239 // Reset the column widths
1240 // The selector should be a ROW HOLDER
1241 function pagelayer_renumber_col(selector){
1242
1243 var pEle = jQuery(selector);
1244 var children = pEle.children('.pagelayer-ele-wrap');
1245 var cols = Math.floor(12 / (children.length));
1246 var obj = {col: cols};
1247
1248 // Find out the number of cols of other cols
1249 children.each(function(){
1250
1251 // This is the wrapper
1252 var jEle = jQuery(this);
1253
1254 // The real element
1255 var Ele = jEle.find('>.pagelayer-ele');
1256
1257 for(var x=1; x<=12; x++){
1258 if(jEle.hasClass('pagelayer-col-'+x)){
1259 jEle.removeClass('pagelayer-col-'+x);
1260 Ele.removeClass('pagelayer-col-'+x);
1261 break;
1262 }
1263 }
1264 jEle.addClass('pagelayer-col-'+cols);
1265 jEle.css({'width': ''});
1266
1267 // Set the att
1268 pagelayer_set_atts(Ele, obj);
1269 pagelayer_set_atts(Ele, 'col_width','');
1270 pagelayer_sc_render(Ele)
1271 });
1272 }
1273
1274 // Make column resizable handler
1275 function pagelayer_col_make_resizable(wrap){
1276
1277 // Resize handler element
1278 var rHandler = jQuery('<div class="pagelayer-resize-handler"><div class="pagelayer-resize-icon"></div></div>');
1279
1280 var pResize = wrap.children('.pagelayer-ele-overlay').find('.pagelayer-resize-handler');
1281
1282 if(pResize.length > 0){
1283 return;
1284 }
1285
1286 // Append it
1287 wrap.children('.pagelayer-ele-overlay').append(rHandler);
1288
1289 // Resize start
1290 rHandler.on('mousedown', function(e) {
1291 e.preventDefault();
1292
1293 var next_ele = wrap.next();
1294 var rHolder_width = wrap.closest('.pagelayer-row-holder').width();
1295 var new_width, nEle_new_width;
1296
1297 // Original 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'));
1300 var original_mouse_x = e.pageX;
1301
1302 var both_width = parseInt(original_width + next_ele_width);
1303
1304 // Add the element width and next element width
1305 both_width = ((both_width / rHolder_width) *100);
1306
1307 if(both_width > 100){
1308 return false;
1309 }
1310
1311 jQuery('body').css({'cursor': 'ew-resize'});
1312 rHandler.css({'display': 'block'});
1313
1314 var mousemoved = false;
1315
1316 var r_mousemove = function(e){
1317 mousemoved = true;
1318
1319 var width = original_width + (e.pageX - original_mouse_x);
1320
1321 // Covert width in percentage
1322 new_width = (width / rHolder_width *100).toFixed(2);
1323
1324 if(both_width > new_width && new_width > 0){
1325 nEle_new_width = (both_width - new_width).toFixed(2);
1326 wrap.css({'width': new_width+'%'});
1327 next_ele.css({'width': nEle_new_width+'%'});
1328
1329 rHandler.attr({'pre-width': new_width+'%', 'next-width': nEle_new_width+'%'});
1330 }
1331
1332 };
1333
1334 var r_mouseup = function(e){
1335
1336 jQuery(document).off('mousemove', r_mousemove);
1337 jQuery(document).off('mouseup', r_mouseup);
1338 jQuery('body').css({'cursor': ''});
1339 rHandler.removeAttr('style pre-width next-width');
1340
1341 // IF mouseMoved
1342 if(!mousemoved) return;
1343
1344 // find real element and next real element
1345 var jEle = wrap.find('>.pagelayer-ele');
1346 var nEle = next_ele.find('>.pagelayer-ele');
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
1355 // Set the element attrs
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', '');
1360
1361 };
1362
1363 // Resize start
1364 jQuery(document).on('mousemove', r_mousemove);
1365 jQuery(document).on('mouseup', r_mouseup);
1366 });
1367 }
1368
1369 // Handle addition of elements from the left
1370 // NOTE : At this point the addition is FINALIZED
1371 // The add element cannot be prevented !
1372 function pagelayer_onadd(jEle, toClick){
1373
1374 toClick = arguments.length == 2 ? toClick : true;
1375
1376 //console.log(jEle);
1377 var id = pagelayer_element_added(jEle);
1378 var jEle = jQuery("[pagelayer-id="+id+"]");
1379
1380 if(toClick){
1381 //console.log('here');
1382 jEle.click();
1383 }
1384
1385 return id;
1386
1387 };
1388
1389 // Add an element into the POST
1390 function pagelayer_element_added(jEle){
1391
1392 var sc = jEle.attr('pagelayer-tag');
1393 var id, par_id;
1394 var gId = jEle.attr('pagelayer-global-id');
1395 gId = gId && !pagelayer_empty(pagelayer_global_widgets[gId]) ? gId : 0;
1396
1397 // Set Pagelayer History FALSE to prevent saving attributes in action history
1398 pagelayer.history_action = false;
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
1406 // Generate the HTML
1407 }else{
1408 html = pagelayer_create_sc(sc);
1409 }
1410
1411 id = pagelayer_assign_id(html);
1412 par_id = id;
1413
1414 // Insert the HTML
1415 jEle[0].outerHTML = html[0].outerHTML;
1416
1417 // Setup the properties of the elements
1418 pagelayer_element_setup("[pagelayer-id="+par_id+"], [pagelayer-id="+par_id+"] .pagelayer-ele", true);
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
1425 // Any children to add ?
1426 if(!('widget' in pagelayer_shortcodes[sc])){
1427
1428 // The element props
1429 var props = pagelayer_shortcodes[sc];
1430
1431 // Do we have to create children ?
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);
1442
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+'"]'));
1453 }
1454 }
1455
1456 }
1457
1458 // Save in action history
1459 var cEle = pagelayer_near_by_ele(id, sc);
1460
1461 pagelayer_history_action_push({
1462 'title' : pagelayer_shortcodes[sc]['name'],
1463 'action' : 'Added',
1464 'pl_id' : id,
1465 'html' : jQuery("[pagelayer-id="+id+"]")[0].outerHTML,
1466 'cEle' : cEle
1467 });
1468
1469 // Set pagelayer history TRUE
1470 pagelayer.history_action = true;
1471 pagelayer.global_render = true;
1472
1473 // To update nav item list
1474 pagelayer_do_dirty(pagelayer_ele_by_id(id));
1475
1476 return id;
1477
1478 };
1479
1480 // Add an element
1481 function pagelayer_element_add_child(pEle, sc, gProp){
1482
1483 gProp = gProp || {};
1484 var child = pagelayer_create_sc(sc);
1485 var cid = pagelayer_assign_id(child);
1486 pagelayer_set_parent(child, pagelayer_assign_id(pEle));
1487
1488 // Does the parent have a holder ?
1489 var tag = pagelayer_tag(pEle);
1490
1491 // There is a holder
1492 if('holder' in pagelayer_shortcodes[tag]){
1493
1494 pEle.find(pagelayer_shortcodes[tag]['holder']).append(child);
1495
1496 // No holder, just append
1497 }else{
1498 pEle.append(child);
1499 }
1500
1501 pagelayer_element_setup('[pagelayer-id='+cid+']', true);
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
1568 // Do we have to create children ?
1569 if('has_group' in pagelayer_shortcodes[sc]){
1570
1571 var has_group = pagelayer_shortcodes[sc]['has_group'];
1572 var gProp = pagelayer_shortcodes[sc][has_group['section']][has_group['prop']];
1573
1574 for(var i=0; i < gProp['count']; i++){
1575 var in_cid = pagelayer_element_add_child(jQuery("[pagelayer-id="+cid+"]"), gProp['sc'], gProp);
1576 }
1577
1578 }
1579
1580 return cid;
1581 };
1582
1583 // Return an element by ID
1584 function pagelayer_ele_by_id(id){
1585 return jQuery('[pagelayer-id='+id+']');
1586 };
1587
1588 // Return the wrap by ID
1589 function pagelayer_wrap_by_id(id){
1590 return jQuery('[pagelayer-wrap-id='+id+']');
1591 };
1592
1593 // Give the Pagelayer ID
1594 function pagelayer_id(jEle){
1595
1596 var id = jEle.attr('pagelayer-wrap-id');
1597 if(id){
1598 return id;
1599 }
1600
1601 id = jEle.attr('pagelayer-id');
1602
1603 return id;
1604
1605 }
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
1613 // Assign the jQuery object an ID
1614 function pagelayer_assign_id(jEle){
1615
1616 // Do you have the pagelayer id
1617 var id = jEle.attr("pagelayer-id");
1618 if(!id || id.length < 1){
1619 id = pagelayer_randstr(3)+pagelayer_randInt(9999).toString();
1620 id = id.toLowerCase();
1621 jEle.attr("pagelayer-id", id);
1622 }
1623
1624 return id;
1625
1626 }
1627
1628 // Show the edit options
1629 function pagelayer_element_clicked(selector, e){
1630
1631 var jEle = jQuery(selector);
1632 e = e || false;
1633 //console.log(e);
1634
1635 // You must be a element atleast
1636 if(!jEle.hasClass('pagelayer-ele')){
1637 return false;
1638 }
1639
1640 // Get the parent
1641 var pId = pagelayer_get_parent(jEle);
1642
1643 // If we found a parent
1644 if(pId){
1645 jEle = pagelayer_ele_by_id(pId);
1646 }
1647
1648 // Make the editable fields active
1649 //pagelayer_clear_editable();// First clear
1650 jEle.find('[pagelayer-editable]').each(function (){
1651 pagelayer_make_editable(jQuery(this), e);
1652 });
1653
1654 // Show left bar
1655 if(pagelayer_empty(e)){
1656 pagelayer.$$('.pagelayer-leftbar-table').removeClass('pagelayer-leftbar-hidden pagelayer-leftbar-minimize');
1657 }
1658
1659 // Lets not rebuild everything to make it faster
1660 if(pagelayer_is_active(jEle)){
1661 return false;
1662 }
1663
1664 pagelayer_trigger_action('pagelayer_element_clicked', [jEle]);
1665
1666 // Set this as the active element
1667 pagelayer_set_active(jEle);
1668
1669 // Show the properties
1670 pagelayer_elpd_open(jEle);
1671
1672 }
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
1720 // The edit option
1721 function pagelayer_edit_element(selector){
1722 pagelayer_element_clicked(selector);
1723 }
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
1735 // Setup the properties on a single click
1736 function pagelayer_element_setup(selector, render){
1737
1738 var selector = selector || ".pagelayer-ele";
1739 render = render || false;
1740
1741 // Loop through
1742 jQuery(pagelayer_editable+' '+selector).each(function(){
1743
1744 var jEle = jQuery(this);
1745
1746 // Assign an ID if not there
1747 var id = pagelayer_assign_id(jEle);
1748 var pId = pagelayer_get_parent(jEle) || '';// Options to show on hover
1749 var selector = '[pagelayer-id='+id+']';
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
1756 if(render){
1757 pagelayer_sc_render(jEle);
1758 }
1759
1760 // Get the tag
1761 var tag = pagelayer_tag(jEle);
1762 var props = pagelayer_get_props(jEle);
1763
1764 // Lets check if we are the child of a parent i.e. element of a group
1765 if(pagelayer_empty(pId)){
1766
1767 // Get the parent
1768 var pEle = jEle.parent().closest('.pagelayer-ele');
1769
1770 // If we found a parent
1771 if(pEle.length > 0){
1772
1773 var pTag = pagelayer_tag(pEle);
1774
1775 // Is the parent a group of this child ?
1776 if(!pagelayer_empty(pagelayer_shortcodes[pTag]) && pagelayer_is_group(pTag)){
1777
1778 var has_group = pagelayer_shortcodes[pTag]['has_group'];
1779 var child_type = pagelayer_shortcodes[pTag][has_group['section']][has_group['prop']]['sc'];
1780
1781 // If the type is the same as jEle
1782 if(child_type == pagelayer_tag(jEle)){
1783 pId = pagelayer_assign_id(pEle);
1784 pagelayer_set_parent(jEle, pId);
1785 }
1786 }
1787
1788 }
1789
1790 }
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
1797 // Make the wraps
1798 jEle.wrap('<div class="pagelayer-ele-wrap" pagelayer-wrap-id="'+id+'"></div>');
1799 var wrap = jEle.parent();
1800
1801 // For column we have to do some kidas !
1802 if(tag == 'pl_col'){
1803
1804 var col;
1805 for(var x=1; x<=12; x++){
1806 if(jEle.hasClass('pagelayer-col-'+x)){
1807 col = 'pagelayer-col-'+x;
1808 break;
1809 }
1810 }
1811
1812
1813 wrap.addClass('pagelayer-col '+col);
1814 //jEle.removeClass('pagelayer-col '+col);
1815 wrap.addClass('pagelayer-wrap-col');
1816
1817 }else if(tag == 'pl_row'){
1818 wrap.addClass('pagelayer-wrap-row');
1819 }else if(tag == 'pl_inner_row'){
1820 wrap.addClass('pagelayer-wrap-inner-row');
1821 }else{
1822 wrap.addClass('pagelayer-wrap-ele');
1823 }
1824
1825 // Create the overlay
1826 wrap.prepend('<div class="pagelayer-ele-overlay"></div>');
1827
1828 var overlay = wrap.children('.pagelayer-ele-overlay');
1829 var html;
1830
1831 if(tag == 'pl_row' || tag == 'pl_inner_row'){
1832
1833 overlay.addClass('pagelayer-row-hover');
1834
1835 if(jEle.hasClass('pagelayer-row-stretch-full')){
1836 pagelayer_sc_render(jEle);
1837 }
1838
1839 html = '<div class="pagelayer-row-option" pagelayer-option-edit pagelayer-option-id="'+id+'">'+
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>'+
1845 '</div>';
1846
1847 }else if(tag == 'pl_col'){
1848
1849 overlay.addClass('pagelayer-col-hover');
1850
1851 html = '<div class="pagelayer-col-option" pagelayer-option-edit pagelayer-option-id="'+id+'">'+
1852 '<i class="fas fa-columns pagelayer-eoi" onclick="pagelayer_edit_element(\''+selector+'\', event)" ></i>'+
1853 '</div>';
1854
1855 // Is it an empty col ?
1856 pagelayer_empty_col(jEle.children('.pagelayer-col-holder'));
1857
1858 // Make col resizable
1859 pagelayer_col_make_resizable(wrap);
1860
1861 }else{
1862
1863 html = '<div class="pagelayer-ele-option" pagelayer-option-edit pagelayer-option-id="'+id+'">'+
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>'+
1869 '</div>';
1870
1871 }
1872
1873 // Append to the child
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
1881 jQuery('[pagelayer-option-id='+id+']').hide();
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
1890 // Setup the HOVER events ABD create WRAPS IF we dont have a parent
1891 if(pId.length > 0){
1892 return;
1893 }
1894
1895 // Make the wrap draggable, but only of independent or parent elements
1896 wrap.attr('draggable', 'true');
1897
1898 wrap.hover(function(){
1899
1900 // Is there an element option shower ?
1901 var opts = jQuery('[pagelayer-option-id='+id+']');
1902
1903 // Give the overlay the hover class
1904 opts.parent().addClass('pagelayer-ele-hover');
1905
1906 // Show them
1907 opts.show();
1908
1909 }, function(){
1910
1911 // Is there an element option shower ?
1912 var opts = jQuery('[pagelayer-option-id='+id+']');
1913
1914 // Remove hover class
1915 opts.parent().removeClass('pagelayer-ele-hover');
1916
1917 // Hide opts
1918 opts.hide();
1919
1920 });
1921
1922 });
1923 }
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
1961 // Left Click
1962 function pagelayer_left_click(){
1963
1964 jQuery(pagelayer_editable).on('click', function(e){
1965
1966 e.preventDefault();// Added by Jivan in Actions / Revisions version
1967
1968 // Hide the context menu
1969 jQuery('.pagelayer-right-click-options').hide();
1970
1971 // Target
1972 var tEle = jQuery(e.target);
1973
1974 // If its an edit option click
1975 if(tEle.hasClass('pagelayer-eoi')){
1976 return false;
1977 }
1978
1979 pagelayer_element_clicked(tEle.closest('.pagelayer-ele'), e);
1980
1981 return false;
1982
1983 });
1984 };
1985
1986 // Right Click Menu
1987 function pagelayer_right_click(){
1988
1989 var html = '<div class="pagelayer-right-click-options" style="display:none;">'+
1990 '<ul>'+
1991 '<li><a class="pagelayer-right-edit">Edit</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>'+
1999 '</ul>'+
2000 '</div>';
2001
2002 jQuery('body').append(html);
2003
2004 var $contextMenu = jQuery('.pagelayer-right-click-options');
2005
2006 jQuery(pagelayer_editable).on('contextmenu', function(e){
2007
2008 var tEle = jQuery(e.target);
2009 var jEle = tEle.closest('.pagelayer-ele-wrap').children('.pagelayer-ele');
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
2016 // Get the parent
2017 var pId = pagelayer_get_parent(jEle);
2018
2019 // If we found a parent
2020 if(pId){
2021 jEle = pagelayer_ele_by_id(pId);
2022 }
2023
2024 // The basics
2025 var id = pagelayer_assign_id(jEle);
2026 var tag = pagelayer_tag(jEle);
2027
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']);
2029 $contextMenu.find('.pagelayer-right-duplicate').attr('onclick', 'pagelayer_copy_element("[pagelayer-id='+id+']")');
2030 $contextMenu.find('.pagelayer-right-copy').attr('onclick', 'pagelayer_copy_select("[pagelayer-id='+id+']")');
2031 $contextMenu.find('.pagelayer-right-delete').attr('onclick', 'pagelayer_delete_element("[pagelayer-id='+id+']")');
2032
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 });
2051 }
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
2060 // Are we to hide the paste ?
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);
2073 }else{
2074 showPaste();
2075 }
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
2105 $contextMenu.css({
2106 display: "block",
2107 left: hPosition,
2108 top: vPosition
2109 });
2110
2111 return false;
2112
2113 });
2114
2115 jQuery('html').on('click', function(e){
2116 $contextMenu.hide();
2117 });
2118 }
2119
2120 // Set the parent for the group
2121 function pagelayer_set_parent(jEle, id){
2122 jEle.attr('pagelayer-parent', id);
2123 };
2124
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
2131 function pagelayer_get_parent(jEle){
2132 return jEle.attr('pagelayer-parent');
2133 };
2134
2135 // Sets the screen mode
2136 function pagelayer_set_screen_mode(mode){
2137 var modes = ['desktop', 'tablet', 'mobile'];
2138 var body = pagelayer.$$('.pagelayer-iframe-holder iframe');
2139 var current = '';
2140
2141 for(var x in modes){
2142
2143 if(body.hasClass('pagelayer-screen-'+modes[x]) && modes[x] != mode){
2144 current = modes[x];
2145 body.removeClass('pagelayer-screen-'+modes[x]);
2146 }
2147 }
2148
2149 // Add the class
2150 body.addClass('pagelayer-screen-'+mode);
2151
2152 // Add the class to the button
2153 pagelayer.$$('.pagelayer-mode-button').removeClass('pli-'+current).addClass('pli-'+mode);
2154
2155 // Add the class to the button
2156 pagelayer.$$('.pagelayer-prop-screen').removeClass('pli-'+current).addClass('pli-'+mode);
2157
2158 // Trigger screen change if any
2159 pagelayer.$$('.pagelayer-elp-screen').trigger('pagelayer-screen-changed');
2160
2161 };
2162
2163 // Get the current screen mode
2164 function pagelayer_get_screen_mode(){
2165 var modes = ['desktop', 'tablet', 'mobile'];
2166 var body = pagelayer.$$('.pagelayer-iframe-holder iframe');
2167
2168 for(var x in modes){
2169 if(body.hasClass('pagelayer-screen-'+modes[x])){
2170 return modes[x];
2171 }
2172 }
2173 }
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
2324 // Handle key press events
2325 pagelayer.gDocument.keydown(function(event){
2326 //alert(String.fromCharCode(event.which));
2327
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 }
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
2674 // Is this in the editable area ?
2675 if (tEle.is('input, textarea') || editable.length > 0) {
2676 return;
2677 }
2678
2679 // Delete
2680 if(event.keyCode == 46){
2681 pagelayer_delete_element('[pagelayer-active]');
2682 }
2683
2684 // ctrl+z handle
2685 if(event.keyCode == 90 && event.ctrlKey){
2686 pagelayer_do_history('undo');
2687 }
2688
2689 // ctrl+y handle
2690 if(event.keyCode == 89 && event.ctrlKey){
2691 pagelayer_do_history('redo');
2692 }
2693
2694 });
2695
2696 // Handle Copy of content
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 }
2704
2705 if(selectedText.length > 0){
2706 return;
2707 }
2708
2709 if(pagelayer_active.el && pagelayer_active.el.id){
2710 copyEvent.preventDefault();
2711
2712 // Save the active element id
2713 pagelayer_copy_select("[pagelayer-id='"+pagelayer_active.el.id+"']", copyEvent);
2714
2715 }
2716
2717 });
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
2733 // Handle Paste in the editor
2734 jQuery(document).on('paste', function(pasteEvent){
2735
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
2741 var pagelayer_ajax_func = {};
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 }
2749
2750 if( items.length < 1 || (items.length == 1 && pagelayer_empty(clipboardData.getData(items[0].type))) ){
2751 pasteWidget = true;
2752 }
2753
2754 // This function for ajax before send call back
2755 pagelayer_ajax_func['beforeSend'] = function(xhr){
2756
2757 // If target is not content editable
2758 if( pagelayer_empty(contenteditable) ){
2759
2760 // If we dont have an active element then return false and stop ajax
2761 if( !(pagelayer_active.el && pagelayer_active.el.id) ){
2762 pagelayer_show_msg(pagelayer_l('active_ele_paste_msg'));
2763 return false;
2764 }
2765
2766 pagelayer.copy_selected = jQuery('<div pagelayer-tag="pl_image"></div>');
2767
2768 // Is it to be pastable
2769 if(!pagelayer_can_copy_to('[pagelayer-id="'+pagelayer_active.el.id+'"]')){
2770 pagelayer.copy_selected = '';
2771 return false;
2772 }
2773 }
2774
2775 pEle_target.css({'opacity': '0.33' , 'transition' : '0.1s'});
2776 }
2777
2778 // This function for ajax success call back
2779 pagelayer_ajax_func['success'] = function(obj){
2780
2781 // Successfully Uploaded
2782 if(obj['success']){
2783
2784 // For content editable e.g. Rich Text
2785 if( !pagelayer_empty(contenteditable) ){
2786 document.execCommand('insertImage', false, obj['data']['url']);
2787
2788 // For our widgets
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
2796 var fTo = pagelayer_can_copy_to('[pagelayer-id="'+pagelayer_active.el.id+'"]');
2797 // We need to empty pagelayer.copy_selected
2798 pagelayer.copy_selected = '';
2799
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 };
2819
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 }
2854 }
2855
2856 // Some error occured
2857 }else{
2858 pagelayer_show_msg(obj['data']['message'], 'error', 10000);
2859 }
2860 }
2861
2862 // This function for ajax complete call back
2863 pagelayer_ajax_func['complete'] = function(xhr){
2864 //console.log(xhr);
2865 pEle_target.css({'opacity': '1' , 'transition' : '0.1s'});
2866 }
2867
2868 var findImg = pagelayer_editable_paste_handler(pasteEvent, pagelayer_ajax_func);
2869
2870 if(pagelayer_empty(findImg) || pasteWidget){
2871
2872 // Check the active element
2873 if(pagelayer_active.el && pagelayer_active.el.id && pagelayer_active.el.tag != 'pl_post_props'){
2874
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
2894 }
2895
2896 }else{
2897 pagelayer_show_msg(pagelayer_l('no_active_ele_paste'));
2898 }
2899 }
2900 });
2901
2902 // Delete an element as per the selector
2903 function pagelayer_delete_element(selector){
2904 var jEle = jQuery(selector);
2905 var nearBy = jEle;
2906
2907 // Anything found ?
2908 if(jEle.length > 0){
2909
2910 var id = pagelayer_assign_id(jEle);
2911 var sc = pagelayer_tag(jEle);
2912
2913 // Is there a wrap
2914 var wrap = jQuery('[pagelayer-wrap-id="'+id+'"]');
2915
2916 var par = wrap.parent();
2917
2918 // Save this element in history action
2919 if(pagelayer.history_action){
2920 var cEle = pagelayer_near_by_ele(id, sc);
2921
2922 nearBy = jQuery(cEle.cEle);
2923
2924 // To save in history, we need to save only element not the wraps as we call setup if we redo or undo
2925 jEle.find('style').remove();
2926 jEle.find('.pagelayer-ele-overlay').remove();
2927
2928 // Unwrap the wraps
2929 jEle.find('.pagelayer-ele').each(function (){
2930 var ele = jQuery(this);
2931 if(ele.parent().is('.pagelayer-ele-wrap')){
2932 ele.unwrap();
2933 }
2934 });
2935
2936 pagelayer_history_action_push({
2937 'title' : pagelayer_shortcodes[sc]['name'],
2938 'action' : 'Deleted',
2939 'pl_id' : id,
2940 'html' : jEle[0].outerHTML,
2941 'cEle' : cEle
2942 });
2943 }
2944
2945 wrap.remove();
2946
2947 pagelayer_empty_col(par);
2948
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)){
2951 pagelayer.$$('.pagelayer-elpd-close').click();
2952 }
2953
2954 }
2955
2956 // Do Pagelayer dirty
2957 pagelayer_do_dirty(nearBy);
2958 };
2959
2960 // Select an element
2961 function pagelayer_copy_select(selector, copyEvent = false){
2962
2963 var sEle = jQuery(selector);
2964
2965 if(sEle.length < 1){
2966 pagelayer_show_msg( pagelayer_l('invalid_copy_ele_msg'));
2967 return;
2968 }
2969
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
2999 }
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
3034 function pagelayer_can_copy_to(to){
3035 var jEle = jQuery(pagelayer.copy_selected);
3036 var tEle = jQuery(to);
3037
3038 var eTag = pagelayer_tag(jEle);
3039 var tTag = pagelayer_tag(tEle);
3040 //console.log(eTag+' - '+tTag);
3041
3042 // Invalid HTML copied
3043 if(pagelayer_empty(eTag)){
3044 return false;
3045 }
3046
3047 // Final to
3048 var fTo;
3049
3050 // Selected element is a Row, can go only after a row
3051 if(eTag == 'pl_row'){
3052 fTo = tEle.closest('.pagelayer-ele.pagelayer-row');
3053 if(fTo.length != 1) return false;
3054 return fTo;
3055 }
3056
3057 // Selected element is a Column, can go only after a col
3058 if(eTag == 'pl_col'){
3059 fTo = tEle.closest('.pagelayer-ele.pagelayer-col');
3060 if(fTo.length != 1) return false;
3061 return fTo;
3062 }
3063
3064 // Is the TARGET a row or column when the selected item is a element
3065 if(tTag == 'pl_row' || tTag == 'pl_col'){
3066 return false;
3067 }
3068
3069 return tEle;
3070
3071 }
3072
3073 // Select an element
3074 function pagelayer_paste_element(to, syncClipboard = true){
3075
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 }
3091
3092 var fTo = pagelayer_can_copy_to(to);
3093
3094 // Is it a valid to
3095 if(!fTo){
3096 return false;
3097 }
3098
3099 if(!pagelayer_empty(pagelayer.copy_selected)){
3100 pagelayer_copy_element(pagelayer.copy_selected, fTo);
3101 return true;
3102 }
3103
3104 pagelayer_show_msg(pagelayer_l('no_copied'));
3105
3106 return false;
3107 }
3108
3109 var pagelayerClipboardLoading = false;
3110 var pagelayerClipboardReadable = true;
3111 // If copy_selected is empty then copy data from localStorage
3112 async function pagelayer_copy_from_clipboard(){
3113
3114 if(pagelayerClipboardLoading){
3115 return;
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 }
3142 }
3143
3144 // Copy an element
3145 // Note : insertAfter should always be an pagelayer-ele
3146 function pagelayer_copy_element(selector, insertAfter){
3147 var src = jQuery(selector);
3148 var tag = pagelayer_tag(src);
3149 insertAfter = insertAfter || src;
3150 insertAfter = insertAfter.parent();
3151
3152 var jEle = pagelayer_element_unsetup(src);
3153
3154 // Give it an ID
3155 var id = pagelayer_assign_id(jEle);
3156
3157 jQuery(insertAfter).after(jEle);
3158
3159 pagelayer_element_setup('[pagelayer-id='+id+'], [pagelayer-id='+id+'] .pagelayer-ele', true);
3160
3161 if(pagelayer_is_group(tag)){
3162 pagelayer_sc_render(jEle);
3163 }
3164
3165 // Save this element in history action
3166 if(pagelayer.history_action){
3167 var cEle = pagelayer_near_by_ele(id, tag);
3168 pagelayer_history_action_push({
3169 'title' : pagelayer_shortcodes[tag]['name'],
3170 'action' : 'Copied',
3171 'pl_id' : id,
3172 'html' : jEle[0].outerHTML,
3173 'cEle' : cEle
3174 });
3175 }
3176
3177 //If column then renumber columns
3178 if(tag == 'pl_col'){
3179 var row = src.parent().closest('.pagelayer-row');
3180 pagelayer_renumber_col(row);
3181 }
3182
3183 pagelayer_do_dirty(jEle);
3184
3185 return id;
3186 };
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
3484 // Language key
3485 function pagelayer_l(k){
3486 if(k in pagelayer_lang){
3487 return pagelayer_lang[k];
3488 }
3489 return k;
3490 }
3491
3492 // Get props based on the tag
3493 function pagelayer_get_props(jEle){
3494 var props = pagelayer_shortcodes[pagelayer_tag(jEle)];
3495 return props;
3496 }
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
3541 // Set the given jELE as active
3542 function pagelayer_set_active(jEle){
3543
3544 // Make all other element as inactive
3545 jQuery('[pagelayer-active]').each(function(){
3546 var $j = jQuery(this);
3547 $j.removeAttr('pagelayer-active');
3548 });
3549
3550 jEle.attr('pagelayer-active', 1);
3551
3552 // Add and remove the class
3553 jQuery('.pagelayer-active').removeClass('pagelayer-active');
3554
3555 jEle.parent().children('.pagelayer-ele-overlay').addClass('pagelayer-active');
3556
3557 }
3558
3559 function pagelayer_sc(sc){
3560 return sc.replace('pl_', '');
3561 };
3562
3563 // Create a HTML dom element of the Short code
3564 // Return the jEle
3565 function pagelayer_create_sc(sc){
3566
3567 var html;
3568 var _sc = pagelayer_sc(sc);
3569 var func = window['pagelayer_create_sc_'+sc];
3570
3571 // Generate the HTML
3572 if(typeof func == 'function'){
3573 html = window['pagelayer_create_sc_'+sc]();
3574 }else{
3575 html = '<div '+pagelayer_sc_atts('pagelayer-'+_sc)+'></div>';
3576 }
3577
3578 html = jQuery(html);
3579
3580 // Add the tag
3581 html.attr('pagelayer-tag', sc);
3582
3583 // Give it an ID
3584 id = pagelayer_assign_id(html);
3585
3586 // Try to set the default values over 5 loops
3587 pagelayer_set_default_atts(html, 5);
3588
3589 return html;
3590
3591 };
3592
3593 // Returns a list of default attributes to set as per the current selection
3594 function pagelayer_set_default_atts(jEle, set){
3595
3596 set = set || 0;
3597 var hasSet = false;
3598
3599 for(var i = 1; i <= set;i++){
3600
3601 //console.log('[pagelayer_set_default_atts] Loop :'+i);
3602 //console.log(jEle);
3603
3604 // Get existing data
3605 var el = pagelayer_data(jEle, true);
3606
3607 // If it is the last loop and we are greater than 1
3608 if(i > 1 && i == set){
3609 console.log('[pagelayer_default_atts] Still vars to set. Please check your shortcode params !');
3610 }
3611
3612 // We are supposed to set !
3613 if('set' in el && !pagelayer_empty(el.set)){
3614 pagelayer_set_atts(jEle, el.set);
3615 hasSet = true;
3616 }else{
3617 break;
3618 }
3619 }
3620
3621 return hasSet;
3622 }
3623
3624 // Returns the tag
3625 function pagelayer_tag(jEle){
3626
3627 // It could be the wrap
3628 if(jEle.hasClass('pagelayer-ele-wrap')){
3629 return jEle.children('.pagelayer-ele').attr('pagelayer-tag');
3630 }
3631
3632 // It could be the row or col holder
3633 if(jEle.hasClass('pagelayer-row-holder') || jEle.hasClass('pagelayer-col-holder')){
3634 return jEle.parent().attr('pagelayer-tag');
3635 }
3636
3637 return jEle.attr('pagelayer-tag');
3638 }
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
3704 // Gets a single attribute value
3705 function pagelayer_get_att(jEle, 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;
3711 };
3712
3713 // Gets a single attribute value
3714 function pagelayer_get_tmp_att(jEle, 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;
3720 };
3721
3722 // This function will just set atts and not do anything else
3723 // Atts can be string or object. If its string, then val is needed
3724 function pagelayer_set_atts(jEle, atts, val){
3725
3726 if(typeof atts == 'string'){
3727 var tmp = {};
3728 tmp[atts] = val;
3729 atts = tmp;
3730 }
3731
3732 if(typeof atts != 'object'){
3733 return false;
3734 }
3735
3736 var tag = pagelayer_tag(jEle);
3737 var trigger_onchange = 0;
3738
3739 if(pagelayer_empty(tag)){
3740 console.log('Set atts found no tag');
3741 console.log(jEle);
3742 return;
3743 }
3744
3745 // All props
3746 var all_props = pagelayer_shortcodes[tag];//console.log(tag);console.log(jEle);
3747 var trigger_props = {};
3748 var no_val = {};
3749 var defaults = {};
3750 var _props = {};
3751
3752 // Loop through all props
3753 for(var i in pagelayer_tabs){
3754
3755 var tab = pagelayer_tabs[i];
3756
3757 for(var section in all_props[tab]){
3758
3759 var props = section in pagelayer_shortcodes[tag] ? pagelayer_shortcodes[tag][section] : pagelayer_styles[section];
3760
3761 for(var x in props){
3762
3763 if('default' in props[x]){
3764 defaults[x] = 1;
3765 }
3766
3767 // Create an easy REFERENCE for access
3768 _props[x] = props[x];
3769
3770 // Screen option REFERENCE is also needed for lookup
3771 if('screen' in _props[x]){
3772 _props[x+'_tablet'] = props[x];
3773 _props[x+'_mobile'] = props[x];
3774 }
3775
3776 // Dont set any val, but we set temp value
3777 if('no_val' in props[x]){
3778 no_val[x] = 1;
3779 }
3780
3781 if('req' in props[x] || 'show' in props[x]){
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
3798 for(var showParam in show){
3799 var val = show[showParam];
3800 var except = showParam.substr(0, 1) == '!' ? true : false;
3801 showParam = except ? showParam.substr(1) : showParam;
3802 trigger_props[showParam] = 1;
3803 }
3804
3805 }
3806
3807 }
3808
3809 }
3810
3811 }
3812
3813 var ref_data = pagelayer_el_data_ref(jEle);
3814
3815 for(var x in atts){
3816
3817 // Are we to trigger change
3818 if(x in trigger_props){
3819 trigger_onchange = 1;
3820 }
3821
3822 //console.log(x+'-'+atts[x]);
3823
3824 // Is this a pro feature and we are not pro ? Then we dont do anything and continue !
3825 if(!pagelayer_empty(_props[x]) && 'pro' in _props[x] && pagelayer_empty(pagelayer_pro)){
3826 continue;
3827 }
3828
3829 if(x in no_val){
3830 pagelayer_set_tmp_atts(jEle, x, atts[x]);
3831 continue;
3832 }
3833
3834 // Record History
3835 if(pagelayer.history_action){
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
3843 pagelayer_history_action_push({
3844 'title' : all_props['name'],
3845 'subTitle' : label,
3846 'action' : 'Edited',
3847 'attrType' : 'a_attr',
3848 'pl_id' : pagelayer_id(jEle),
3849 'atts' : x,
3850 'oldVal' : old_val,
3851 'newVal' : atts[x]
3852 });
3853 }
3854
3855 // Remove the attribute if its BLANK and there is no default for it
3856 // If there is a default, we set it to blank to keep record of the current val
3857 if(pagelayer_length(atts[x]) < 1){
3858
3859 // Remove values which are not defaults
3860 if(!(x in defaults)){
3861 delete ref_data['attr'][x];
3862 // Otherwise keep value set for avoiding resetting
3863 }else{
3864 ref_data['attr'][x] = atts[x];
3865 }
3866
3867 // Remove the tmp atts anyway
3868 pagelayer_clear_tmp_atts(jEle, x);
3869
3870 // Set the value
3871 }else{
3872 ref_data['attr'][x] = pagelayer_trim(atts[x]);
3873 }
3874
3875 // Are you the active element
3876 if(pagelayer_is_active(jEle)){
3877
3878 // TODO : Record Undo and Redo
3879
3880 }
3881
3882 }
3883
3884 pagelayer_el_dump_data(jEle);
3885
3886 // Trigger the change of the parameter and show the required properties
3887 if(trigger_onchange){
3888 pagelayer_elpd_show_rows();
3889 }
3890
3891 pagelayer_do_dirty(jEle);
3892
3893 };
3894
3895 // This function will just set atts and not do anything else
3896 // Atts can be string or object. If its string, then val is needed
3897 function pagelayer_set_tmp_atts(jEle, atts, val){
3898
3899 if(typeof atts == 'string'){
3900 var tmp = {};
3901 tmp[atts] = val;
3902 atts = tmp;
3903 }
3904
3905 if(typeof atts != 'object'){
3906 return false;
3907 }
3908
3909 var ref_data = pagelayer_el_data_ref(jEle);
3910
3911 for(var x in atts){
3912
3913 // Record history
3914 if(pagelayer.history_action){
3915
3916 var old_val = pagelayer_get_tmp_att(jEle, x) || '';
3917 pagelayer_history_action_push({
3918 'title' : pagelayer_shortcodes[pagelayer_tag(jEle)]['name'],
3919 'subTitle' : x,
3920 'action' : 'Edited',
3921 'attrType' : 'tmp_attr',
3922 'pl_id' : pagelayer_id(jEle),
3923 'atts' : x,
3924 'oldVal' : old_val,
3925 'newVal' : atts[x]
3926 });
3927
3928 }
3929
3930 ref_data['tmp'][x] = atts[x];
3931
3932 }
3933
3934 pagelayer_el_dump_data(jEle);
3935
3936 };
3937
3938 // This function removes the temporary attributes of an ele
3939 function pagelayer_clear_tmp_atts(jEle, attr){
3940
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 }
3950 }
3951 }
3952
3953 // This function removes the temporary attributes of an ele
3954 function pagelayer_img_tmp_atts(jEle, attr){
3955
3956 var found = {};
3957 var regexp = new RegExp('^'+attr+'\-', 'gi');
3958 var ref_data = pagelayer_el_data_ref(jEle);
3959
3960 for(var n in ref_data['tmp']){
3961 if(n.match(regexp)){
3962 found[n] = 1;
3963 }
3964 }
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();
3972 return 'class="'+classes+' pagelayer-ele" '+r.join(' ');
3973 }
3974
3975 // Is the jEle the active element ?
3976 function pagelayer_is_active(jEle){
3977
3978 // Is this the active Element ?
3979 if(pagelayer_empty(pagelayer_active.el) || jEle.attr('pagelayer-id') != pagelayer_active.el.id){
3980 return false;
3981 }
3982
3983 return true;
3984
3985 };
3986
3987 // Removes {{}} from the variable name
3988 function pagelayer_var(val){
3989 return val.substring(2, (val.length - 2));
3990 }
3991
3992 // Take care of the CSS
3993 function pagelayer_css_render(css, val, seperator){
3994 //console.log('CSS '+css+' | '+val);
3995
3996 // Seperator
3997 seperator = seperator || ',';
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
4012 // Replace the val
4013 css = replaceCss(css, val, '{{val}}');
4014
4015 // If there is an array
4016 if(css.match(/val\[\d/)){
4017
4018 if(typeof val != 'object' || val === null){
4019 val = String(val).split(seperator);
4020 }
4021
4022 for(var i in val){
4023 css = replaceCss(css, val[i], '{{val['+i+']}}');
4024 }
4025 }
4026
4027 //console.log('Final CSS '+css);
4028
4029 return css;
4030
4031 };
4032
4033 // Handle hexa to rgba and also remove alpha which is ff
4034 function pagelayer_hex8_to_rgba(val){
4035
4036 val = String(val);
4037
4038 // If opacity is ff then discard ff
4039 if(val.match(/^#([a-f0-9]{6})ff$/)){
4040 return val.substr(0,7);
4041 }
4042
4043 // Lets handle the RGB+opacity
4044 if(val.match(/^#([a-f0-9]{8})$/)){
4045 var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(val);
4046 val = 'rgba('+parseInt(result[1], 16)+', '+parseInt(result[2], 16)+', '+parseInt(result[3], 16)+', '+(parseInt(result[4], 16)/255).toFixed(2)+')';
4047 }
4048
4049 return val;
4050
4051 };
4052
4053 // Replace the variables
4054 function pagelayer_parse_el_vars(str, el){
4055
4056 str = str.split('{{element}}').join(el.CSS.cssSel);
4057 str = str.split('{{wrap}}').join(el.CSS.wrap);
4058 str = str.split('{{ele_id}}').join(el.id);
4059
4060 return str;
4061
4062 }
4063
4064 // Replace the variables
4065 function pagelayer_parse_vars(str, el){
4066
4067 for(var x in el.tmp){
4068 str = str.split('{{{'+x+'}}}').join(el.tmp[x]);
4069 }
4070
4071 for(var x in el.atts){
4072 str = str.split('{{'+x+'}}').join(el.atts[x]);
4073 }
4074
4075 return str;
4076 };
4077
4078 // Render the Element
4079 function pagelayer_sc_render(jEle){
4080
4081 // We render only the active element
4082 if(!pagelayer_is_active(jEle)){
4083 //return false;
4084 }
4085
4086 //console.log('Rendering');
4087
4088 // Handle the CSS part
4089 // Get the id, tag, atts, data, etc
4090 var el = pagelayer_data(jEle, true);
4091 var all_props = pagelayer_shortcodes[el.tag];
4092 var elCSS = {
4093 classes: [],
4094 remove_classes: [],
4095 attr: [],
4096 remove_attr: [],
4097 css: [],
4098 edit: [],
4099 cssSel: '.p-'+el.id,
4100 sel: '[pagelayer-id="'+el.id+'"]',
4101 wrap: '[pagelayer-wrap-id="'+el.id+'"]'
4102 };
4103
4104 // Create a reference
4105 el.CSS = elCSS;
4106
4107 // Make sure if we have the class selector
4108 el.$.addClass('p-'+el.id);
4109
4110 //console.log(el.atts);
4111
4112 for(var i in pagelayer_tabs){
4113 var tab = pagelayer_tabs[i];
4114 for(var section in all_props[tab]){ //console.log(tab+' '+section);
4115
4116 var props = section in pagelayer_shortcodes[el.tag] ? pagelayer_shortcodes[el.tag][section] : pagelayer_styles[section];//console.log(props);
4117
4118 // Loop the props
4119 for(var x in props){
4120
4121 // pagelayer_data will return attributes even if they are BLANK e.g. attr=""
4122 // Render doesnt consider BLANK values as values, and we are unsetting them now
4123 // If in any situation you need to consider blank values, please handle in the JS / PHP function of the Shortcode
4124 if(x in el.atts && pagelayer_length(el.atts[x]) < 1){
4125 delete el.atts[x];
4126 }
4127
4128 // Any editor ?
4129 if('edit' in props[x]){
4130 elCSS.edit.push({prop: x, sel: props[x]['edit']});
4131 }
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
4184 // Do we have a addClass ?
4185 // We are checking before the element has a value so that we can add or remove the class
4186 if('addClass' in props[x]){
4187
4188 var addClasses;
4189
4190 // Convert the string to an array
4191 if(typeof props[x]['addClass'] === 'string'){
4192 addClasses = [props[x]['addClass']];
4193 }else{
4194 addClasses = props[x]['addClass'];
4195 }
4196
4197 for(var c in addClasses){
4198
4199 // The selector
4200 var tSel = jQuery.isNumeric(c) ? '' : c;
4201
4202 // If there is a VAL
4203 // NOTE : Only val is allowed when there is a list
4204 if(addClasses[c].match(/\{\{val\}\}/) && 'list' in props[x]){
4205
4206 for(var l in props[x]['list']){
4207
4208 var tmp = {'sel': tSel, 'val': addClasses[c].replace('{{val}}', l)};
4209
4210 if(el.atts[x] == l){
4211 elCSS['classes'].push(tmp);
4212 }else{
4213 elCSS['remove_classes'].push(tmp);
4214 }
4215
4216 }
4217
4218 }else{
4219
4220 var tmp = {'sel': tSel, 'val': addClasses[c].replace('{{val}}', el.atts[x])};
4221
4222 // If the value is there
4223 if(x in el.atts){
4224 elCSS['classes'].push(tmp);
4225 }else{
4226 elCSS['remove_classes'].push(tmp);
4227 }
4228
4229 }
4230 }
4231 }
4232
4233 // Do we have a addAttr ?
4234 // We are checking before the element has a value so that we can add or remove the attr
4235 if('addAttr' in props[x]){
4236
4237 var addAttr;
4238
4239 // Convert the string to an array
4240 if(typeof props[x]['addAttr'] === 'string'){
4241 addAttr = [props[x]['addAttr']];
4242 }else{
4243 addAttr = props[x]['addAttr'];
4244 }
4245
4246 for(var c in addAttr){
4247
4248 // The selector
4249 var tSel = jQuery.isNumeric(c) ? '' : c;
4250 var tmp = {'sel': tSel, 'val': addAttr[c]};
4251
4252 // If the value is there
4253 if(x in el.atts){
4254 elCSS['attr'].push(tmp);
4255 }else{
4256 elCSS['remove_attr'].push(tmp);
4257 }
4258 }
4259 }
4260
4261 // Do we have a CSS ?
4262 if('css' in props[x]){
4263
4264 var css;
4265
4266 // Convert the string to an array
4267 if(typeof props[x]['css'] === 'string'){
4268 css = [props[x]['css']];
4269 }else{
4270 css = props[x]['css'];
4271 }
4272
4273 // Screen modes
4274 var modes = {desktop: '', tablet: '_tablet', mobile: '_mobile'};
4275 var desk_global = (props[x]['type'] == 'typography') ? pagelayer_is_global_typo(el.atts[x]) : '';
4276
4277 for(var m in modes){
4278
4279 var xm = x+modes[m];
4280
4281 // If the value is there
4282 if(!(xm in el.atts) && pagelayer_empty(desk_global)){
4283 continue;
4284 }
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
4311 for(var c in css){
4312
4313 // The selector
4314 var tSel = jQuery.isNumeric(c) ? '{{element}}' : c;
4315 var tmp = {
4316 sel: tSel,
4317 val: pagelayer_css_render(css[c], xm_val, (props[x].sep || ',')),
4318 };
4319
4320 // Is this a tablet
4321 if(m == 'tablet'){
4322 tmp.sel = '@media (max-width: '+ pagelayer_settings['tablet_breakpoint'] +'px) and (min-width: '+ (pagelayer_settings['mobile_breakpoint'] +1) +'px){'+tmp.sel;
4323 tmp.val = tmp.val+'}';
4324 }
4325
4326 // Is this a mobile mode ?
4327 if(m == 'mobile'){
4328 tmp.sel = '@media (max-width: '+ pagelayer_settings['mobile_breakpoint'] +'px){'+tmp.sel;
4329 tmp.val = tmp.val+'}';
4330 }
4331
4332 // Push to store
4333 elCSS.css.push(tmp);
4334 }
4335
4336 }
4337
4338 }
4339
4340 }
4341
4342 }
4343
4344 }
4345
4346 // If there is an HTML, then process it
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')];
4351
4352 if(typeof fn == 'function'){
4353 fn(el);
4354 }
4355
4356 el.iHTML = jQuery('<div>'+pagelayer_shortcodes[el.tag]['html']+'</div>');
4357
4358 // Lets process the 'if-ext'
4359 el.iHTML.find('[if-ext]').each(function (){
4360 var $j = jQuery(this);
4361 var reqvar = pagelayer_var($j.attr('if-ext'));
4362 $j.removeAttr('if-ext');
4363
4364 // Is the element there ?
4365 if(!(reqvar in el.atts && !pagelayer_empty(el.atts[reqvar]))){
4366 //console.log('HERE');
4367 $j[0].outerHTML = $j.html();
4368 }
4369
4370 });
4371
4372 // Lets process the 'if'
4373 el.iHTML.find('[if]').each(function (){
4374 var $j = jQuery(this);
4375 var reqvar = pagelayer_var($j.attr('if'));
4376 $j.removeAttr('if');
4377
4378 // Is the element there ?
4379 if(!(reqvar in el.atts && !pagelayer_empty(el.atts[reqvar]))){
4380 //console.log('HERE');
4381 $j.remove();
4382 }
4383
4384 });
4385
4386 //console.log(el.atts);
4387
4388 // Parse the variables
4389 var new_html = pagelayer_parse_vars(el.iHTML.html(), el);
4390 el.iHTML.html(new_html);
4391
4392 // Do we have to wrap the innerHTML ?
4393 if('holder' in pagelayer_shortcodes[el.tag]){
4394
4395 var hSel = pagelayer_shortcodes[el.tag]['holder'];
4396 var holder = jEle.find(hSel).first();
4397
4398 // Detach the holder
4399 holder.detach();
4400
4401 // Add the new HTML
4402 el.$.html(el.iHTML.html());
4403
4404 // reAttach the children only
4405 el.$.find(hSel).html(holder.children());
4406
4407 // No holder
4408 }else{
4409
4410 //console.log(el.iHTML.html());
4411 el.$.html(el.iHTML.html());
4412
4413 }
4414
4415 // Rows, Cols and Groups
4416 }else{
4417
4418 // Is there a function to render ?
4419 var fn = window['pagelayer_sc_render_'+jEle.attr('pagelayer-tag')];
4420
4421 if(typeof fn == 'function'){
4422 fn(el);
4423 }
4424
4425 }
4426
4427 // Is there a function to render after HTML insertion but before CSS and attr ?
4428 var post = window['pagelayer_render_html_'+jEle.attr('pagelayer-tag')];
4429
4430 if(typeof post == 'function'){
4431 post(el);
4432 }
4433
4434 ////////////////////////////
4435 // Are there any edit fields ?
4436 ////////////////////////////
4437
4438 if(elCSS.edit.length > 0){
4439
4440 for(var c in elCSS.edit){
4441 var prop = elCSS.edit[c]['prop'];
4442 var tSel = elCSS.edit[c]['sel'];
4443 var node = tSel.length < 1 ? jEle : jEle.find(tSel);
4444 node.attr({'pagelayer-editable': prop, 'contenteditable' : 'true'});
4445 }
4446
4447 }
4448
4449 ////////////////////////////
4450 // Are there any addClass ?
4451 ////////////////////////////
4452
4453 // If we have any classes to add
4454 if(elCSS.classes.length > 0){
4455 //console.log(elCSS.classes);
4456
4457 for(var c in elCSS.classes){
4458 var tSel = elCSS.classes[c]['sel'].replace('{{element}}', '');
4459 var node = tSel.length < 1 ? jEle : jEle.find(tSel);
4460 if(!node.hasClass(elCSS.classes[c]['val'])){
4461 node.addClass(elCSS.classes[c]['val']);
4462 }
4463 }
4464 }
4465
4466 // If we have any classes to remove
4467 if(elCSS.remove_classes.length > 0){
4468 //console.log(elCSS.remove_classes);
4469
4470 for(var c in elCSS.remove_classes){
4471 var tSel = elCSS.remove_classes[c]['sel'].replace('{{element}}', '');
4472 var node = tSel.length < 1 ? jEle : jEle.find(tSel);
4473 if(node.hasClass(elCSS.remove_classes[c]['val'])){
4474 node.removeClass(elCSS.remove_classes[c]['val']);
4475 }
4476 }
4477 }
4478
4479 ////////////////////////////
4480 // Are there any addAttr ?
4481 ////////////////////////////
4482
4483 // If we have any attributes to add
4484 if(elCSS.attr.length > 0){
4485 //console.log(elCSS.attr);
4486
4487 for(var c in elCSS.attr){
4488 var tSel = elCSS.attr[c]['sel'].replace('{{element}}', '');
4489 var node = tSel.length < 1 ? jEle : jEle.find(tSel);
4490 var att = elCSS.attr[c]['val'].split(/=(.*)/);
4491 att[1] = pagelayer_parse_vars(att[1], el);
4492 att[1] = pagelayer_trim(att[1], '"');
4493
4494 // Is it the same val ?
4495 if(!node.attr(att[0]) !== att[1]){
4496 node.attr(att[0], att[1]);
4497 }
4498 }
4499 }
4500
4501 // If we have any attributes to add
4502 if(elCSS.remove_attr.length > 0){
4503 //console.log(elCSS.remove_attr);
4504
4505 for(var c in elCSS.remove_attr){
4506 var tSel = elCSS.remove_attr[c]['sel'].replace('{{element}}', '');
4507 var node = tSel.length < 1 ? jEle : jEle.find(tSel);
4508 var att = elCSS.remove_attr[c]['val'].split('=');
4509
4510 if(node.is('['+att[0]+']')){
4511 node.removeAttr(att[0]);
4512 }
4513 }
4514 }
4515
4516 // The style element
4517 var style = pagelayer.$('[pagelayer-style-id='+el.id+']');
4518
4519 // If we have any RULES CSS, then handle it
4520 if(elCSS.css.length > 0){
4521
4522 // Did we find it ?
4523 if(style.length < 1){
4524 jEle.prepend('<style pagelayer-style-id="'+el.id+'"></style>');
4525 }
4526
4527 // Get it again
4528 style = pagelayer.$('[pagelayer-style-id='+el.id+']');
4529
4530 // Make the rules
4531 var rules = [];
4532
4533 // Loop
4534 for(var c in elCSS.css){
4535 var tSel = pagelayer_parse_el_vars(elCSS.css[c]['sel'], el);
4536 var rule = elCSS.css[c]['val'];
4537 if(tSel.length > 0){
4538 rules.push(tSel+'{'+rule+'}');
4539 }else{
4540 rules.push(pagelayer_parse_el_vars(rule, el));
4541 }
4542 }
4543
4544 // CSS Selector overide
4545 if(!pagelayer_empty(all_props['overide_css_selector'])){
4546 for(var r in rules){
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);
4550 }
4551 }
4552
4553 // Set the style
4554 style.html(pagelayer_parse_vars(rules.join("\n"), el));
4555 //console.log(style);
4556 }else{
4557 style.remove();
4558 }
4559
4560 // Is there a function to render at the end ?
4561 var end = window['pagelayer_render_end_'+jEle.attr('pagelayer-tag')];
4562
4563 if(typeof end == 'function'){
4564 end(el);
4565 }
4566
4567 // If the element have any parent
4568 var par = pagelayer_get_parent(jEle);
4569 var eleId = el.id;
4570
4571 if(par){
4572 eleId = par;
4573 pagelayer_sc_render(pagelayer_ele_by_id(par));
4574 }
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
4595 };
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
4711 // Is the given tag a group
4712 function pagelayer_is_group(tag){
4713
4714 if('has_group' in pagelayer_shortcodes[tag] && !pagelayer_empty(pagelayer_shortcodes[tag]['has_group'])){
4715 return true;
4716 }
4717
4718 return false;
4719
4720 }
4721
4722 // Do action / event
4723 function pagelayer_trigger_action(act, param = []){
4724 jQuery(document).trigger(act, param);
4725 }
4726
4727 // Perform a function on an action / event
4728 function pagelayer_add_action(act, func){
4729 jQuery(document).on(act, func);
4730 }
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
4910 // Save the post
4911 function pagelayer_save(){
4912
4913 // hiding and showing loading animation
4914 pagelayer.$$('.pagelayer-update-text').hide();
4915 pagelayer.$$('.pagelayer-update-loader').show();
4916
4917 pagelayer_trigger_action('pagelayer_save');
4918
4919 var pagelayerajaxurl = pagelayer_ajax_url+'&action=pagelayer_save_content&postID='+pagelayer_postID;
4920 var post = pagelayer_generate_sc(pagelayer_editable);//alert(post);return;
4921
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'];
4933 }
4934
4935 // Do we have contact templates ?
4936 var contacts_props = pagelayer_get_contact_templates();
4937
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),
4953 pagelayer_nonce: pagelayer_ajax_nonce,
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 }
5011 }
5012 });
5013 }
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();
5022 };
5023
5024 //Close the Editor
5025 function pagelayer_close(){
5026 if(pagelayer_isDirty == true){
5027 var r = confirm('Your Data has not been Saved yet! \n Press OK to stay on the Page.'+
5028 '\n Press Cancel to Close Editor. ');
5029 if(r == false){
5030 window.top.location.href = pagelayer_returnURL;
5031 }
5032 }else{
5033 window.top.location.href = pagelayer_returnURL;
5034 }
5035 };
5036
5037 function pagelayer_htmlEntities(str) {
5038 return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
5039 }
5040
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){
5052
5053 selfEle = selfEle || false;
5054 var txt = '';
5055
5056 var generate_sc_single = function(jEle){
5057
5058 // The ID
5059 var id = jEle.attr('pagelayer-id');
5060
5061 // If there is an Add element wrapper
5062 if(pagelayer_empty(id)){
5063 return;
5064 }
5065
5066 // Find the type of tag
5067 var tag = jEle.attr('pagelayer-tag');
5068 var final_tag = tag;
5069 var closestEle = jEle.closest('.pagelayer-col-holder');
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
5076 // Define inner row | Note : Commented as we now have a new widget of type inner_row
5077 /*if(tag == 'pl_row' && closestEle.length > 0 && closestEle.closest(pagelayer_editable).length > 0){
5078 final_tag = 'pl_inner_row';
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 }
5087
5088 // Define inner column
5089 if(tag == 'pl_col' && closestEle.length > 0 && closestEle.closest(pagelayer_editable).length > 0){
5090 final_tag = 'pl_inner_col';
5091 }
5092 //console.log(tag);
5093
5094 // Is there an innerHTML ele
5095 var inner = '';
5096 if('innerHTML' in pagelayer_shortcodes[tag]){
5097 inner = pagelayer_shortcodes[tag]['innerHTML'];
5098 }
5099
5100 // Data reference
5101 var ref_data = pagelayer_el_data_ref(jEle);
5102
5103 // Create the tag
5104 var data = JSON.parse(JSON.stringify(ref_data['attr']));
5105
5106 data['pagelayer-id'] = id;
5107 data = pagelayer_serializeAttributes(data);
5108
5109 var content = '';
5110
5111 // Any internal function to handle the save ?
5112 var func = window['pagelayer_tag_'+tag];
5113 if(typeof func == 'function'){
5114
5115 content = func(jEle);
5116
5117 // If its a Row or Column or Group then it will have children
5118 }else if(jEle.hasClass('pagelayer-row') || jEle.hasClass('pagelayer-col') || jEle.hasClass('pagelayer-inner_row') || pagelayer_is_group(tag)){
5119
5120 var sel = jEle;
5121
5122 // Any holder which holds children ?
5123 if('holder' in pagelayer_shortcodes[tag]){
5124 sel = jEle.find(pagelayer_shortcodes[tag]['holder']);
5125 }
5126
5127 // Select the top-most element
5128 sel = jQuery(sel).first();
5129
5130 // Any child selector - Majorly for owl carousel
5131 // NOTE : Child selector should be very specific with immediate child selection at all levels
5132 var child_selector = false;
5133 if('child_selector' in pagelayer_shortcodes[tag]){
5134 childSel = sel.find(pagelayer_shortcodes[tag]['child_selector']);
5135
5136 if(childSel.length > 0){
5137 sel = childSel;
5138 }
5139 }
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;
5146 }
5147
5148 // Its a normal element so we might need to handle the content
5149 }else{
5150
5151 if(inner.length > 0){
5152 content = pagelayer_get_att(jEle, inner);
5153 if(!content){
5154 content = '';
5155 }
5156 }else{
5157 content = '';//jEle.html();
5158 }
5159
5160 }
5161
5162 // Leaving HTML and non-pagelayer supported content intact
5163 if(final_tag == 'pl_missing'){
5164 txt += content;
5165 return;
5166 }
5167
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 };
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
5193 return txt;
5194
5195 };
5196
5197 // Show the required leftbar tab
5198 function pagelayer_leftbar_tab(tab){
5199 pagelayer.$$('.pagelayer-leftbar-tab').hide();
5200 pagelayer.$$('#'+tab).show();
5201 }
5202
5203 // Sets up the leftbar
5204 function pagelayer_leftbar(){
5205
5206 // Toggle the holder
5207 pagelayer.$$('.pagelayer-leftbar-toggle').on('click', function(){
5208 pagelayer.$$('.pagelayer-leftbar-table').toggleClass('pagelayer-leftbar-hidden');
5209 pagelayer_trigger_action('pagelayer-leftbar-toggle');
5210 });
5211
5212 // Close leftbar
5213 pagelayer.$$('.pagelayer-leftbar-close').on('click', function(){
5214 pagelayer.$$('.pagelayer-leftbar-toggle').click();
5215 });
5216
5217 // Minimize leftbar
5218 pagelayer.$$('.pagelayer-leftbar-minimize').on('click', function(){
5219 pagelayer.$$('.pagelayer-leftbar-table').toggleClass('pagelayer-leftbar-minimize');
5220 });
5221
5222 var html = '<div class="pagelayer-leftbar">'+
5223 '<div class="pagelayer-leftbar-scroll">'+
5224 '<div id="pagelayer-shortcodes" class="pagelayer-leftbar-tab pagelayer-shortcodes">'+
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>';
5234
5235 for(var x in pagelayer_groups){
5236
5237 // Title
5238 var group_title = x;
5239 if (x === 'Basic') group_title = 'Atomic Elements';
5240 else if (x === 'Common') group_title = 'General';
5241
5242 html += '<div class="pagelayer-leftbar-group pagelayer-group-name-'+x+'"><h5>'+group_title+'</h5>';
5243
5244 // Indivdual icon
5245 for(var y in pagelayer_groups[x]){
5246
5247 var sc = pagelayer_groups[x][y];
5248
5249 if(!(sc in pagelayer_shortcodes) || 'not_visible' in pagelayer_shortcodes[sc]){
5250 continue;
5251 }
5252
5253 html += '<div class="pagelayer-shortcode-drag" draggable="true" pagelayer-tag="'+sc+'">'+
5254 '<div class="pagelayer-sc">'+
5255 '<center class="pagelayer-shortcode-inner">';
5256
5257 if('icon' in pagelayer_shortcodes[sc]){
5258 html += '<i class="pagelayer-shortcode '+pagelayer_shortcodes[sc]['icon']+'"></i>';
5259 }else{
5260 html += '<i class="pagelayer-shortcode pli pagelayer-'+sc+'"></i>';
5261 }
5262
5263 html += '</center>'+
5264 '<span class="pagelayer-shortcode-text">'+pagelayer_shortcodes[sc]['name']+'</span>'+
5265 '</div>'+
5266 '</div>';
5267
5268 }
5269
5270 html += '</div>';
5271
5272 }
5273
5274 html += '</div>'+
5275 '<div id="pagelayer-global-widget" class="pagelayer-hidden pagelayer-global-widget"></div>'+
5276 '</div>'+
5277 '<div id="pagelayer-elpd" class="pagelayer-leftbar-tab pagelayer-elpd"></div>'+
5278 '<div id="pagelayer-options" class="pagelayer-leftbar-tab pagelayer-options"></div>'+
5279 '<div id="pagelayer-history" class="pagelayer-leftbar-tab pagelayer-history"></div>'+
5280 '<div id="pagelayer-post-settings" class="pagelayer-leftbar-tab pagelayer-post-settings"></div>'+
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>'+
5283 '</div>'+
5284 '</div>';
5285
5286 pagelayer.$$('.pagelayer-leftbar-holder').prepend(html);
5287 pagelayer_leftbar_tab('pagelayer-shortcodes');
5288
5289 pagelayer.$$('.pagelayer-leftbar-scroll').slimScroll({
5290 height: '100%',
5291 railVisible: false,
5292 alwaysVisible: true,
5293 color: '#000',
5294 size: '5px',
5295 });
5296
5297 // Hide the ones which are not supposed to be shown
5298 pagelayer.$$('.pagelayer-search-field').on('input', function(){
5299
5300 var val = jQuery(this).val();
5301 var re = new RegExp(val, 'i');
5302
5303 // Show only the required tags
5304 pagelayer.$$('.pagelayer-leftbar-group').each(function(){
5305
5306 var group = jQuery(this);
5307 var res = group.find('[pagelayer-tag]');
5308 var hidden = 0;
5309
5310 res.each(function(){
5311
5312 var tEle = jQuery(this);
5313 if(tEle.find('.pagelayer-shortcode-text').html().match(re)){
5314 tEle.show();
5315 }else{
5316 hidden += 1;
5317 tEle.hide();
5318 }
5319
5320 });
5321
5322 // Hide the whole group
5323 if(hidden == res.length){
5324 group.hide();
5325 }else{
5326 group.show();
5327 }
5328
5329 });
5330 });
5331
5332 // On click Pagelayer setting icon
5333 pagelayer.$$('.pagelayer-settings-icon, .pagelayer-settings').click(function(event){
5334 pagelayer_active = {};
5335
5336 var pl_tag = jQuery(this).attr('pagelayer-tag') || 'pl_post_props';
5337 var nModal = jQuery(this).attr('pagelayer-modal-none');
5338
5339 pagelayer_post_settings(pl_tag);
5340
5341 });
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
5435 // On click search empty
5436 pagelayer.$$('.pagelayer-leftbar-search>.pagelayer-sf-empty').click(function(){
5437 pagelayer.$$('.pagelayer-search-field').val('').trigger('input');
5438 });
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 });
5469 };
5470
5471 // Post setting holder
5472 function pagelayer_post_settings(pl_tag, to_click){
5473
5474 to_click = to_click == -1 ? false : true;
5475
5476 // Is there a post settings ?
5477 var jEle = jQuery(pagelayer_editable+' [pagelayer-tag="'+ pl_tag +'"]');
5478
5479 // Could not find
5480 if(jEle.length < 1){
5481 jEle = pagelayer_create_sc(pl_tag);
5482 var id = pagelayer_id(jEle);
5483 jQuery(pagelayer_editable).prepend(jEle);
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();
5488 }
5489
5490 if(to_click){
5491 jEle.click();
5492 }
5493
5494 return jEle;
5495 }
5496
5497 // Get the closest element and method
5498 function pagelayer_near_by_ele(id, sc){
5499
5500 // Get the previous element of the id element
5501 var prevEle_id = jQuery('[pagelayer-wrap-id="'+id+'"]').prev().attr('pagelayer-wrap-id') || '';
5502 var method, cEle, args = {};
5503
5504 if(prevEle_id.length > 0){
5505
5506 // If have previous element of the id element
5507 // Set the method and previous element selector
5508 args = {'method' : 'after', 'cEle' : '[pagelayer-wrap-id="'+prevEle_id+'"]'};
5509
5510 }else{
5511
5512 // If don't have previous element of the id element then get parent element
5513 if(sc == "pl_row"){
5514 args = {'method' : 'prepend', 'cEle' : pagelayer_editable};
5515 }else{
5516
5517 // Get the parent element
5518 var pEle_id = pagelayer_id(jQuery('[pagelayer-wrap-id="'+id+'"]').closest('.pagelayer-ele'));
5519
5520 // Get the parent element tag
5521 var pEle_tag = pagelayer_tag(jQuery('[pagelayer-id="'+pEle_id+'"]'));
5522 var holder = '>'+ pagelayer_shortcodes[pEle_tag]['holder'] || '';
5523 args = {'method' : 'prepend', 'cEle' : '[pagelayer-id="'+pEle_id+'"] '+ holder+' '};
5524
5525 }
5526
5527 }
5528
5529 return args;
5530
5531 };
5532
5533 // Push the action data in the pagelayer_history_obj object
5534 function pagelayer_history_action_push(args){
5535
5536 var currentTime = new Date();
5537 var history_obj_len = pagelayer_history_obj['action_data'].length;
5538
5539 // If the history_obj_len is less then 1 then set the data in array 0 position
5540 if(history_obj_len < 1){
5541 pagelayer_history_obj['action_data'][0] = {'title' : 'Start Editing', 'action' : 'Start' };
5542 pagelayer_history_obj['current_active_item_id'] = 0;
5543 }
5544
5545 // Remove the second array element if the history_obj_len greater then 100
5546 if(history_obj_len > 100){
5547 pagelayer_history_obj['action_data'].splice(1, 1);
5548 pagelayer_history_obj['current_active_item_id'] = pagelayer_history_obj['action_data'].length - 1;
5549 }
5550
5551 // Get current active history action id
5552 var action_id = parseInt(pagelayer_history_obj['current_active_item_id']) || 0;
5553
5554 // Remove the all array element after the active array element
5555 var del_ele = history_obj_len - action_id - 1;
5556 pagelayer_history_obj['action_data'].splice(action_id + 1, del_ele);
5557
5558 // Check if the same attr set as current active history
5559 if(args.action == "Edited" && history_obj_len > 1 && currentTime - pagelayer.history_lastTime < 1000){
5560 var atts = pagelayer_history_obj['action_data'][action_id] || '';
5561 if(atts['atts'] == args['atts'] && atts['pl_id'] == args['pl_id'] && pagelayer_empty(atts['sub_actions_group']) ){
5562 args['oldVal'] = atts['oldVal'];
5563 pagelayer_history_obj['action_data'][action_id] = args;
5564 pagelayer_history_setup();
5565
5566 // Set the last history time
5567 pagelayer.history_lastTime = currentTime;
5568 return true;
5569 }
5570 }
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
5590 pagelayer_history_obj['action_data'].push(args);
5591 pagelayer_history_obj['current_active_item_id'] = pagelayer_history_obj['action_data'].length - 1;
5592 pagelayer_history_setup();
5593
5594 // Set the last history time
5595 pagelayer.history_lastTime = currentTime;
5596 }
5597
5598 // Setup pagelayer history
5599 function pagelayer_history_setup(force){
5600
5601 var force = force || false;
5602
5603 // If the history tab is visible, only then setup
5604 if(!pagelayer.$$('#pagelayer-history').is(':visible') && !force){
5605 return;
5606 }
5607
5608 // The current active action id
5609 var current_id = pagelayer_history_obj['current_active_item_id'];
5610
5611 // pagelayer-HISTORY - Element Properties Dialog
5612 var pagelayer_history_html = '<div class="pagelayer-history-tabs">'+
5613 '<div class="pagelayer-history-tab" pagelayer-history-tab="actions" pagelayer-history-active-tab="1">Actions</div>'+
5614 '<div class="pagelayer-history-tab" pagelayer-history-tab="revisions">Revisions</div>'+
5615 '</div>'+
5616 '<div class="pagelayer-history-body">'+
5617 '<div class="pagelayer-history-section active" pagelayer-show-tab="actions">';
5618
5619 // Any actions
5620 if(pagelayer_history_obj['action_data'].length > 0){
5621
5622 for(var x in pagelayer_history_obj['action_data']){
5623
5624 if(pagelayer_empty(pagelayer_history_obj['action_data'][x])){continue;}
5625
5626 var title = pagelayer_history_obj['action_data'][x]['title'] || '';
5627 var subTitle = pagelayer_history_obj['action_data'][x]['subTitle'] || '';
5628 var action = pagelayer_history_obj['action_data'][x]['action'] || '';
5629 var tmp_attr = pagelayer_history_obj['action_data'][x]['attrType'] || '';
5630 var eAttr = '';
5631
5632 if(!pagelayer_empty(tmp_attr) && tmp_attr == "tmp_attr"){
5633 eAttr = "pagelayer-history-hidden";
5634 }
5635
5636 pagelayer_history_html += '<div class="pagelayer-history-holder '+((current_id == x) ? 'current_active_item' : '' )+' '+eAttr+'" history-action-id="'+x+'" >'+
5637 '<div class="pagelayer-history-detail-holder">'+
5638 '<span class="pagelayer-history-title"><b> '+title+' </b></span>'+
5639 '<span class="pagelayer-history-subtitle"> '+subTitle+' </span>'+
5640 '<span class="pagelayer-history-action"><i> '+action+' </i></span>'+
5641 '</div>'+
5642 '<div class="pagelayer-history-icon">'+
5643 '<span class="pagelayer-history-check pli pli-checkmark" aria-hidden="true"></span>'+
5644 '</div>'+
5645 '</div>';
5646 }
5647
5648 }else{
5649 pagelayer_history_html += 'No Actions history available yet';
5650 }
5651
5652 pagelayer_history_html += '</div>'+
5653 '<div class="pagelayer-history-section" pagelayer-show-tab="revisions">';
5654
5655 // Any revisions ?
5656 if(pagelayer_revision_obj){
5657 for(var x in pagelayer_revision_obj){
5658 pagelayer_history_html += '<div class="pagelayer-revision-holder" revision-id="'+pagelayer_revision_obj[x]['ID']+'">'+
5659 '<div class="pagelayer-revision-img-holder">'+
5660 '<img src="'+pagelayer_revision_obj[x]['post_author_url']+'" />'+
5661 '</div>'+
5662 '<div class="pagelayer-revision-detail-holder">'+
5663 '<div class="pagelayer-revision-date">'+
5664 pagelayer_revision_obj[x]['post_date_ago']+
5665 '('+pagelayer_revision_obj[x]['post_date']+')'+
5666 '</div>'+
5667 '<div class="pagelayer-revision-author">'+
5668 pagelayer_revision_obj[x]['post_type'] +' by '+
5669 pagelayer_revision_obj[x]['post_author_name']+
5670 '</div>'+
5671 '</div>'+
5672 '<div class="pagelayer-revision-icon-holder">'+
5673 '<i class="pagelayer-revision-delete pli pli-cross"></i>'+
5674 '</div>'+
5675 '</div>';
5676 }
5677
5678 }else{
5679 pagelayer_history_html += 'No Revisions history available';
5680 }
5681
5682 pagelayer_history_html += '</div>'+
5683 '</div>';
5684
5685 // Create the dialog box
5686 pagelayer.$$('#pagelayer-history').html(pagelayer_history_html);
5687 var holder = pagelayer.$$('#pagelayer-history');
5688
5689 // Set active history holder
5690 holder.find('.pagelayer-history-holder').on('click', function(){
5691 var hEle = jQuery(this);
5692 var prev_item_id = pagelayer_history_obj['current_active_item_id'];
5693 hEle.parent().children().removeClass('current_active_item');
5694 hEle.addClass('current_active_item');
5695 var do_item_id = parseInt(hEle.attr('history-action-id'));
5696 pagelayer_history_action_setup(do_item_id, prev_item_id);
5697 });
5698
5699 // Apply revision
5700 holder.find('.pagelayer-revision-holder').on('click', function(){
5701 var revision_id = jQuery(this).attr('revision-id');
5702
5703 jQuery.ajax({
5704 url: pagelayer_ajax_url+'&action=pagelayer_apply_revision&revisionID='+revision_id,
5705 type: 'post',
5706 data: {
5707 pagelayer_nonce: pagelayer_ajax_nonce,
5708 'pagelayer-live' : 1,
5709 },
5710 success: function(response, status, xhr){
5711
5712 var obj = jQuery.parseJSON(response);
5713 if(obj['error']){
5714 pagelayer_show_msg(obj['error'] , 'error');
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
5727 jQuery(pagelayer_editable).html(obj['content']);
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);
5749 pagelayer_add_widget();
5750 pagelayer_show_msg(obj['success'], 'success');
5751 }
5752 }
5753 });
5754 });
5755
5756 // Delete the revision
5757 holder.find('.pagelayer-revision-delete').click(function(e){
5758
5759 e.stopPropagation();
5760 var rEle = jQuery(this).closest('.pagelayer-revision-holder');
5761 var revision_id = rEle.attr('revision-id');
5762
5763 if(confirm("Are you sure you want to delete the revision ?")){
5764 jQuery.ajax({
5765 url: pagelayer_ajax_url+'&action=pagelayer_delete_revision&revisionID='+revision_id,
5766 type: 'post',
5767 data: {pagelayer_nonce: pagelayer_ajax_nonce},
5768 success: function(response, status, xhr){
5769
5770 var obj = jQuery.parseJSON(response);
5771 if(obj['error']){
5772 pagelayer_show_msg(obj['error'], 'error');
5773 }else{
5774 pagelayer_show_msg(obj['success'], 'success');
5775 rEle.hide();
5776 }
5777
5778 }
5779 });
5780 }
5781
5782 });
5783
5784 // The tabs
5785 holder.find('.pagelayer-history-tab').on('click', function(){
5786 var attr = 'pagelayer-history-active-tab';
5787 holder.find('.pagelayer-history-tab').each(function(){
5788 jQuery(this).removeAttr(attr);
5789 });
5790 jQuery(this).attr(attr, 1);
5791
5792 // Get the active tab
5793 var active_tab = holder.find('[pagelayer-history-active-tab]').attr('pagelayer-history-tab');
5794
5795 // Trigger the showing of rows
5796 holder.find('[pagelayer-show-tab]').each(function(){
5797 var sec = jQuery(this);
5798
5799 // Is it the active tab ?
5800 if(sec.attr('pagelayer-show-tab') != active_tab){
5801 sec.hide();
5802 }else{
5803 sec.show();
5804 }
5805 });
5806 });
5807 }
5808
5809 // Get revisions Handler
5810 function pagelayer_get_revision(){
5811
5812 jQuery.ajax({
5813 url: pagelayer_ajax_url+'&action=pagelayer_get_revision&postID='+pagelayer_postID,
5814 type: 'post',
5815 data: {
5816 pagelayer_nonce: pagelayer_ajax_nonce,
5817 },
5818 //async:false,
5819 success: function(response, status, xhr){
5820 var obj = jQuery.parseJSON(response);
5821
5822 if(!pagelayer_empty(obj['error'])){
5823 pagelayer_show_msg(obj['error'], 'error');
5824 }else{
5825 pagelayer_revision_obj = obj;
5826 pagelayer_history_setup(true);
5827 }
5828 }
5829 });
5830 };
5831
5832 // Do the history action - use for ctrl-z and ctrl-y
5833 function pagelayer_do_history(action){
5834
5835 var cur_id = pagelayer_history_obj['current_active_item_id'];
5836 var new_id = cur_id;
5837 var action_data_len = pagelayer_history_obj['action_data'].length;
5838
5839
5840 if(action == 'undo'){
5841
5842 // You cannot undo from the first movement
5843 if(cur_id == 0){
5844 return true;
5845 }
5846
5847 for(var i = (cur_id - 1); i => 0; i--){
5848
5849 var action = pagelayer_history_obj['action_data'][i];
5850
5851 if('attrType' in action && action['attrType'] == 'tmp_attr'){
5852 continue;
5853 }
5854
5855 new_id = i;
5856 break;
5857
5858 }
5859
5860 }else if(action == 'redo'){
5861 for(var i = cur_id + 1; i < action_data_len; i++){
5862
5863 var action = pagelayer_history_obj['action_data'][i];
5864
5865 if('attrType' in action && action['attrType'] == 'tmp_attr'){
5866 continue;
5867 }
5868
5869 new_id = i;
5870 break;
5871
5872 }
5873 }
5874
5875 // Do the action
5876 pagelayer_history_action_setup(new_id, cur_id);
5877 pagelayer_history_setup();
5878
5879 };
5880
5881 // Action setup handle on ctrl-z and ctrl-y
5882 function pagelayer_history_action_setup(current_item_id, prev_item_id){
5883
5884 // Set this as the current active
5885 pagelayer_history_obj['current_active_item_id'] = current_item_id;
5886
5887 // Delete the element
5888 var delete_ele = function(id){
5889
5890 // Set Pagelayer History FALSE to prevent saving delete action in action history
5891 pagelayer.history_action = false;
5892
5893 pagelayer_delete_element('[pagelayer-id='+id+']');
5894
5895 // Set Pagelayer History TRUE
5896 pagelayer.history_action = true;
5897
5898 };
5899
5900 // Re-setup the element
5901 var resetup_ele = function(history_array){
5902 jQuery(history_array.cEle.cEle)[history_array.cEle.method](history_array.html);
5903 pagelayer_element_setup('[pagelayer-id='+history_array.pl_id+'], [pagelayer-id='+history_array.pl_id+'] .pagelayer-ele', true);
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);
5909 };
5910
5911 // Re-setup the element attr
5912 var reset_ele_attr = function(hEle, atts, val, attrType){
5913
5914 // Set Pagelayer History FALSE to prevent saving attributes in action history
5915 pagelayer.history_action = false;
5916 if(attrType == "tmp_attr"){
5917 pagelayer_set_tmp_atts(hEle, atts, val);
5918 }else{
5919 pagelayer_set_atts(hEle, atts, val);
5920 }
5921
5922 // The property holder
5923 var holder = pagelayer.$$('.pagelayer-elpd-body');
5924 holder.html(' ');
5925 pagelayer_sc_render(hEle);
5926 pagelayer_elpd_generate(hEle, holder);
5927 pagelayer.history_action = true;
5928
5929 };
5930
5931 // Move element
5932 var pagelayer_move_ele = function(id, move_loc){
5933 var eWrap = pagelayer_wrap_by_id(id);
5934 var pCol = eWrap.closest('.pagelayer-col-holder') || '';
5935
5936 jQuery(move_loc.cEle)[move_loc.method](eWrap);
5937
5938 // Ensure the column is not empty
5939 if(!pagelayer_empty(pCol)){
5940 pagelayer_empty_col(pCol);
5941 pagelayer_empty_col(pagelayer_wrap_by_id(id).closest('.pagelayer-col-holder'));
5942 }
5943
5944 pagelayer_do_dirty(eWrap);
5945 };
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
5990 if(prev_item_id > current_item_id){
5991
5992 // All Actions for undo here
5993 var i = parseInt(prev_item_id);
5994
5995 for(i; i > current_item_id; i--){
5996
5997 var history_array = pagelayer_history_obj['action_data'][i];
5998 var sub_actions_group = history_array['sub_actions_group'] || '';
5999
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 }
6006 }
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 }
6017 }
6018
6019 }else{
6020
6021 // All Actions for redo here
6022 var i = parseInt(prev_item_id)+1;
6023
6024 for(i; i <= current_item_id; i++){
6025
6026 var history_array = pagelayer_history_obj['action_data'][i];
6027 var sub_actions_group = history_array['sub_actions_group'] || '';
6028 // Main action
6029 pagelayer_redo_action(history_array);
6030
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]);
6035 }
6036 }
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 }
6044 }
6045 }
6046
6047 };
6048
6049 // Report an error
6050 function pagelayer_error(error, func){
6051 var prefix = func || '';
6052 alert(prefix+error);
6053 };
6054
6055 function pagelayer_bottombar(){
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>'+
6071 '</div>'+
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>'+
6088 '</div>';
6089
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
6096 holder.find('.pagelayer-update-button').on('click', function(){
6097 pagelayer_save();
6098 pagelayer_history_setup();// Setup history tab after update
6099 });
6100
6101 holder.find('.pagelayer-close-button').on('click', function(){
6102 pagelayer_close();
6103 });
6104
6105 holder.find('.screen-mode').on('click', function(){
6106 var screen_mode = jQuery(this).attr('pagelayer-mode-data');
6107 pagelayer_set_screen_mode(screen_mode);
6108 holder.find('.screen-mode').removeClass('active');
6109 jQuery(this).addClass('active');
6110 });
6111
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'));
6114 pagelayer.$$('.pagelayer-logo').hide();
6115 pagelayer_leftbar_tab('pagelayer-history');
6116 pagelayer_active = {};
6117 pagelayer_history_setup();
6118 });
6119
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'));
6122 pagelayer.$$('.pagelayer-logo').hide();
6123
6124 // If the navigator tab visible, then don't setup
6125 if(!pagelayer.$$('#pagelayer-navigator').is(':visible')){
6126 pagelayer_navigator_setup();
6127 }
6128
6129 pagelayer_leftbar_tab('pagelayer-navigator');
6130 pagelayer_active = {};
6131 });
6132
6133 holder.find('.pagelayer-preview').click(function(){
6134
6135 // If the page is not dirty
6136 if(!pagelayer_isDirty){
6137
6138 // Open in new tab the existing page itself
6139 window.open(pagelayer_post_permalink, '_blank');
6140 return;
6141
6142 }
6143
6144 // Get post content
6145 var post = pagelayer_generate_sc(pagelayer_editable);//alert(post);return;
6146
6147 pagelayer.$$('.pagelayer-body').css({'opacity' : '0.33'});
6148 jQuery.ajax({
6149 url: pagelayer_ajax_url+'&action=pagelayer_create_post_autosave&postID='+pagelayer_postID,
6150 type: 'POST',
6151 data: {
6152 'pagelayer_nonce': pagelayer_ajax_nonce,
6153 'pagelayer_post_content': pagelayer_Base64.encode(post)
6154 },
6155 success: function(data) {
6156 var data = JSON.parse(data);
6157
6158 // If there is some error
6159 if(!pagelayer_empty(data['error']) || pagelayer_empty(data['id'])){
6160 pagelayer_show_msg('Unable to set preview for some reason', 'error');
6161 return;
6162 }
6163
6164 var url = data['url']+'&preview_id='+pagelayer_postID+'&preview_nonce='+
6165 pagelayer_preview_nonce;
6166
6167 // Open in new tab
6168 window.open(url, '_blank');
6169 },
6170 complete: function(){
6171 pagelayer.$$('.pagelayer-body').css({'opacity' : '1'});
6172 }
6173 });
6174 });
6175 };
6176
6177
6178 ///////////////////////////////
6179 // Miscellaneuos Functions
6180 ///////////////////////////////
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
6276 // Setup navigator
6277 function pagelayer_navigator_setup(){
6278
6279 var navigator_ele = pagelayer.$$('#pagelayer-navigator'),
6280 navigator_padding = 10,
6281 navigator_html = '';
6282
6283 // Get the child elements list
6284 var pagelayer_create_navi_list = function(selector){
6285
6286 var navigator_list = '';
6287
6288 selector.children('.pagelayer-ele-wrap, .pagelayer-ele').each(function(){
6289
6290 var cEle = jQuery(this),
6291 tag = pagelayer_tag(cEle),
6292 id = pagelayer_id(cEle),
6293 child_ele = false,
6294 ele_class = '';
6295
6296 // If tag is not found then return
6297 if(pagelayer_empty(tag)){
6298 return;
6299 }
6300
6301 // if is row or col or inner-row
6302 if(tag == 'pl_row' || tag == 'pl_col' || tag == 'pl_inner_row'){
6303 ele_class = 'pagelayer-navigator-toggle';
6304 child_ele = true;
6305 }
6306
6307 navigator_list += '<div class="pagelayer-navigetor-ele" pagelayer-id="'+id+'">'+
6308 '<div class="pagelayer-ele-name '+ ele_class +'" pagelayer-tag="'+tag+'" style="padding-left:'+navigator_padding+'px">'+
6309 '<i class="fa pagalayer-arrow"></i><i class="fa pagelayer-'+tag+'"></i>'+
6310 pagelayer_shortcodes[tag]['name']+
6311 '<span class="pagelayer-navigator-options"><i class="pli pli-pencil" data-action="edit"></i><i class="pli pli-trashcan" data-action="delete"></i></span>'+
6312 '</div>';
6313
6314 // Create the list of child element
6315 if(child_ele){
6316 navigator_padding += 15; // Increment padding left for widget
6317 navigator_list += pagelayer_create_navi_list( cEle.find(pagelayer_shortcodes[tag]['holder']).first() );
6318 navigator_padding -= 15; // Decrement padding left for widget
6319 }
6320
6321 navigator_list += '</div>';
6322 });
6323
6324 return navigator_list;
6325 }
6326
6327 // Create list of all rows and their child widgets
6328 jQuery(pagelayer_editable).children('.pagelayer-wrap-row').each(function(){
6329 navigator_html += pagelayer_create_navi_list(jQuery(this));
6330 });
6331
6332 // Put the navigator list
6333 navigator_ele.html('<div class="pagelayer-leftbar-prop-body">'+navigator_html+'</div>');
6334
6335 // edit and delete element click handler
6336 navigator_ele.find('.pagelayer-navigator-options .pli').on('click', function(event){
6337
6338 var sEle = jQuery(this).closest('.pagelayer-navigetor-ele');
6339 var sId = sEle.attr('pagelayer-id');
6340 var action = jQuery(this).data('action');
6341 if( action == 'edit'){
6342 pagelayer_edit_element('[pagelayer-id = '+sId+']', event);
6343 }else if(action == 'delete'){
6344 sEle.find('.pagelayer-ele-name').css({'background':'rgb(255, 114, 114)','opacity':'0.5'});
6345 pagelayer_delete_element('[pagelayer-id = '+sId+']');
6346 }
6347
6348 });
6349
6350 // On click toggle the element
6351 navigator_ele.find('.pagelayer-ele-name').on('click', function(){
6352
6353 var tEle = jQuery(this);
6354 var pl_id = tEle.parent().attr('pagelayer-id'); // Get Pagelayer id
6355 var jEle = pagelayer_ele_by_id(pl_id);
6356
6357 // If the class "pagelayer-navigator-toggle" exist then toggle
6358 if(tEle.hasClass('pagelayer-navigator-toggle')){
6359 tEle.parent().toggleClass('pagelayer-navigator-open');
6360 }
6361
6362 // Also open all parents
6363 tEle.parent().parents('.pagelayer-navigetor-ele').addClass('pagelayer-navigator-open');
6364
6365 // Set the click element active
6366 navigator_ele.find('.pagelayer-ele-name').removeClass('pagelayer-navi-active');
6367 tEle.addClass('pagelayer-navi-active')
6368
6369 // Set the element active
6370 if(jEle.length > 0){
6371 //pagelayer_active.el = pagelayer_data(jEle);
6372 pagelayer_set_active(jEle);
6373 pagelayer_scroll_to_viewport(jEle);
6374 }
6375
6376 });
6377
6378 // Do active ele tab open
6379 if( pagelayer_active.el && pagelayer_active.el.id ){
6380 navigator_ele.find('[pagelayer-id="'+pagelayer_active.el.id+'"]').children('.pagelayer-ele-name').click();
6381 }
6382
6383 /* var posY = 0, orig_eleY= 0;
6384
6385 // On mouse down in pagelayer-ele-name
6386 navigator_ele.find('.pagelayer-ele-name').on('mousedown', function(e){
6387 e = e || window.event;
6388 e.preventDefault();
6389
6390 // Get ele position
6391 orig_eleY = jQuery(this).offset().top;
6392
6393 // Get the mouse cursor at startup:
6394 posY = e.clientY;
6395
6396 // The variable needs to be empty.
6397 newMethod = '';
6398
6399 // Mouse up handler
6400 var ele_mousemove = function(){
6401
6402 }
6403
6404 // Mouse move handler
6405 var ele_mouseup = function(){
6406 pagelayer.$$(document).off('mouseup', ele_mouseup);
6407 pagelayer.$$(document).off('mousemove', ele_mousemove);
6408 }
6409
6410 pagelayer.$$(document).on('mouseup', ele_mouseup);
6411 pagelayer.$$(document).on('mousemove', ele_mousemove);
6412
6413 }); */
6414
6415
6416 }
6417
6418 // Scroll page to element view port
6419 function pagelayer_scroll_to_viewport(jEle, timeout, parentEle){
6420
6421 var scrolled = parentEle || jQuery('html, body');
6422 timeout = timeout || 500;
6423 parentEle = parentEle || jQuery(window);
6424
6425 setTimeout(function(){
6426 var parentHeight = parentEle.height(),
6427 parentScrollTop = parentEle.scrollTop(),
6428 elementTop = jEle.offset().top,
6429 topToCheck = elementTop - parentScrollTop;
6430
6431 if (topToCheck > 0 && topToCheck < parentHeight) {
6432 return;
6433 }
6434
6435 var scrolling = elementTop - parentHeight / 2;
6436 scrolled.stop(true).animate({
6437 scrollTop: scrolling
6438 }, 1000);
6439 }, timeout);
6440 }
6441
6442 // Generates a random string of "n" characters
6443 function pagelayer_randstr(n, special){
6444 var text = '';
6445 var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
6446
6447 special = special || 0;
6448 if(special){
6449 possible = possible + '&#$%@';
6450 }
6451
6452 for(var i=0; i < n; i++){
6453 text += possible.charAt(Math.floor(Math.random() * possible.length));
6454 }
6455
6456 return text;
6457 };
6458
6459 function pagelayer_randInt(max) {
6460 return Math.floor(Math.random() * Math.floor(max));
6461 }
6462
6463 // Convert the regular URL of a Video to a Embed URL
6464 function pagelayer_video_url(src, no_url){
6465
6466 no_url = no_url || false;
6467 var youtubeRegExp = /youtube\.com|youtu\.be/;
6468 var vimeoRegExp = /vimeo\.com/;
6469 var match = '';
6470 var videoId = '';
6471 var vid_params = {};
6472
6473 if (youtubeRegExp.exec(src)) {
6474 match = 'youtube';
6475 } else if (vimeoRegExp.exec(src)) {
6476 match = 'vimeo';
6477 }
6478
6479 switch(match){
6480 case 'youtube':
6481
6482 var youtubeRegExp1 = /youtube\.com/;
6483 var youtubewatch = /watch/;
6484 var youtubeembed = /embed/;
6485 var youtube = /youtu\.be/;
6486
6487 if (youtubeRegExp1.exec(src)) {
6488
6489 if (youtubewatch.exec(src)) {
6490 videoId = src.split('?v=');
6491
6492 } else if (youtubewatch.exec(src)) {
6493 videoId = src.split('embed/');
6494 }
6495
6496 } else if (youtube.exec(src)) {
6497 videoId = src.split('.be/');
6498 }
6499
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();
6507
6508 break;
6509
6510 case 'vimeo':
6511
6512 var vimeoplayer = /player\.vimeo\.com/;
6513 var vimeovideo = /video/;
6514
6515 if (vimeoplayer.exec(src) && vimeovideo.exec(src)) {
6516 videoId = src.split('video/');
6517 } else if (vimeoRegExp.exec(src)) {
6518 videoId = src.split('.com/');
6519 }
6520
6521 vid_params = {
6522 type : 'vimeo',
6523 src : '//player.vimeo.com/video/'+videoId[1],
6524 id : videoId[1]
6525 };
6526
6527 break;
6528 default:
6529 vid_params = {
6530 type : 'local',
6531 src : src
6532 };
6533
6534 }
6535
6536 if(!no_url){
6537 return vid_params.src;
6538 }
6539
6540 return vid_params;
6541 };
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
6554 // Add widget section
6555 function pagelayer_add_widget(){
6556
6557 html='<div class="pagelayer-add-widget-area">'+
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 '</div>'+
6562 '<p class="pagelayer-add-widget-text">Click here to add new row OR drag widgets</p>'+
6563 '</div>';
6564
6565 jQuery(pagelayer_editable).append(html);
6566
6567 var add_area = jQuery('.pagelayer-add-widget-area');
6568
6569 // Add a code before this
6570 var add_sc = function(tag, global_id = ''){
6571
6572 var attr = '';
6573 if(!pagelayer_empty(global_id)){
6574 attr = ' pagelayer-global-id="'+global_id+'" ';
6575 }
6576
6577 // Create Row
6578 var row = jQuery('<div pagelayer-tag="pl_row" '+((tag == 'pl_row') ? attr : '') +'></div>');
6579 add_area.before(row);
6580 var row_id = pagelayer_onadd(row, false);
6581 var rEle = pagelayer_ele_by_id(row_id);
6582
6583 if(tag == 'pl_row' && !pagelayer_empty(global_id)){
6584 rEle.click();
6585 return row_id;
6586 }
6587
6588 // Create Column
6589 var col = jQuery('<div pagelayer-tag="pl_col" '+((tag == 'pl_col') ? attr : '') +'></div>');
6590 rEle.find('.pagelayer-row-holder').append(col);
6591 var col_id = pagelayer_onadd(col, false);
6592 var cEle = pagelayer_ele_by_id(col_id);
6593
6594
6595 if(tag == 'pl_row'){
6596 rEle.click();
6597 return row_id;
6598 }
6599
6600 if(tag == 'pl_col'){
6601 cEle.click();
6602 return col_id;
6603 }
6604
6605 // Create element
6606 var ele = jQuery('<div pagelayer-tag="'+tag+'" '+attr+'></div>');
6607 cEle.find('.pagelayer-col-holder').append(ele);
6608 //console.log(ele);
6609 var id = pagelayer_onadd(ele);
6610 //console.log(id);
6611 //console.log(col_id);
6612 var eEle = pagelayer_ele_by_id(col_id);
6613 //console.log(eEle);
6614 // Ensure the column is not empty
6615 pagelayer_empty_col(cEle.find('.pagelayer-col-holder'));
6616
6617 if(tag == 'pl_inner_row' && pagelayer_empty(global_id)){
6618 // Create Column
6619 var in_col = jQuery('<div pagelayer-tag="pl_col"></div>');
6620 eEle.find('.pagelayer-row-holder').append(in_col);
6621 var in_col_id = pagelayer_onadd(in_col, false);
6622 }
6623
6624 return id;
6625
6626 }
6627
6628 // Handle Click on Plus Button
6629 add_area.find('.pagelayer-add-circle-plus').on('click', function(e){
6630 e.stopPropagation();
6631 add_sc('pl_col');
6632 });
6633
6634 // Handle Click on Template/Folder Button
6635 add_area.find('.pagelayer-add-section').on('click', function(e){
6636 e.stopPropagation();
6637 pagelayer_add_section_area();// Setup and show sections modal
6638 });
6639
6640
6641
6642 // Background click fallback (adds column if clicked outside circles)
6643 add_area.on('click', function(e){
6644 if(e.target === this || jQuery(e.target).hasClass('pagelayer-add-widget-text')){
6645 e.stopPropagation();
6646 add_sc('pl_col');
6647 }
6648 });
6649
6650 // Handle Drag over
6651 add_area.on('dragover', function(e){
6652 //console.log(e)
6653 add_area.addClass('pagelayer-add-widget-drag');
6654 });
6655
6656 // Handle Drag Leave
6657 add_area.on('dragleave', function(e){
6658 //console.log(e)
6659 add_area.removeClass('pagelayer-add-widget-drag');
6660 });
6661
6662 // Handle On Drop
6663 add_area.on('drop', function(e){
6664
6665 //console.log(e);
6666 //console.log(e.originalEvent.dataTransfer.getData('tag'));
6667 add_area.removeClass('pagelayer-add-widget-drag');
6668 jQuery('.pagelayer-is-dragging').removeClass('pagelayer-is-dragging');
6669
6670 var tag = e.originalEvent.dataTransfer.getData('tag');
6671 var global_id = e.originalEvent.dataTransfer.getData('global_id');
6672
6673 // Is it an existing element ?
6674 if(tag.length < 1){
6675 return false;
6676 }
6677
6678 e.preventDefault();
6679
6680 //console.log(tag);
6681
6682 add_sc(tag, global_id);
6683 });
6684 };
6685
6686 // Is the element in view while scrolling
6687 function pagelayer_isElementInView(elem, holder, partial) {
6688 partial = partial || true;
6689 var container = jQuery(holder);
6690 var contHeight = container.height();
6691 var contTop = container.scrollTop();
6692 var contBottom = contTop + contHeight ;
6693
6694 var elemTop = jQuery(elem).offset().top - container.offset().top;
6695 var elemBottom = elemTop + jQuery(elem).height();
6696
6697 var isTotal = (elemTop >= 0 && elemBottom <=contHeight);
6698 var isPart = ((elemTop < 0 && elemBottom > 0 ) || (elemTop > 0 && elemTop <= container.height())) && partial;
6699
6700 return isTotal || isPart ;
6701 }
6702
6703 // Append section modal into body
6704 function pagelayer_add_section_area(){
6705
6706 var body = pagelayer.$$('body');
6707 var mEle = body.find('.pagelayer-add-section-modal-container');
6708
6709 if(mEle.length > 0){
6710 mEle.show();
6711 return;
6712 }
6713
6714 var section_modal = '<div class="pagelayer-add-section-modal-container">'+
6715 '<div class="pagelayer-add-section-modal-holder">'+
6716 '<div class="pagelayer-add-section-modal">'+
6717 '<div class="pagelayer-add-section-modal-header">'+
6718 '<div>Add Sections</div>'+
6719 '<div class="pagelayer-section-type-div">Type : '+
6720 '<select name="type" id="pagelayer-section-type">'+
6721 '<option value="section">Sections</option>'+
6722 '<option value="header">Headers</option>'+
6723 '<option value="footer">Footers</option>'+
6724 '<option value="page">Pages</option>'+
6725 '</select>'+
6726 '</div>'+
6727 '<div class="pagelayer-add-section-modal-close">&times;</div>'+
6728 '</div>'+
6729 '<div class="pagelayer-add-section-modal-row">'+
6730 '<div class="pagelayer-add-section-modal-left">'+
6731 '<div class="pagelayer-section-search-div">'+
6732 '<i class="pli pli-search" ></i><input class="pagelayer-section-search" /><span class="pagelayer-sf-empty pli">&times;</span>'+
6733 '</div>'+
6734 '<div class="pagelayer-section-tags-holder"></div>'+
6735 '</div>'+
6736 '<div class="pagelayer-section-modal-body-holder">'+
6737 '<div class="pagelayer-add-section-modal-body"></div>'+
6738 '</div>'+
6739 '</div>'+
6740 '<div class="pagelayer-add-section-modal-overlay" style="display:none;">'+
6741 '<div class="pagelayer-section-wait">'+
6742 '<div class="pagelayer-loader">'+
6743 '<div class="pagelayer-percent-parent"></div>'+
6744 '</div><br/>'+
6745 '<span>Please wait a moment</span>'+
6746 '</div>'+
6747 '</div>'+
6748 '</div>'+
6749 '</div>'+
6750 '</div>';
6751
6752 mEle = jQuery(section_modal);
6753
6754 // Append the element in the body
6755 body.append(mEle);
6756
6757 // On click close modal
6758 mEle.find('.pagelayer-add-section-modal-close').on('click', function(){
6759 mEle.hide();
6760 });
6761
6762 // Search Empty
6763 mEle.find('.pagelayer-sf-empty').on('click', function(){
6764 mEle.find('.pagelayer-section-search').val('');
6765 });
6766
6767 // On select section type
6768 mEle.find('#pagelayer-section-type').on('change', function(){
6769 var val = jQuery(this).val();
6770 pagelayer_add_sections_list_setup(val);
6771 });
6772
6773 // Append the list items into modal body
6774 pagelayer_add_sections_list_setup();
6775
6776 mEle.show();// Show the modal
6777
6778 };
6779
6780 // Append section list into modal body
6781 function pagelayer_add_sections_list_setup(type){
6782
6783 var mEle = pagelayer.$$('.pagelayer-add-section-modal-container');
6784 var body = mEle.find('.pagelayer-add-section-modal-body');
6785 var add_area = jQuery('.pagelayer-add-widget-area');
6786 type = type || 'section';
6787
6788 // Find the number of cols
6789 var body_width = jQuery(window.parent).width();
6790 var num_cols = 3;
6791 if(body_width >= 1500){
6792 num_cols = 4;
6793 }else if(body_width >= 992){
6794 num_cols = 3;
6795 }else if(body_width >= 768){
6796 num_cols = 2;
6797 }else if(body_width >= 360){
6798 num_cols = 1;
6799 }
6800 //console.log(num_cols+' - '+body_width);
6801
6802 var viewer = '<div class="pagelayer-section-is-visible"></div>';
6803 var selected_tags = {};
6804 var result_set = {};
6805
6806 // Setup the scroll
6807 mEle.find('.pagelayer-section-tags-holder').slimScroll({
6808 height: 'calc(100vh - 150px)',
6809 railVisible: false,
6810 alwaysVisible: true,
6811 color: '#000',
6812 size: '5px',
6813 });
6814
6815 // Create list of items
6816 var pagelayer_section_list = function(){
6817
6818 // List the tags
6819 if(!pagelayer_empty(pagelayer_add_section_data[type]['tags'])){
6820 var tags_html = '';
6821 var tags = pagelayer_add_section_data[type]['tags'];
6822 for(var k in tags){
6823 tags_html += '<span class="pagelayer-section-tags" tag="'+k+'">'+k+' ('+tags[k].length+')</span>';
6824 }
6825 mEle.find('.pagelayer-section-tags-holder').html(tags_html);
6826
6827 // Handle tag click
6828 mEle.find('.pagelayer-section-tags').unbind('click');
6829 mEle.find('.pagelayer-section-tags').on('click', function(e){
6830
6831 var search = mEle.find('.pagelayer-section-search');
6832
6833 // Blank the search
6834 if(search.val().length > 0){
6835 search.val('');
6836 selected_tags = {};
6837 }
6838
6839 // Fill the selected_tags
6840 tEle = jQuery(this);
6841 var tag = tEle.attr('tag')
6842
6843 if(tEle.attr('on') == '1'){
6844 delete selected_tags[tag];
6845 tEle.removeAttr('on');
6846 }else{
6847 tEle.attr('on', 1);
6848 selected_tags[tag] = 1;
6849 }
6850
6851 // Filter
6852 pagelayer_section_filter(false, 1);
6853
6854 });
6855 }
6856
6857 // Fill in the result
6858 result_set = { ...pagelayer_add_section_data[type]['list']};
6859
6860 show_result();
6861
6862 };
6863
6864 // How the result and setup scroll
6865 var show_result = function(){
6866
6867 var html = '';
6868 for(var i = 0; i < num_cols; i++){
6869 html += '<div class="pagelayer-section-holder" pagelayer-section-type="'+type+'" num="'+i+'"></div>';
6870 }
6871
6872 // Blank the body
6873 body.html(html+viewer);
6874
6875 mEle.find('.pagelayer-section-modal-body-holder').unbind('scroll');
6876 mEle.find('.pagelayer-section-modal-body-holder').on('scroll', pagelayer_section_body_scroll);
6877 pagelayer_section_body_scroll();
6878 }
6879
6880 var scroll_accessed = false;
6881
6882 // Section body ON scroll
6883 var pagelayer_section_body_scroll = function(){
6884
6885 // Check if there is anything to display in the first place, as we do delete pagelayer_add_section_data
6886 if(pagelayer_empty(result_set)){
6887 return;
6888 }
6889
6890 var tester = mEle.find('.pagelayer-section-is-visible');
6891 var modal = mEle.find('.pagelayer-section-modal-body-holder');
6892
6893 // If we have scroll
6894 if(!pagelayer_isElementInView(tester, modal) || scroll_accessed){
6895 return;
6896 }
6897
6898 scroll_accessed = true;
6899
6900 var html = '';
6901 var i = 0;
6902
6903 // Loop result_set
6904 for(var id in result_set){
6905
6906 if(i >= (num_cols * 5)){
6907 break;
6908 }
6909
6910 var col = i % num_cols;
6911 //console.log(col);
6912
6913 i++;
6914
6915 var pro = 0;
6916
6917 // Is it pro ?
6918 if(!pagelayer_empty(result_set[id]) && pagelayer_empty(pagelayer_pro)){
6919 pro = 1;
6920 }
6921
6922 html = '<div class="pagelayer-section-item" pagelayer-section-type="'+type+'" pagelayer-add-section-id="'+id+'">'+
6923 '<img src="'+ pagelayer_add_section_data[type]['image_url'] + id +'/screenshot.jpg" alt="Pagelayer code screenshot" />'+
6924 (pro ? '<div class="pagelayer-section-pro-req">Pro</div><div class="pagelayer-section-pro-txt">'+pagelayer.pro_txt+'</div>' : '')+
6925 '</div>';
6926
6927 body.find('.pagelayer-section-holder[num='+col+']').append(html);
6928
6929 delete result_set[id];
6930
6931 }
6932
6933 //console.log(result_set);
6934
6935 mEle.find('.pagelayer-section-item').unbind('click');
6936 mEle.find('.pagelayer-section-item').on('click', function(e){
6937 pagelayer_section_item_clickable(jQuery(this));
6938 });
6939
6940 scroll_accessed = false;
6941
6942 }
6943
6944 // If we have searched something / or clicked tags
6945 var pagelayer_section_filter = function(event, not_input){
6946
6947 var txt = mEle.find('.pagelayer-section-search').val();
6948 var tags = pagelayer_add_section_data[type]['tags'];
6949
6950 // Searched anything
6951 if(!pagelayer_empty(txt) || pagelayer_empty(not_input)){
6952
6953 // Blank the tags
6954 selected_tags = {};
6955
6956 mEle.find('.pagelayer-section-tags').removeAttr('on');
6957
6958 for(var k in tags){
6959 if(k.search(txt) >= 0){
6960 selected_tags[k] = 1;
6961 mEle.find('.pagelayer-section-tags[tag="'+k+'"]').attr('on', 1);
6962 }
6963 }
6964
6965 }
6966
6967 var new_result = {};
6968 var new_length = 0;
6969
6970 // Filter the content
6971 for(var t in selected_tags){
6972
6973 for(var i in tags[t]){
6974 new_length++;
6975 new_result[tags[t][i]] = tags[t][i];
6976 }
6977
6978 }
6979
6980 // Copy the result
6981 result_set = {...new_result};
6982 //console.log(type);console.log(selected_tags);console.log(result_set);
6983
6984 show_result();
6985
6986 }
6987
6988 // On search change
6989 mEle.find('.pagelayer-section-search').unbind('input');
6990 mEle.find('.pagelayer-section-search').on('input', pagelayer_section_filter);
6991
6992 // On click items
6993 var pagelayer_section_item_clickable = function(jEle){
6994
6995 var section_id = jEle.attr('pagelayer-add-section-id');
6996
6997 // IF section id not found
6998 if(pagelayer_empty(section_id)){
6999 return false;
7000 }
7001
7002 if(jEle.find('.pagelayer-section-pro-req').length > 0){
7003 return false;
7004 }
7005
7006 // Show the overlay
7007 mEle.find('.pagelayer-add-section-modal-overlay').show();
7008
7009 // Do shortcode the content
7010 jQuery.ajax({
7011 url: pagelayer_ajax_url+'&action=pagelayer_get_section_shortcodes&postID='+pagelayer_postID,
7012 type: 'POST',
7013 data: {
7014 'pagelayer_nonce': pagelayer_ajax_nonce,
7015 'pagelayer_section_id': section_id,
7016 'pagelayer-live': 1
7017 },
7018 success: function(data) {
7019
7020 try{
7021
7022 var data = JSON.parse(data);
7023
7024 if(!pagelayer_empty(data['error'])){
7025 pagelayer_show_msg('Error getting the section', 'error');
7026 mEle.find('.pagelayer-add-section-modal-overlay').hide();
7027 mEle.hide();
7028 return;
7029 }
7030
7031 var cEle = jQuery(data['code']);
7032
7033 // Add section before add widget area
7034 add_area.before(cEle);
7035
7036 // We need to it setup
7037 cEle.each(function(){
7038 var pl_id = pagelayer_id(jQuery(this));
7039
7040 if(!pagelayer_empty(pl_id)){
7041 pagelayer_element_setup('[pagelayer-id="'+pl_id+'"], [pagelayer-id='+pl_id+'] .pagelayer-ele', true);
7042 }
7043 });
7044
7045 }catch(e){
7046 pagelayer_show_msg('Error getting the section', 'error');
7047 mEle.find('.pagelayer-add-section-modal-overlay').hide();
7048 mEle.hide();
7049 return;
7050 }
7051
7052 },
7053 complete: function(){
7054 mEle.find('.pagelayer-add-section-modal-overlay').hide();
7055 mEle.hide();
7056 }
7057 });
7058 }
7059
7060 // Load the data if not there
7061 if(!(type in pagelayer_add_section_data)){
7062
7063 // Show the loading
7064 mEle.find('.pagelayer-add-section-modal-overlay').show();
7065
7066 // Get the sections list data and append it
7067 jQuery.ajax({
7068 url: pagelayer_api_url+'/library.php?give='+type,
7069 type: 'post',
7070 success: function(response){
7071 var tmp = JSON.parse(response);
7072
7073 // Is the list there ?
7074 if( !('list' in tmp && !pagelayer_empty(tmp['list'])) ){
7075 return;
7076 }
7077
7078 pagelayer_add_section_data[type] = tmp;
7079
7080 // Create the Type
7081 pagelayer_section_list(type);
7082
7083 // Hide the loading
7084 mEle.find('.pagelayer-add-section-modal-overlay').hide();
7085
7086 },
7087 complete: function(){
7088 mEle.find('.pagelayer-add-section-modal-overlay').hide();
7089 }
7090 });
7091
7092 // We have the data, so show it
7093 }else{
7094 pagelayer_section_list(type);
7095 }
7096 }
7097
7098 // Upload an image
7099 function pagelayer_upload_image(fileName, blob, pagelayer_ajax_func){
7100
7101 var formData = new FormData();
7102 formData.append('action', 'upload-attachment');
7103 formData.append('_ajax_nonce', pagelayer_media_ajax_nonce);
7104 formData.append('async-upload', blob, fileName);
7105
7106 jQuery.ajax({
7107 url:pagelayer_ajax_url,
7108 data: formData,// the formData function is available in almost all new browsers.
7109 type:"post",
7110 contentType:false,
7111 processData:false,
7112 cache:false,
7113 beforeSend: function( xhr ) {
7114 if(typeof pagelayer_ajax_func.beforeSend == 'function'){
7115 pagelayer_ajax_func.beforeSend(xhr);
7116 }
7117 },
7118 xhr: function() {
7119 var xhr = new window.XMLHttpRequest();
7120 if(typeof pagelayer_ajax_func.uploadProgress == 'function'){
7121 xhr = pagelayer_ajax_func.uploadProgress(xhr);
7122 }
7123 return xhr;
7124 },
7125 error:function(err){
7126 //console.error(err);
7127 pagelayer_show_msg('Unable to upload image for some reason.', 'error');
7128 },
7129 success:function(response){
7130 var obj = jQuery.parseJSON(response);
7131 if(typeof pagelayer_ajax_func.success == 'function'){
7132 pagelayer_ajax_func.success(obj);
7133 }
7134 },
7135 complete:function(xhr){
7136 if(typeof pagelayer_ajax_func.complete == 'function'){
7137 pagelayer_ajax_func.complete(xhr);
7138 }
7139 }
7140 });
7141 };
7142
7143 // On editable area image paste handler
7144 function pagelayer_editable_paste_handler(pasteEvent, pagelayer_ajax_func){
7145 var items,
7146 is_Paste = (pasteEvent.type == 'paste' ? true : false),
7147 mustPreventDefault = false,
7148 reader;
7149
7150 try {
7151 if(is_Paste){
7152 items = (pasteEvent.originalEvent || pasteEvent).clipboardData.items;
7153 }else{
7154 items = [pasteEvent];
7155 }
7156
7157 for (var i = items.length - 1; i >= 0; i -= 1) {
7158
7159 if (items[i].type.match(/^image\//)) {
7160
7161 reader = new FileReader();
7162 /* jshint -W083 */
7163 reader.onloadend = function(event) {
7164
7165 var src = event.target.result;
7166
7167 if(src.indexOf('data:image') === 0 ) {
7168
7169 var block = src.split(";");
7170 var contentType = block[0].split(":")[1];
7171 var realData = block[1].split(",")[1];
7172 if(is_Paste){
7173 var fileName = "image."+contentType.split("/")[1];
7174 }else{
7175 var fileName = items[0]['name'];
7176 }
7177
7178 // Convert it to a blob to upload
7179 var blob = pagelayer_b64toBlob(realData, contentType);
7180
7181 pagelayer_upload_image(fileName, blob, pagelayer_ajax_func);
7182
7183 }
7184
7185 };
7186 /* jshint +W083 */
7187 if(is_Paste){
7188 reader.readAsDataURL(items[i].getAsFile());
7189 }else{
7190 reader.readAsDataURL(items[i]);
7191 }
7192 mustPreventDefault = true;
7193 }
7194 }
7195
7196 if(mustPreventDefault && is_Paste){
7197 pasteEvent.stopPropagation();
7198 pasteEvent.preventDefault();
7199 }
7200
7201 }catch(err){
7202 console.log(err);
7203 }
7204
7205 return mustPreventDefault;
7206
7207 }
7208
7209 // Convert base64 to Blob
7210 function pagelayer_b64toBlob(b64Data, contentType, sliceSize) {
7211 contentType = contentType || '';
7212 sliceSize = sliceSize || 512;
7213
7214 var byteCharacters = atob(b64Data);
7215 var byteArrays = [];
7216
7217 for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
7218 var slice = byteCharacters.slice(offset, offset + sliceSize);
7219
7220 var byteNumbers = new Array(slice.length);
7221 for (var i = 0; i < slice.length; i++) {
7222 byteNumbers[i] = slice.charCodeAt(i);
7223 }
7224
7225 var byteArray = new Uint8Array(byteNumbers);
7226
7227 byteArrays.push(byteArray);
7228 }
7229
7230 var blob = new Blob(byteArrays, {type: contentType});
7231 return blob;
7232 }
7233
7234 // Function to check if the URL is external
7235 function pagelayer_parse_theme_vars(img_url){
7236
7237 for(x in pagelayer_theme_vars){
7238 img_url = img_url.replace(x, pagelayer_theme_vars[x]);
7239 }
7240
7241 return img_url;
7242 };
7243
7244 // Tooltip Setup for Editor
7245 function pagelayer_tooltip_setup(){
7246 //pagelayer.$$('[data-tlite]').each(function(){pagelayer_tlite.show(jQuery(this).get(0));});return;
7247 pagelayer.$$('[data-tlite]').hover(function(){
7248 pagelayer_tlite.show(jQuery(this).get(0));
7249 }, function(){
7250 pagelayer_tlite.hide(jQuery(this).get(0));
7251 });
7252
7253 };
7254
7255 // Pagelayer Messages
7256 function pagelayer_show_msg(msg, state, time){
7257
7258 time = time || 5000;
7259 state = !pagelayer_empty(state) ? 'pagelayer-editor-msg-state-'+state : '';
7260 var nholder = pagelayer.$$('.pagelayer-editor-notice');
7261 var mEle = jQuery('<div class="pagelayer-editor-msg '+state+'">'+msg+' <span class="pli pli-cross pagelayer-notice-x"></span></div>');
7262
7263 nholder.append(mEle);
7264
7265 mEle.find('.pagelayer-notice-x').on('click', function(){
7266 mEle.css({opacity: 0});
7267 setTimeout(function(){
7268 mEle.css({transition: 'none'});
7269 mEle.slideUp(function(){
7270 mEle.remove();
7271 });
7272 }, 900);
7273 });
7274
7275 setTimeout(function(){
7276 mEle.find('.pagelayer-notice-x').click();
7277 }, time);
7278
7279 }
7280
7281 // Pagelayer confirmation box
7282 function pagelayer_confirmation_box(message, yesCallback, noCallback, yesText, noText) {
7283
7284 yesText = yesText || pagelayer_l('Yes');
7285 noText = noText || pagelayer_l('No');
7286
7287 var dialog = jQuery('<div class="pagelayer-confirm-box-holder">'+
7288 '<div class="pagelayer-confirm-box" style="border-radius:5px">'+
7289 '<div class="pagelayer-confirmation-msg">'+ message +'</div>'+
7290 '<center>'+
7291 '<span class="pagelayer-btnyes button button-pagelayer">'+ yesText +'</span>&nbsp;&nbsp;&nbsp;'+
7292 '<span class="pagelayer-btnno button button-pagelayer">'+ noText +'</span>'+
7293 '</center>'+
7294 '</div>'+
7295 '</div>');
7296
7297 pagelayer.$$('body').append(dialog);
7298
7299 dialog.find('.pagelayer-btnyes').on('click', function() {
7300 dialog.remove();
7301 if(typeof yesCallback == 'function'){
7302 yesCallback();
7303 }
7304 });
7305 dialog.find('.pagelayer-btnno').on('click', function() {
7306 dialog.remove();
7307 if(typeof noCallback == 'function'){
7308 noCallback();
7309 }
7310 });
7311 dialog.show();
7312 }
7313
7314 function pagelayer_trim(str, charlist){
7315 // discuss at: http://locutus.io/php/trim/
7316
7317 if(typeof str != 'string'){
7318 return str;
7319 }
7320
7321 var whitespace = [' ', '\n', '\r', '\t', '\f', '\x0b', '\xa0', '\u2000', '\u2001', '\u2002', '\u2003', '\u2004', '\u2005', '\u2006', '\u2007', '\u2008', '\u2009', '\u200a', '\u200b', '\u2028', '\u2029', '\u3000' ].join('');
7322 var l = 0;
7323 var i = 0;
7324 str += '';
7325
7326 if (charlist) {
7327 whitespace = (charlist + '').replace(/([[\]().?/*{}+$^:])/g, '$1');
7328 }
7329
7330 l = str.length;
7331 for (i = 0; i < l; i++) {
7332 if (whitespace.indexOf(str.charAt(i)) === -1) {
7333 str = str.substring(i);
7334 break;
7335 }
7336 }
7337
7338 l = str.length;
7339 for (i = l - 1; i >= 0; i--) {
7340 if (whitespace.indexOf(str.charAt(i)) === -1) {
7341 str = str.substring(0, i + 1);
7342 break;
7343 }
7344 }
7345
7346 return whitespace.indexOf(str.charAt(0)) === -1 ? str : '';
7347 };
7348
7349 function pagelayer_ucwords(str) {
7350 return (str + '').replace(/^([a-z])|\s+([a-z])/g, function ($1) {
7351 return $1.toUpperCase();
7352 });
7353 }
7354
7355 // Check length for string and object
7356 function pagelayer_length(mixed_var) {
7357
7358 var length = 0;
7359 var undef, key, i, len;
7360 var emptyValues = [undef, null, false];
7361
7362 for(i = 0, len = emptyValues.length; i < len; i++) {
7363 if (mixed_var === emptyValues[i]) {
7364 return length;
7365 }
7366 }
7367
7368 // Is array, object or jQuery object?
7369 if(typeof mixed_var === 'object'){
7370
7371 // If is jQuery object
7372 if( mixed_var.hasOwnProperty('length')){
7373 return mixed_var.length;
7374 }
7375
7376 for (key in mixed_var) {
7377 // TODO: should we check for own properties only?
7378 //if ( .hasOwnProperty(key)) {
7379 length++;
7380 //}
7381 }
7382
7383 return length;
7384 }
7385
7386 length = String(mixed_var).length;
7387
7388 return length;
7389 };
7390
7391 // Create Widget list dropdown
7392 function pagelayer_create_widget_tooltip(){
7393
7394 var html = '<div class="pagelayer-widget-tooltip">'+
7395 '<div class="pagelayer-widget-search-holder">'+
7396 '<div class="pagelayer-widget-search">'+
7397 '<i class="pli pli-search" ></i><input class="pagelayer-search-field" /><span class="pagelayer-sf-empty pli">&times;</span>'+
7398 '</div>'+
7399 '</div>';
7400
7401 for(var x in pagelayer_groups){
7402
7403 // Title
7404 html += '<div class="pagelayer-widget-group pagelayer-group-name-'+x+'"><h5>'+x+'</h5>';
7405
7406 // Indivdual icon
7407 for(var y in pagelayer_groups[x]){
7408
7409 var sc = pagelayer_groups[x][y];
7410
7411 if(!(sc in pagelayer_shortcodes) || 'not_visible' in pagelayer_shortcodes[sc]){
7412 continue;
7413 }
7414
7415 html += '<div class="pagelayer-shortcode-holder" pagelayer-tag="'+sc+'">'+
7416 '<div class="pagelayer-pointer pagelayer-sc">'+
7417 '<center class="pagelayer-shortcode-inner">';
7418
7419 if('icon' in pagelayer_shortcodes[sc]){
7420 html += '<i class="pagelayer-shortcode '+pagelayer_shortcodes[sc]['icon']+'"></i>';
7421 }else{
7422 html += '<i class="pagelayer-shortcode pli pagelayer-'+sc+'"></i>';
7423 }
7424
7425 html += '</center>'+
7426 '<span class="pagelayer-pointer pagelayer-shortcode-text">'+pagelayer_shortcodes[sc]['name']+'</span>'+
7427 '</div>'+
7428 '</div>';
7429
7430 }
7431
7432 html += '</div>';
7433
7434 }
7435
7436 html += '</div>';
7437
7438 pagelayer.$$('body').append(html);
7439
7440 var wdHolder = pagelayer.$$('.pagelayer-widget-tooltip');
7441
7442 // Hide the ones which are not supposed to be shown
7443 wdHolder.find('.pagelayer-search-field').on('input', function(){
7444
7445 var val = jQuery(this).val();
7446 var re = new RegExp(val, 'i');
7447
7448 // Show only the required tags
7449 wdHolder.find('.pagelayer-widget-group').each(function(){
7450
7451 var group = jQuery(this);
7452 var res = group.find('[pagelayer-tag]');
7453 var hidden = 0;
7454
7455 res.each(function(){
7456
7457 var tEle = jQuery(this);
7458 if(tEle.find('.pagelayer-shortcode-text').html().match(re)){
7459 tEle.show();
7460 }else{
7461 hidden += 1;
7462 tEle.hide();
7463 }
7464
7465 });
7466
7467 // Hide the whole group
7468 if(hidden == res.length){
7469 group.hide();
7470 }else{
7471 group.show();
7472 }
7473
7474 });
7475
7476 wdHolder.find('.pagelayer-shortcode-holder:visible').first().trigger('widget_active');
7477
7478 });
7479
7480 // On click search empty
7481 wdHolder.find('.pagelayer-widget-search>.pagelayer-sf-empty').click(function(){
7482 wdHolder.find('.pagelayer-search-field').val('').trigger('input');
7483 });
7484
7485 // Register widget active event
7486 wdHolder.find('.pagelayer-shortcode-holder').on('widget_active', function(){
7487 var activeEle = jQuery(this);
7488 wdHolder.find('.pagelayer-list-widget-active').removeClass('pagelayer-list-widget-active');
7489
7490 if(!activeEle.hasClass('pagelayer-list-widget-active')){
7491 activeEle.addClass('pagelayer-list-widget-active');
7492 }
7493
7494 activeEle[0].scrollIntoView({behavior: "smooth", block: "end"});
7495 });
7496
7497 pagelayer.gDocument.on('mousedown.pagelayer_wdlist', function(e){
7498 var target = jQuery(e.target);
7499
7500 if(target.closest('.pagelayer-widget-tooltip').is(wdHolder)){
7501 return;
7502 }
7503
7504 wdHolder.find('.pagelayer-shortcode-holder:visible').first().trigger('widget_active');
7505
7506 wdHolder.hide();
7507 jQuery('.pagelayer-show-wiget-list').removeClass('pagelayer-show-wiget-list');
7508 jQuery(window).off('scroll.pagelayer_wdlist resize.pagelayer_wdlist');
7509 });
7510
7511 }
7512
7513 // Show Widget list dropdown
7514 function pagelayer_show_widget_list(jEle, val){
7515
7516 val = val || '';
7517 jEle = jQuery(jEle);
7518
7519 var wEle = pagelayer.$$('.pagelayer-widget-tooltip'),
7520 winH = jQuery(window).height(),
7521 iframe = pagelayer.$$('#pagelayer-iframe'),
7522 iframeTop = iframe.offset().top,
7523 iframeLeft = iframe.offset().left,
7524 style = {},
7525 wTop = 'auto',
7526 wBottom = 'auto',
7527 wLeft = '';
7528 wHeight = '';
7529
7530 searchField = wEle.find('.pagelayer-search-field');
7531 searchField.val(val);
7532 searchField.trigger('input');
7533
7534 // Add widget show class
7535 if(jEle.hasClass('pagelayer-shortcode-plus')){
7536 jEle.parent('.pagelayer-ele-overlay').addClass('pagelayer-show-wiget-list');
7537 }
7538
7539 var bounds = jEle[0].getBoundingClientRect();
7540
7541 wEle.removeClass('pagelayer-widget-list-tooltip');
7542 wLeft = (bounds.left + iframeLeft) - wEle.width() / 2;
7543
7544 // In list view?
7545 if(jEle.closest('[pagelayer-editable]').length > 0){
7546 wEle.addClass('pagelayer-widget-list-tooltip');
7547 var selection = window.getSelection();
7548 var range = selection.getRangeAt(0);
7549 wLeft = (range.getBoundingClientRect().left + iframeLeft) - wEle.width() / 2;
7550 }
7551
7552 wEle.closest('.pagelayer-widget-tooltip').show();
7553 wEle.find('.pagelayer-shortcode-holder:visible').first().trigger('widget_active');
7554
7555 // Hide Widget list
7556 if(jEle.closest('[pagelayer-editable]').length > 0 && wEle.find('.pagelayer-widget-group:visible').length < 1){
7557 pagelayer.gDocument.trigger('mousedown.pagelayer_wdlist');
7558 return;
7559 }else{
7560 searchField.focus().select();
7561 }
7562
7563 var docW = iframeLeft + iframe.width() - 30;
7564
7565 // Prevent to hide on left or right
7566 if(docW < wLeft + wEle.width()){
7567 wLeft = docW - wEle.width();
7568 }else if(iframeLeft > wLeft){
7569 wLeft = iframeLeft;
7570 }
7571
7572 if(winH / 2 < bounds.top + 10){
7573 wBottom = winH - bounds.top + 10;
7574 wHeight = bounds.top - 10;
7575 }else{
7576 wTop = bounds.bottom + iframeTop + 10;
7577 wHeight = winH - bounds.bottom - 10;
7578 }
7579
7580 style['left'] = wLeft;
7581 style['top'] = wTop;
7582 style['bottom'] = wBottom;
7583 style['max-height'] = '';
7584
7585 if(wHeight < 350){
7586 style['max-height'] = wHeight;
7587 }
7588
7589 wEle.css(style);
7590
7591 jQuery(window).off('scroll.pagelayer_wdlist resize.pagelayer_wdlist');
7592 jQuery(window).on('scroll.pagelayer_wdlist resize.pagelayer_wdlist', function(){
7593 var _val = wEle.find('.pagelayer-search-field').val();
7594 pagelayer_show_widget_list(jEle, _val);
7595 });
7596
7597 wEle.find('.pagelayer-shortcode-holder').off('click');
7598 wEle.find('.pagelayer-shortcode-holder').on('click', function(e){
7599
7600 var tag = jQuery(this).attr('pagelayer-tag');
7601 var mWrap = jEle.closest('.pagelayer-ele-wrap[pagelayer-wrap-id]');
7602 var mTag = pagelayer_tag(mWrap);
7603
7604 var ele = jQuery('<div pagelayer-tag="'+tag+'"></div>');
7605
7606 // Is col?
7607 if(mTag == 'pl_col'){
7608 var colHolder = mWrap.find('>.pagelayer-col > .pagelayer-col-holder');
7609 colHolder.append(ele);
7610 pagelayer_empty_col(colHolder);
7611 }else{
7612 mWrap.after(ele);
7613 }
7614
7615 // Replace widget
7616 if(jEle.closest('[pagelayer-editable]').length > 0){
7617 pagelayer_delete_element(mWrap.find('>.pagelayer-ele'));
7618 }
7619
7620 var eleId = pagelayer_onadd(ele, false);
7621 var eEle = pagelayer_ele_by_id(eleId);
7622
7623 // Create Column
7624 if( tag == 'pl_inner_row' ){
7625 var in_col = jQuery('<div pagelayer-tag="pl_col"></div>');
7626 eEle.find('>.pagelayer-row-holder').append(in_col);
7627 var in_col_id = pagelayer_onadd(in_col, false);
7628 }
7629
7630 eEle.click();
7631
7632 // Hide Widget list
7633 pagelayer.gDocument.trigger('mousedown.pagelayer_wdlist');
7634 });
7635
7636 }
7637
7638 // Set Selection By Character Offsets
7639 function pagelayer_setCaret(containerEl, start, end){
7640
7641 end = end || start;
7642
7643 // Refered from http://jsfiddle.net/zQUhV/47/
7644 if(window.getSelection && document.createRange){
7645
7646 var charIndex = 0, range = document.createRange();
7647 range.setStart(containerEl, 0);
7648 range.collapse(true);
7649 var nodeStack = [containerEl], node, foundStart = false, stop = false;
7650
7651 while (!stop && (node = nodeStack.pop())) {
7652 if (node.nodeType == 3) {
7653 var nextCharIndex = charIndex + node.length;
7654 if (!foundStart && start >= charIndex && start <= nextCharIndex) {
7655 range.setStart(node, start - charIndex);
7656 foundStart = true;
7657 }
7658 if (foundStart && end >= charIndex && end <= nextCharIndex) {
7659 range.setEnd(node, end - charIndex);
7660 stop = true;
7661 }
7662 charIndex = nextCharIndex;
7663 } else {
7664 var i = node.childNodes.length;
7665 while (i--) {
7666 nodeStack.push(node.childNodes[i]);
7667 }
7668 }
7669 }
7670
7671 var sel = window.getSelection();
7672 sel.removeAllRanges();
7673 sel.addRange(range);
7674
7675 } else if (document.selection) {
7676 var textRange = document.body.createTextRange();
7677 textRange.moveToElementText(containerEl);
7678 textRange.collapse(true);
7679 textRange.moveEnd("character", end);
7680 textRange.moveStart("character", start);
7681 textRange.select();
7682 }
7683 }
7684
7685 // Set Selection By Character Offsets
7686 function pagelayer_content_line(containerEl){
7687
7688 var lines = [], charIndex = 0, range = document.createRange();
7689 range.setStart(containerEl, 0);
7690 range.collapse(true);
7691 var bounding = range.getBoundingClientRect();
7692 var nodeStack = [containerEl], node, prevX = bounding.x, nextStart = 0;
7693
7694 while(node = nodeStack.pop()){
7695 if (node.nodeType == 3) {
7696 for(var i = 1; i <= node.length; i++){
7697 range.setStart(node, i);
7698 range.setEnd(node, i);
7699 bounding = range.getBoundingClientRect();
7700 charIndex ++;
7701
7702 if(prevX > bounding.x){
7703 lines.push({start:nextStart, end:charIndex - 1});
7704 nextStart = charIndex;
7705 }
7706 prevX = bounding.x;
7707 }
7708 } else {
7709 var i = node.childNodes.length;
7710 while(i--){
7711 nodeStack.push(node.childNodes[i]);
7712 }
7713 }
7714 }
7715
7716 // Push last line
7717 if(nextStart != charIndex || nextStart == 0){
7718 lines.push({start:nextStart, end:charIndex});
7719 }
7720
7721 return lines;
7722 }
7723
7724 //http://jsfiddle.net/TjXEG/900/
7725 function pagelayer_getCaretCharacterOffsetWithin(element){
7726 var caretOffset = 0;
7727 var doc = element.ownerDocument || element.document;
7728 var win = doc.defaultView || doc.parentWindow;
7729 var sel;
7730 if( typeof win.getSelection != "undefined" ){
7731 sel = win.getSelection();
7732 if (sel.rangeCount > 0) {
7733 var range = win.getSelection().getRangeAt(0);
7734 var preCaretRange = range.cloneRange();
7735 preCaretRange.selectNodeContents(element);
7736 preCaretRange.setEnd(range.endContainer, range.endOffset);
7737 caretOffset = preCaretRange.toString().length;
7738 }
7739 }else if( (sel = doc.selection) && sel.type != "Control" ){
7740 var textRange = sel.createRange();
7741 var preCaretTextRange = doc.body.createTextRange();
7742 preCaretTextRange.moveToElementText(element);
7743 preCaretTextRange.setEndPoint("EndToEnd", textRange);
7744 caretOffset = preCaretTextRange.text.length;
7745 }
7746 return caretOffset;
7747 }
7748
7749 // ==========================================================================
7750 // PAGELAYER UX IMPROVEMENTS
7751 // ==========================================================================
7752
7753 var pagelayer_is_command_palette_open = false;
7754
7755 function pagelayer_ux_improvements_init() {
7756 // Setup global shortcuts inside Parent Window and Iframe Document
7757 var setupShortcuts = function(doc) {
7758 jQuery(doc).on('keydown', function(e) {
7759 // Command Palette: Ctrl+K
7760 if (e.key === 'k' && (e.ctrlKey || e.metaKey)) {
7761 e.preventDefault();
7762 pagelayer_toggle_command_palette();
7763 }
7764 });
7765 };
7766
7767 setupShortcuts(document);
7768 if (pagelayer.gDocument) {
7769 setupShortcuts(pagelayer.gDocument);
7770 }
7771
7772 // Hook selection callback to refresh Navigator if it is open in the right sidebar
7773 pagelayer_add_action('pagelayer_element_clicked', function(jEle) {
7774 if (jEle && jEle.length > 0) {
7775 var isNavigatorOpen = pagelayer.$$('body').hasClass('pagelayer-right-sidebar-open') && pagelayer.$$('#pagelayer-navigator').is(':visible');
7776 if (isNavigatorOpen) {
7777 var newId = pagelayer_id(jEle);
7778 if (newId) {
7779 pagelayer_active.el = pagelayer_active.el || {};
7780 pagelayer_active.el.id = newId;
7781 }
7782 pagelayer_navigator_setup();
7783 }
7784 }
7785 });
7786
7787 // Redirect Navigator & History/Revisions tabs to a new small right sidebar
7788 window.pagelayer_close_right_sidebar = function() {
7789 var sidebar = pagelayer.$$('.pagelayer-right-sidebar');
7790 if (sidebar.length > 0) {
7791 sidebar.css('right', '-300px');
7792 pagelayer.$$('body').removeClass('pagelayer-right-sidebar-open');
7793 pagelayer.$$('.pagelayer-navigator-icon, .pagelayer-history-icon').closest('.pagelayer-header-icon-wrap').removeClass('active');
7794 pagelayer.$$('#pagelayer-navigator').hide();
7795 pagelayer.$$('#pagelayer-history').hide();
7796 }
7797 };
7798
7799 window.pagelayer_open_right_sidebar = function(tab) {
7800 var sidebar = pagelayer.$$('.pagelayer-right-sidebar');
7801 if (sidebar.length === 0) {
7802 var sidebarHtml =
7803 '<div class="pagelayer-right-sidebar">' +
7804 '<div class="pagelayer-right-sidebar-header">' +
7805 '<h4 class="pagelayer-right-sidebar-title"></h4>' +
7806 '<button class="pagelayer-right-sidebar-close"><i class="pli pli-cross"></i></button>' +
7807 '</div>' +
7808 '<div class="pagelayer-right-sidebar-content">' +
7809 '</div>' +
7810 '</div>';
7811 pagelayer.$$('body').append(sidebarHtml);
7812 sidebar = pagelayer.$$('.pagelayer-right-sidebar');
7813
7814 sidebar.find('.pagelayer-right-sidebar-close').on('click', function() {
7815 window.pagelayer_close_right_sidebar();
7816 });
7817 }
7818
7819 var isDark = pagelayer.$$('body').hasClass('pagelayer-dark');
7820 if (isDark) {
7821 sidebar.addClass('pagelayer-dark');
7822 } else {
7823 sidebar.removeClass('pagelayer-dark');
7824 }
7825
7826 pagelayer.$$('.pagelayer-navigator-icon, .pagelayer-history-icon').closest('.pagelayer-header-icon-wrap').removeClass('active');
7827
7828 var title = '';
7829 var iconClass = '';
7830 if (tab === 'pagelayer-navigator') {
7831 title = pagelayer_l('pagelayer_navigator') || 'Navigator';
7832 iconClass = '.pagelayer-navigator-icon';
7833 } else {
7834 title = pagelayer_l('pagelayer_history') || 'History & Revisions';
7835 iconClass = '.pagelayer-history-icon';
7836 }
7837
7838 sidebar.find('.pagelayer-right-sidebar-title').text(title);
7839
7840 var isVisible = pagelayer.$$('body').hasClass('pagelayer-right-sidebar-open');
7841 var targetContainer = pagelayer.$$('#' + tab);
7842 if (isVisible && targetContainer.length > 0 && targetContainer.is(':visible')) {
7843 window.pagelayer_close_right_sidebar();
7844 return;
7845 }
7846
7847 pagelayer.$$(iconClass).closest('.pagelayer-header-icon-wrap').addClass('active');
7848 sidebar.find('.pagelayer-right-sidebar-content').children().hide();
7849
7850 if (targetContainer.parent().hasClass('pagelayer-right-sidebar-content') === false) {
7851 sidebar.find('.pagelayer-right-sidebar-content').append(targetContainer);
7852 }
7853
7854 targetContainer.show().css({'height': '100%', 'position': 'static'});
7855 sidebar.css('right', '0px');
7856 pagelayer.$$('body').addClass('pagelayer-right-sidebar-open');
7857 };
7858
7859 var original_pagelayer_leftbar_tab = window.pagelayer_leftbar_tab;
7860 window.pagelayer_leftbar_tab = function(tab) {
7861 if (tab === 'pagelayer-navigator' || tab === 'pagelayer-history') {
7862 window.pagelayer_open_right_sidebar(tab);
7863 } else {
7864 // Do not hide navigator or history tab if they are in the right sidebar
7865 pagelayer.$$('.pagelayer-leftbar-tab').not('#pagelayer-navigator, #pagelayer-history').hide();
7866 pagelayer.$$('#'+tab).show();
7867 }
7868 };
7869
7870 var bindIcons = function() {
7871 var $historyIcon = pagelayer.$$('.pagelayer-history-icon');
7872 $historyIcon.off('click');
7873 $historyIcon.closest('.pagelayer-header-icon-wrap').off('click').on('click', function(e) {
7874 e.stopPropagation();
7875 window.pagelayer_open_right_sidebar('pagelayer-history');
7876 pagelayer_history_setup();
7877 });
7878
7879 var $navigatorIcon = pagelayer.$$('.pagelayer-navigator-icon');
7880 $navigatorIcon.off('click');
7881 $navigatorIcon.closest('.pagelayer-header-icon-wrap').off('click').on('click', function(e) {
7882 e.stopPropagation();
7883 var targetContainer = pagelayer.$$('#pagelayer-navigator');
7884 if (!targetContainer.is(':visible')) {
7885 pagelayer_navigator_setup();
7886 }
7887 window.pagelayer_open_right_sidebar('pagelayer-navigator');
7888 });
7889 };
7890
7891 bindIcons();
7892 setInterval(bindIcons, 3000);
7893 }
7894
7895 // Toggle Command Palette Modal (Figma / Bricks style search palette)
7896 function pagelayer_toggle_command_palette() {
7897 var modal = pagelayer.$$('.pagelayer-command-palette-modal');
7898 if (modal.length > 0) {
7899 if (modal.is(':visible')) {
7900 modal.hide();
7901 pagelayer_is_command_palette_open = false;
7902 } else {
7903 modal.show().find('.pagelayer-cmd-input').focus().val('');
7904 pagelayer_is_command_palette_open = true;
7905 pagelayer_render_command_palette_results('');
7906 }
7907 return;
7908 }
7909
7910 // Create modal in parent window
7911 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;">' +
7912 '<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;">' +
7913 '<div class="pagelayer-cmd-search-bar" style="display: flex; align-items: center; padding: 14px 18px; border-bottom: 1px solid #f1f5f9; gap: 12px;">' +
7914 '<i class="fas fa-search" style="color: #64748b; font-size: 16px;"></i>' +
7915 '<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;" />' +
7916 '<span style="font-size: 11px; background: #f1f5f9; color: #64748b; padding: 2px 6px; border-radius: 4px; border: 1px solid #cbd5e1;">ESC</span>' +
7917 '</div>' +
7918 '<div class="pagelayer-cmd-results" style="flex: 1; overflow-y: auto; padding: 8px 0; max-height: 380px;">' +
7919 '</div>' +
7920 '</div>' +
7921 '</div>';
7922
7923 pagelayer.$$('body').append(modalHtml);
7924 modal = pagelayer.$$('.pagelayer-command-palette-modal');
7925 pagelayer_is_command_palette_open = true;
7926
7927 // Add dark mode support to command palette
7928 if (pagelayer.$$('body').hasClass('pagelayer-dark')) {
7929 modal.find('.pagelayer-cmd-container').css({ 'background': '#0b0f19', 'border-color': '#1e293b', 'color': '#f8fafc' });
7930 modal.find('.pagelayer-cmd-search-bar').css({ 'border-bottom-color': '#1e293b' });
7931 modal.find('.pagelayer-cmd-input').css({ 'color': '#f8fafc' });
7932 modal.find('span').css({ 'background': '#1e293b', 'color': '#cbd5e1', 'border-color': '#334155' });
7933 }
7934
7935 modal.on('click', function(e) {
7936 if (e.target === this) {
7937 modal.hide();
7938 pagelayer_is_command_palette_open = false;
7939 }
7940 });
7941
7942 modal.find('.pagelayer-cmd-input').on('input', function() {
7943 var q = jQuery(this).val();
7944 pagelayer_render_command_palette_results(q);
7945 });
7946
7947 modal.find('.pagelayer-cmd-input').on('keydown', function(e) {
7948 var results = modal.find('.pagelayer-cmd-item');
7949 var active = modal.find('.pagelayer-cmd-item.active');
7950
7951 if (e.key === 'ArrowDown') {
7952 e.preventDefault();
7953 if (active.length === 0 || active.is(':last-child')) {
7954 results.removeClass('active').first().addClass('active').get(0).scrollIntoView({ block: 'nearest' });
7955 } else {
7956 active.removeClass('active').next().addClass('active').get(0).scrollIntoView({ block: 'nearest' });
7957 }
7958 } else if (e.key === 'ArrowUp') {
7959 e.preventDefault();
7960 if (active.length === 0 || active.is(':first-child')) {
7961 results.removeClass('active').last().addClass('active').get(0).scrollIntoView({ block: 'nearest' });
7962 } else {
7963 active.removeClass('active').prev().addClass('active').get(0).scrollIntoView({ block: 'nearest' });
7964 }
7965 } else if (e.key === 'Enter') {
7966 e.preventDefault();
7967 if (active.length > 0) {
7968 active.click();
7969 }
7970 } else if (e.key === 'Escape') {
7971 modal.hide();
7972 pagelayer_is_command_palette_open = false;
7973 }
7974 });
7975
7976 modal.find('.pagelayer-cmd-input').focus();
7977 pagelayer_render_command_palette_results('');
7978 }
7979
7980 function pagelayer_render_command_palette_results(query) {
7981 var modal = pagelayer.$$('.pagelayer-command-palette-modal');
7982 var resultsContainer = modal.find('.pagelayer-cmd-results');
7983 resultsContainer.empty();
7984
7985 query = query.toLowerCase().trim();
7986 var items = [];
7987
7988 // 1. Gather all shortcodes/widgets
7989 var addedWidgets = {};
7990
7991 // First, gather from pagelayer_groups to prioritize standard draggable widgets
7992 for (var group in pagelayer_groups) {
7993 for (var index in pagelayer_groups[group]) {
7994 var key = pagelayer_groups[group][index];
7995 if (addedWidgets[key]) continue;
7996
7997 var sc = pagelayer_shortcodes[key];
7998 if (!sc || !sc.name || 'not_visible' in sc) continue;
7999
8000 if (query === '' || sc.name.toLowerCase().indexOf(query) > -1 || key.toLowerCase().indexOf(query) > -1) {
8001 items.push({
8002 type: 'widget',
8003 title: sc.name,
8004 subtitle: 'Add Widget',
8005 key: key,
8006 icon: sc.icon || '',
8007 action: (function(k) {
8008 return function() {
8009 pagelayer_insert_widget(k);
8010 };
8011 })(key)
8012 });
8013 addedWidgets[key] = true;
8014 }
8015 }
8016 }
8017
8018 // Fallback to scan raw shortcodes to capture any miscellaneous widgets not categorized in sidebar groups
8019 for (var key in pagelayer_shortcodes) {
8020 if (addedWidgets[key]) continue;
8021
8022 var sc = pagelayer_shortcodes[key];
8023 if (!sc || !sc.name || 'not_visible' in sc) continue;
8024
8025 if (query === '' || sc.name.toLowerCase().indexOf(query) > -1 || key.toLowerCase().indexOf(query) > -1) {
8026 items.push({
8027 type: 'widget',
8028 title: sc.name,
8029 subtitle: 'Add Widget',
8030 key: key,
8031 icon: sc.icon || '',
8032 action: (function(k) {
8033 return function() {
8034 pagelayer_insert_widget(k);
8035 };
8036 })(key)
8037 });
8038 addedWidgets[key] = true;
8039 }
8040 }
8041
8042 // 2. Gather editor actions
8043 var actions = [
8044 { title: 'Undo Last Edit', subtitle: 'History Action', icon: 'fas fa-undo', search: 'undo ctrl+z back', action: function() { pagelayer_do_history('undo'); } },
8045 { title: 'Redo Edit', subtitle: 'History Action', icon: 'fas fa-redo', search: 'redo ctrl+y', action: function() { pagelayer_do_history('redo'); } },
8046 { title: 'Switch to Desktop View', subtitle: 'Screen Mode', icon: 'fas fa-desktop', search: 'desktop screen responsive preview', action: function() { pagelayer_set_screen_mode('desktop'); } },
8047 { 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'); } },
8048 { 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'); } },
8049 { title: 'Open Revisions & History', subtitle: 'Revision History', icon: 'fas fa-history', search: 'history revisions undo changes', action: function() { pagelayer.$$('.pagelayer-history-icon').click(); } },
8050 { 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(); } },
8051 { 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(); } }
8052 ];
8053
8054 actions.forEach(function(act) {
8055 if (query === '' || act.title.toLowerCase().indexOf(query) > -1 || act.search.indexOf(query) > -1) {
8056 items.push({
8057 type: 'action',
8058 title: act.title,
8059 subtitle: act.subtitle,
8060 icon: act.icon,
8061 action: act.action
8062 });
8063 }
8064 });
8065
8066 if (items.length === 0) {
8067 resultsContainer.html('<div style="text-align: center; color: #64748b; padding: 24px 0; font-size: 14px;">No results found. Try another query.</div>');
8068 return;
8069 }
8070
8071 var slice = items.slice(0, 100);
8072 var isDark = pagelayer.$$('body').hasClass('pagelayer-dark');
8073
8074 slice.forEach(function(item, idx) {
8075 var iconClass = '';
8076 if (item.type === 'widget') {
8077 if (item.icon) {
8078 iconClass = 'pagelayer-shortcode ' + item.icon;
8079 } else {
8080 iconClass = 'pagelayer-shortcode pli pagelayer-' + item.key;
8081 }
8082 } else {
8083 iconClass = item.icon;
8084 }
8085 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;">' +
8086 '<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>' +
8087 '<div style="flex: 1; display: flex; flex-direction: column;">' +
8088 '<span style="font-weight: 500; color: ' + (isDark ? '#f8fafc' : '#0f172a') + ';">' + item.title + '</span>' +
8089 '<span style="font-size: 11px; color: #64748b;">' + item.subtitle + '</span>' +
8090 '</div>' +
8091 '</div>');
8092
8093 var hoverBg = isDark ? '#1e293b' : '#f8fafc';
8094
8095 itemHtml.hover(function() {
8096 modal.find('.pagelayer-cmd-item').removeClass('active');
8097 jQuery(this).addClass('active');
8098 });
8099
8100 itemHtml.on('click', function() {
8101 modal.hide();
8102 pagelayer_is_command_palette_open = false;
8103 item.action();
8104 });
8105
8106 resultsContainer.append(itemHtml);
8107 });
8108
8109 var styleTag = pagelayer.$$('head #pagelayer-cmd-palette-styles');
8110 if (styleTag.length === 0) {
8111 pagelayer.$$('head').append('<style id="pagelayer-cmd-palette-styles">' +
8112 '.pagelayer-cmd-item.active { background: ' + (isDark ? '#1e293b !important' : '#f1f5f9 !important') + '; }' +
8113 '</style>');
8114 }
8115 }
8116
8117 // Programmatic widget placement
8118 function pagelayer_insert_widget(tag) {
8119 var active = pagelayer_active.el;
8120 var parentCol = null;
8121 var target = null;
8122 var method = 'append';
8123
8124 if (active && active.$) {
8125 var tag_active = pagelayer_tag(active.$);
8126 if (tag_active === 'pl_col') {
8127 parentCol = active.$.find('>.pagelayer-col-holder');
8128 method = 'append';
8129 } else if (tag_active === 'pl_row' || tag_active === 'pl_inner_row') {
8130 parentCol = active.$.find('.pagelayer-col-holder').first();
8131 method = 'append';
8132 } else {
8133 target = active.$.closest('.pagelayer-ele-wrap');
8134 method = 'after';
8135 }
8136 } else {
8137 parentCol = jQuery(pagelayer_editable).find('.pagelayer-col-holder').first();
8138 method = 'append';
8139 }
8140
8141 if ((!parentCol || parentCol.length === 0) && (!target || target.length === 0)) {
8142 var row = jQuery('<div pagelayer-tag="pl_row"></div>');
8143 jQuery(pagelayer_editable).append(row);
8144 var rowId = pagelayer_onadd(row, false);
8145 var rEle = pagelayer_ele_by_id(rowId);
8146
8147 var col = jQuery('<div pagelayer-tag="pl_col"></div>');
8148 rEle.find('.pagelayer-row-holder').append(col);
8149 var colId = pagelayer_onadd(col, false);
8150 var cEle = pagelayer_ele_by_id(colId);
8151 parentCol = cEle.find('.pagelayer-col-holder');
8152 method = 'append';
8153 }
8154
8155 var ele = jQuery('<div pagelayer-tag="' + tag + '"></div>');
8156 if (method === 'append') {
8157 parentCol.append(ele);
8158 pagelayer_empty_col(parentCol);
8159 } else {
8160 target.after(ele);
8161 pagelayer_empty_col(target.closest('.pagelayer-col-holder'));
8162 }
8163
8164 var newId = pagelayer_onadd(ele, true);
8165 pagelayer_do_dirty(ele);
8166 }
8167
8168