ru-se.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

customizer-base.js (203735B)


      1 (function ($) {
      2     if (!Element.prototype.scrollIntoViewIfNeeded) {
      3         Element.prototype.scrollIntoViewIfNeeded = function (centerIfNeeded) {
      4             centerIfNeeded = arguments.length === 0 ? true : !!centerIfNeeded;
      5 
      6             var parent = this.parentNode,
      7                 parentComputedStyle = window.getComputedStyle(parent, null),
      8                 parentBorderTopWidth = parseInt(parentComputedStyle.getPropertyValue('border-top-width')),
      9                 parentBorderLeftWidth = parseInt(parentComputedStyle.getPropertyValue('border-left-width')),
     10                 overTop = this.offsetTop - parent.offsetTop < parent.scrollTop,
     11                 overBottom = (this.offsetTop - parent.offsetTop + this.clientHeight - parentBorderTopWidth) > (parent.scrollTop + parent.clientHeight),
     12                 overLeft = this.offsetLeft - parent.offsetLeft < parent.scrollLeft,
     13                 overRight = (this.offsetLeft - parent.offsetLeft + this.clientWidth - parentBorderLeftWidth) > (parent.scrollLeft + parent.clientWidth),
     14                 alignWithTop = overTop && !overBottom;
     15 
     16             if ((overTop || overBottom) && centerIfNeeded) {
     17                 parent.scrollTop = this.offsetTop - parent.offsetTop - parent.clientHeight / 2 - parentBorderTopWidth + this.clientHeight / 2;
     18             }
     19 
     20             if ((overLeft || overRight) && centerIfNeeded) {
     21                 parent.scrollLeft = this.offsetLeft - parent.offsetLeft - parent.clientWidth / 2 - parentBorderLeftWidth + this.clientWidth / 2;
     22             }
     23 
     24             if ((overTop || overBottom || overLeft || overRight) && !centerIfNeeded) {
     25                 this.scrollIntoView(alignWithTop);
     26             }
     27         };
     28     }
     29 
     30     $.fn.tagName = function () {
     31         if (!this[0])
     32             return null;
     33         if (this[0] && this[0].nodeName) {
     34             return this[0].nodeName.toLowerCase();
     35         }
     36         return null;
     37     };
     38 
     39     $.fn.insertAt = function (index, $parent) {
     40         return this.each(function () {
     41             if ($(this).parent().is($parent)) {
     42                 var siblings = $(this).siblings();
     43                 if (index < siblings.length) {
     44                     siblings.eq(index).before(this);
     45                 } else {
     46                     siblings.last().after(this);
     47                 }
     48             } else {
     49                 if (index === 0 || !$parent.children().length) {
     50                     $parent.prepend(this);
     51                 } else {
     52                     if (index >= $parent.children().length) {
     53                         $parent.append(this);
     54                     } else {
     55                         $parent.children().eq(index - 1).after(this);
     56                     }
     57                 }
     58             }
     59         });
     60     };
     61 
     62 
     63     if (!NodeList.prototype.forEach) {
     64         NodeList.prototype.forEach = Array.prototype.forEach;
     65         HTMLCollection.prototype.forEach = Array.prototype.forEach; // Because of https://bugzilla.mozilla.org/show_bug.cgi?id=14869
     66 
     67     }
     68 
     69     if (!Array.from) {
     70         Array.from = function (object) {
     71             return [].slice.call(object);
     72         };
     73     }
     74 
     75 
     76 })(jQuery);
     77 
     78 (function ($, root) {
     79 
     80     wp.customize.bind("save-request-params", function (query) {
     81         query.customize_post_id = CP_Customizer.preview.data().pageID;
     82         if (CP_Customizer && CP_Customizer.hooks) {
     83             query = CP_Customizer.hooks.applyFilters('save-request-params', query);
     84         }
     85         return query;
     86     });
     87 
     88     function translateCompanionString(text) {
     89 
     90         if (!text || !_.isString(text)) {
     91             return text;
     92         }
     93 
     94         if (root.__materialisCustomizerStrings[text] !== undefined) {
     95             return root.__materialisCustomizerStrings[text];
     96         } else {
     97             //in debug mode
     98             if (CP_Customizer.options('SCRIPT_DEBUG')) {
     99                 console.warn("[Not translated] " + text);
    100             }
    101             return text;
    102         }
    103     }
    104 
    105     var CP_Customizer = {
    106             events: {
    107                 "PREVIEW_LOADED": "PREVIEW_LOADED",
    108                 "ADD_FIXED_OVERLAYS": "ADD_FIXED_OVERLAYS",
    109                 "RIGHT_SECTION_CLOSED": "RIGHT_SECTION_CLOSED",
    110                 "ELEMENT_DECORATED": "ELEMENT_DECORATED",
    111                 "CONTENT_ROW_REMOVED": "CONTENT_ROW_REMOVED",
    112                 "DOCUMENT_READY": "DOCUMENT_READY",
    113                 "STATE_UPDATED": "STATE_UPDATED",
    114                 "FOCUS_CONTROL": "FOCUS_CONTROL"
    115             },
    116 
    117             getSlug: window.getSlug,
    118 
    119             wpApi: wp.customize,
    120 
    121             MAX_SAFE_INTEGER: Number.MAX_SAFE_INTEGER ? Number.MAX_SAFE_INTEGER : 9007199254740991,
    122 
    123             hooks: window.hooksManager,
    124 
    125             CONTENT_ELEMENTS: 'p,h1,h2,h3,h4,h5,h6,a,span,i,hr,img,ul,div.spacer',
    126             TEXT_ELEMENTS: "p,h1,h2,h3,h4,h5,h6,span",
    127             THEME_MOD_NODES: '[data-theme],[data-theme-src],[data-theme-mdi]',
    128 
    129             translateCompanionString: translateCompanionString,
    130 
    131             data: function () {
    132                 return root.cpCustomizerGlobal.pluginOptions.data;
    133             },
    134 
    135             addContentElementsSelectors: function (selectors) {
    136                 if (!_.isArray(selectors)) {
    137                     selectors = [selectors]
    138                 }
    139 
    140                 this.CONTENT_ELEMENTS = this.CONTENT_ELEMENTS.split(',').concat(selectors).join(',')
    141             },
    142 
    143             IO: {
    144                 get: function (action, data) {
    145                     return this.send({
    146                         data: _.isObject(action) ? action : _.extend(data || {}, {action: action}),
    147                         type: 'GET'
    148                     });
    149                 },
    150                 post: function (action, data) {
    151                     return this.send({
    152                         data: _.isObject(action) ? action : _.extend(data || {}, {action: action})
    153                     });
    154                 },
    155 
    156 
    157                 customGet: function (url, data) {
    158                     data = _.isObject(data) ? data : {};
    159                     var options = {
    160                         type: "GET",
    161                         data: data
    162                     };
    163 
    164 
    165                     return CP_Customizer.IO.customSend(url, options);
    166                 },
    167                 customPost: function (url, data) {
    168                     data = _.isObject(data) ? data : {};
    169                     var options = {
    170                         type: "POST",
    171                         data: data
    172                     };
    173 
    174                     return CP_Customizer.IO.customSend(url, options);
    175                 },
    176 
    177                 customSend: function (url, options) {
    178 
    179                     options = _.defaults(options || {}, {
    180                         type: 'POST',
    181                         url: url
    182                     });
    183 
    184                     return CP_Customizer.IO.send(options);
    185                 },
    186 
    187                 rest: {
    188                     get: function (route, data) {
    189                         data = _.isObject(data) ? data : {};
    190                         var options = {
    191                             type: "GET",
    192                             data: data
    193                         };
    194 
    195 
    196                         return CP_Customizer.IO.rest.send(route, options);
    197                     },
    198                     post: function (route, data) {
    199                         data = _.isObject(data) ? data : {};
    200                         var options = {
    201                             type: "POST",
    202                             data: data
    203                         };
    204 
    205                         return CP_Customizer.IO.rest.send(route, options);
    206                     },
    207 
    208                     send: function (route, options) {
    209                         var url = CP_Customizer.options('restURL');
    210 
    211                         options = _.defaults(options || {}, {
    212                             type: 'POST',
    213                             url: CP_Customizer.utils.phpTrim(url, '/') + "/" + CP_Customizer.utils.phpTrim(route, '/')
    214                         });
    215 
    216                         return CP_Customizer.IO.send(options);
    217                     }
    218                 },
    219 
    220                 send: function (action, options) {
    221                     var promise, deferred;
    222                     if (_.isObject(action)) {
    223                         options = action;
    224                     } else {
    225                         options = options || {};
    226                         options.data = _.extend(options.data || {}, {action: action});
    227                     }
    228 
    229                     options = _.defaults(options || {}, {
    230                         type: 'POST',
    231                         url: wp.ajax.settings.url,
    232                         context: this,
    233                         _: Date.now(),
    234                         xhrFields: {
    235                             withCredentials: true
    236                         }
    237                     });
    238 
    239                     deferred = $.Deferred(function (deferred) {
    240                         // Transfer success/error callbacks.
    241                         if (options.success)
    242                             deferred.done(options.success);
    243                         if (options.error)
    244                             deferred.fail(options.error);
    245 
    246                         delete options.success;
    247                         delete options.error;
    248 
    249                         deferred.jqXHR = $.ajax(options).done(function (response) {
    250                             deferred.resolveWith(this, [response, deferred.jqXHR]);
    251                         }).fail(function () {
    252                             deferred.rejectWith(this, arguments);
    253                         });
    254                     });
    255 
    256                     promise = deferred.promise();
    257                     promise.abort = function () {
    258                         deferred.jqXHR.abort();
    259                         return this;
    260                     };
    261 
    262                     return promise;
    263                 }
    264             },
    265 
    266 
    267             options: function (key, defaultValue) {
    268                 var result = root.cpCustomizerGlobal.pluginOptions;
    269 
    270                 if (key) {
    271                     var keyParts = key.split(':');
    272                     for (var i = 0; i < keyParts.length; i++) {
    273                         var part = keyParts[i];
    274 
    275                         if (!_.isUndefined(result[part])) {
    276                             result = result[part];
    277                         } else {
    278                             result = defaultValue;
    279                             break;
    280                         }
    281                     }
    282                 }
    283 
    284                 return result;
    285             },
    286 
    287             __exportsCache: {},
    288             getSectionExports: function (sectionId) {
    289 
    290                 if (sectionId.jquery) {
    291                     sectionId = sectionId.attr('data-export-id');
    292                 }
    293 
    294                 if (this.__exportsCache[sectionId]) {
    295                     return this.__exportsCache[sectionId];
    296                 }
    297 
    298                 var sectionData = CP_Customizer.options('data:sections', []).filter(function (s) {
    299                     return s.id === sectionId
    300                 }).pop();
    301 
    302                 var modules = {},
    303                     module = {},
    304                     exports = {};
    305 
    306                 if (sectionData && sectionData.export) {
    307                     try {
    308                         eval(sectionData.export);
    309 
    310                         if (!_.isUndefined(modules.export)) {
    311                             exports = modules.export;
    312                         } else {
    313                             if (!_.isUndefined(module.exports)) {
    314                                 exports = module.exports;
    315                             }
    316                         }
    317                     } catch (e) {
    318                         console.warn('invalid section ' + sectionId + ' exports');
    319                     }
    320 
    321                 }
    322 
    323                 this.__exportsCache[sectionId] = exports;
    324                 return exports || {};
    325             },
    326 
    327 
    328             slugPrefix: function () {
    329                 return root.cpCustomizerGlobal.pluginOptions.slugPrefix;
    330             },
    331 
    332 
    333             log: function (name, data, type) {
    334 
    335                 if (!CP_Customizer.options('SCRIPT_DEBUG', false) && !top.SCRIPT_DEBUG) {
    336                     return;
    337                 }
    338 
    339                 type = type || 'log';
    340 
    341                 var colors = {
    342                     'log': 'background-color:#03a9f4; color:#ffffff',
    343                     'error': 'background-color:#ff0000; color:#ffffff'
    344                 };
    345 
    346                 if (!data) {
    347                     data = 'NO DATA';
    348                 }
    349 
    350                 console.groupCollapsed('%c  ' + name + '  ', colors[type]);
    351                 console[type](data);
    352                 console.groupEnd();
    353             },
    354 
    355 
    356             logError: function (name, data) {
    357                 this.log(name, data, 'error');
    358             },
    359 
    360 
    361             bind: function (event, callback) {
    362                 this.on(event, callback, false);
    363             },
    364             unbind: function (event, callback) {
    365                 this.off(event, callback);
    366             },
    367 
    368             on: function (event, callback, async) {
    369 
    370                 event = event.split(' ').map(function (ev) {
    371                     return 'cp_customizer.' + ev;
    372                 }).join(' ');
    373 
    374                 if (async) {
    375                     var originalCallback = callback;
    376 
    377                     callback = function () {
    378                         var args = Array.from(arguments);
    379                         var cb = this.callback;
    380 
    381                         setTimeout(function () {
    382                             cb.apply(this, args);
    383                         }, 0);
    384 
    385                     }.bind({
    386                         callback: originalCallback
    387                     });
    388                 }
    389 
    390                 $(window).bind(event, callback);
    391             },
    392 
    393             off: function (event, callback) {
    394                 event = event.split(' ').map(function (ev) {
    395                     return 'cp_customizer.' + ev;
    396                 }).join(' ');
    397                 $(window).unbind(event, callback);
    398             },
    399 
    400             one: function (event, callback) {
    401                 event = event.split(' ').map(function (ev) {
    402                     return 'cp_customizer.' + ev;
    403                 }).join(' ');
    404                 $(window).one(event, callback);
    405             },
    406 
    407 
    408             trigger: function (event, data) {
    409                 $(window).trigger('cp_customizer.' + event, data);
    410             },
    411 
    412             showLoader: function () {
    413                 $('div#cp-full-screen-loader').addClass('active');
    414                 jQuery('select').each(function () {
    415                     var $select = $(this);
    416                     if ($select.data() && $select.data().selectize) {
    417                         $select.data().selectize.blur();
    418                     }
    419                 });
    420             },
    421 
    422             hideLoader: function () {
    423                 $('div#cp-full-screen-loader').removeClass('active');
    424             },
    425 
    426             jsTPL: {},
    427 
    428             __containerDataHandlers: {},
    429 
    430             addContainerDataHandler: function (selector, getter, setter) {
    431                 this.__containerDataHandlers[selector] = {
    432                     getter: getter,
    433                     setter: setter
    434                 };
    435             },
    436 
    437             __containerDataFilters: [],
    438 
    439             addContainerDataFilter: function (callback) {
    440                 this.__containerDataFilters.push(callback);
    441             },
    442 
    443 
    444             __modules: [],
    445             __modulesLoaded: false,
    446             addModule: function (callback) {
    447                 var self = this;
    448 
    449                 if (this.__modulesLoaded) {
    450                     callback(this);
    451                 } else {
    452                     this.__modules.push(callback);
    453                 }
    454             },
    455 
    456             popUp: function (title, elementID, data) {
    457                 var selector = "#TB_inline?inlineId=" + elementID;
    458                 var query = [];
    459 
    460 
    461                 $.each(data || {}, function (key, value) {
    462                     query.push(key + "=" + value);
    463                 });
    464 
    465                 selector = query.length ? selector + "&" : selector + "";
    466                 selector += query.join("&");
    467 
    468                 root.tb_show(title, selector);
    469 
    470                 root.jQuery('#TB_window').css({
    471                     'z-index': '5000001',
    472                     'transform': 'opacity .4s',
    473                     'opacity': 0
    474                 });
    475 
    476                 root.jQuery('#TB_overlay').css({
    477                     'z-index': '5000000'
    478                 });
    479 
    480 
    481                 setTimeout(function () {
    482                     root.jQuery('#TB_window').css({
    483                         'margin-top': -1 * ((root.jQuery('#TB_window').outerHeight() + 50) / 2),
    484                         'opacity': 1
    485                     });
    486                     root.jQuery('#TB_window').find('#cp-item-ok').focus();
    487                 }, 0);
    488 
    489                 if (data && data.class) {
    490                     root.jQuery('#TB_window').addClass(data.class);
    491                 }
    492 
    493                 return root.jQuery('#TB_window');
    494             },
    495 
    496 
    497             popUpInfo: function (title, content, data) {
    498                 var id = _.uniqueId('temp-popup-text');
    499 
    500                 var tempContainer = $('<div id="' + id + '" />').hide();
    501                 tempContainer.appendTo($('body'));
    502                 tempContainer.append('<div>' + content + '</div>');
    503 
    504                 return this.popUp(title, id, data);
    505 
    506             },
    507 
    508             popupPrompt: function (title, text, value, callback, extraHTML) {
    509 
    510                 if (extraHTML) {
    511                     extraHTML = '<div class="prompt-extra">' + extraHTML + '</div>';
    512                 } else {
    513                     extraHTML = '';
    514                 }
    515 
    516                 var content = '' +
    517                     '<div class="prompt-wrapper">' +
    518                     '   <h4 class="prompt-title">' + text + '</h4>' +
    519                     '   <div class="prompt-content">' +
    520                     '      <input value="' + CP_Customizer.utils.htmlEscape(value) + '" type="text">' +
    521                     '   </div>' +
    522                     '   ' + extraHTML +
    523                     '   <div class="prompt-footer">' +
    524                     '      <button class="submit button button-primary"> ' + root.CP_Customizer.translateCompanionString("OK") + '</button>' +
    525                     '      <button class="cancel button button-secondary">' + root.CP_Customizer.translateCompanionString("Cancel") + '</button>' +
    526                     '   </div>' +
    527                     '</div>';
    528 
    529                 var data = {
    530                     width: "400",
    531                     class: "popup-400"
    532                 };
    533 
    534                 var $content = this.popUpInfo(title, content, data);
    535 
    536                 function onClose(canceled) {
    537                     var newValue = $content.find('input').val().trim();
    538 
    539                     if (canceled) {
    540                         newValue = null;
    541                     }
    542 
    543                     if (_.isFunction(callback)) {
    544                         callback(newValue, value)
    545                     }
    546                     CP_Customizer.closePopUps();
    547                 }
    548 
    549                 $content.on('keypress', 'input', function () {
    550                     if (event.which !== 13) {
    551                         return true;
    552                     }
    553                     onClose();
    554                 });
    555 
    556                 $content.on('click', 'button.submit', function () {
    557                     onClose();
    558                 });
    559 
    560 
    561                 $content.on('click', 'button.cancel', function () {
    562                     onClose(true);
    563                 });
    564 
    565             },
    566 
    567             popupSelectPrompt: function (title, text, value, options, callback, emptySelection, extraHTML) {
    568                 var select = '<select>';
    569 
    570 
    571                 if (emptySelection) {
    572                     select += "<option value='' >" + emptySelection + "</option>";
    573                 }
    574 
    575                 for (var i in options) {
    576                     var selectedAttr = (i === value) ? "selected" : "";
    577                     select += "<option " + CP_Customizer.utils.htmlEscape(selectedAttr) + " value='" + i + "' >" + options[i] + "</option>";
    578                 }
    579 
    580                 select += '</select>';
    581                 if (extraHTML) {
    582                     extraHTML = '<div class="prompt-extra">' + extraHTML + '</div>';
    583                 } else {
    584                     extraHTML = '';
    585                 }
    586 
    587                 var content = '' +
    588                     '<div class="prompt-wrapper">' +
    589                     '   <h4 class="prompt-title">' + text + '</h4>' +
    590                     '   <div class="prompt-content">' +
    591                     '       ' + select +
    592                     '   </div>' +
    593                     '   ' + extraHTML +
    594                     '   <div class="prompt-footer">' +
    595                     '      <button class="submit button button-primary"> ' + root.CP_Customizer.translateCompanionString("OK") + '</button>' +
    596                     '      <button class="cancel button button-secondary">' + root.CP_Customizer.translateCompanionString("Cancel") + '</button>' +
    597                     '   </div>' +
    598                     '</div>';
    599 
    600                 var data = {
    601                     width: "400",
    602                     class: "popup-400"
    603                 };
    604 
    605                 var $content = this.popUpInfo(title, content, data);
    606 
    607                 function onClose(canceled) {
    608                     var newValue = $content.find('select').val();
    609 
    610                     if (canceled) {
    611                         newValue = null;
    612                     }
    613 
    614                     if (_.isFunction(callback)) {
    615                         callback(newValue, value)
    616                     }
    617                     CP_Customizer.closePopUps();
    618                 }
    619 
    620                 $content.on('click', 'button.submit', function () {
    621                     onClose();
    622                 });
    623 
    624 
    625                 $content.on('click', 'button.cancel', function () {
    626                     onClose(true);
    627                 });
    628 
    629                 return $content;
    630 
    631             },
    632 
    633             closePopUps: function () {
    634                 root.tb_remove();
    635                 root.jQuery('#TB_overlay').css({
    636                     'z-index': '-1'
    637                 });
    638             },
    639 
    640             openMultiImageManager: function (title, callback, single) {
    641                 var node = false;
    642                 var interestWindow = root;
    643                 custom_uploader = interestWindow.wp.media.frames.file_frame = interestWindow.wp.media({
    644                     title: title,
    645                     button: {
    646                         text: root.CP_Customizer.translateCompanionString('Choose Images')
    647                     },
    648                     multiple: !single
    649                 });
    650                 //When a file is selected, grab the URL and set it as the text field's value
    651                 custom_uploader.on('select', function () {
    652                     var attachment = custom_uploader.state().get('selection').toJSON();
    653                     callback(attachment);
    654                 });
    655                 custom_uploader.off('close.cp').on('close.cp', function () {
    656                     callback(false);
    657                 });
    658                 //Open the uploader dialog
    659                 custom_uploader.open();
    660 
    661                 custom_uploader.content.mode('browse');
    662                 // Show Dialog over layouts frame
    663                 interestWindow.jQuery(interestWindow.wp.media.frame.views.selector).parent().css({
    664                     'z-index': '16000000'
    665                 });
    666             },
    667 
    668             openImageManager: function (callback, multi) {
    669                 this.openMultiImageManager('Image Manager', function (obj) {
    670                     if ($('iframe').length) {
    671                         $('iframe').get(0).focus();
    672                     }
    673                     if (!obj) {
    674                         return;
    675                     }
    676                     for (var i = 0; i < obj.length; i++) {
    677                         var link = obj[i].url;
    678                         callback(link);
    679                     }
    680                 }, !multi);
    681             },
    682 
    683             openMediaCustomFrame: function (extender, mode, title, single, callback) {
    684                 var interestWindow = root;
    685 
    686                 var frame = extender(interestWindow.wp.media.view.MediaFrame.Select);
    687 
    688                 var custom_uploader = new frame({
    689                     title: title,
    690                     button: {
    691                         text: title
    692                     },
    693                     multiple: !single
    694                 });
    695 
    696 
    697                 //When a file is selected, grab the URL and set it as the text field's value
    698                 custom_uploader.on('select', function () {
    699                     attachment = custom_uploader.state().get('selection').toJSON();
    700                     custom_uploader.content.mode('browse');
    701                     callback(attachment);
    702                 });
    703 
    704 
    705                 custom_uploader.on('close', function () {
    706                     custom_uploader.content.mode('browse');
    707                     callback(false);
    708                 });
    709 
    710                 //Open the uploader dialog
    711                 custom_uploader.open();
    712                 custom_uploader.content.mode(mode);
    713                 // Show Dialog over layouts frame
    714                 interestWindow.jQuery(custom_uploader.views.selector).parent().css({
    715                     'z-index': '16000000'
    716                 });
    717 
    718             },
    719 
    720             openMIManager: function (title, callback, single) {
    721                 var node = false;
    722                 var interestWindow = root;
    723 
    724                 // if (!interestWindow.wp.media.cp.FAFrame) {
    725                 var frame = interestWindow.wp.media.cp.extendFrameWithMDI(interestWindow.wp.media.view.MediaFrame.Select);
    726                 var custom_uploader = new frame({
    727                     title: title,
    728                     button: {
    729                         text: root.CP_Customizer.translateCompanionString('Choose Icon')
    730                     },
    731                     multiple: !single
    732                 });
    733                 interestWindow.wp.media.cp.MIFrame = custom_uploader;
    734 
    735                 // }
    736 
    737 
    738                 //When a file is selected, grab the URL and set it as the text field's value
    739                 interestWindow.wp.media.cp.MIFrame.on('select', function () {
    740                     attachment = custom_uploader.state().get('selection').toJSON();
    741                     interestWindow.wp.media.cp.MIFrame.content.mode('browse');
    742                     callback(attachment);
    743                 });
    744                 interestWindow.wp.media.cp.MIFrame.on('close', function () {
    745                     interestWindow.wp.media.cp.MIFrame.content.mode('browse');
    746                     callback(false);
    747                 });
    748 
    749                 //Open the uploader dialog
    750                 interestWindow.wp.media.cp.MIFrame.open();
    751                 interestWindow.wp.media.cp.MIFrame.content.mode('cp_material_icons');
    752                 // Show Dialog over layouts frame
    753                 interestWindow.jQuery(custom_uploader.views.selector).parent().css({
    754                     'z-index': '16000000'
    755                 });
    756 
    757             },
    758 
    759             openCropableImageManager: function (width, height, flexible, callback) {
    760                 var control = new root.wp.customize.CroppedImageControl('custom_image_cropper[' + Date.now() + ']',
    761                     {params: {}});
    762 
    763                 control.params = {
    764                     button_labels: {
    765                         frame_title: root.CP_Customizer.translateCompanionString("Select Image")
    766                     },
    767                     height: height,
    768                     width: width
    769 
    770                 };
    771 
    772                 flexible = _.isUndefined(flexible) ? true : flexible;
    773 
    774                 if (flexible) {
    775                     control.params = _.extend(control.params, {
    776                         flex_width: width,
    777                         flex_height: height
    778                     });
    779                 }
    780 
    781                 control.initFrame();
    782                 control.frame.setState('library').open();
    783                 control.frame.content.mode('browse');
    784 
    785                 function fixCropKeyPressBug() {
    786                     setTimeout(function () {
    787                         root.jQuery(top.document).unbind(root.jQuery.imgAreaSelect.keyPress);
    788                     }, 100);
    789                 }
    790 
    791                 control.setImageFromAttachment = function (attachment) {
    792                     callback([attachment]);
    793                     fixCropKeyPressBug();
    794                 };
    795 
    796                 control.frame.on('close', function () {
    797                     fixCropKeyPressBug();
    798                 });
    799 
    800 
    801                 root.jQuery(control.frame.views.selector).parent().css({
    802                     'z-index': '16000000'
    803                 });
    804 
    805                 root.jQuery(control.frame.views.selector).find('.instructions').remove();
    806 
    807 
    808                 control.frame.on('content:create:crop', function () {
    809                     var c = control;
    810                     var state = c.frame.state();
    811                     var __createCropToolbar = state.createCropToolbar;
    812                     state.createCropToolbar = function () {
    813                         state.set('canSkipCrop', true);
    814                         __createCropToolbar.apply(state, arguments);
    815                     };
    816 
    817                 });
    818             },
    819 
    820             openGalleryImageManager: function (options, callback) {
    821                 var interestWindow = root;
    822                 options = _.extend({
    823                     "shortocode": false,
    824                     "ids": [],
    825                     "columns": "5",
    826                     "state": 'gallery-edit',
    827                     "size": "medium",
    828                     "link": "file"
    829                 }, options);
    830 
    831 
    832                 if (_.isArray(options.ids)) {
    833                     options.ids = options.ids.join(",");
    834                 }
    835 
    836                 if (_.isEmpty(options.ids.trim())) {
    837                     options.ids = 'fake-' + Date.now();
    838                 }
    839 
    840                 var shortcode = "[gallery";
    841                 $.each(options, function (index, val) {
    842                     shortcode += " " + index + '="' + val + '"';
    843                 });
    844                 shortcode += "]";
    845 
    846                 var gallery = interestWindow.wp.media.gallery;
    847                 var frame = gallery.edit(shortcode);
    848 
    849 
    850                 frame.state(options.state).on('update', function (selection) {
    851                     var ids = selection.map(function (model) {
    852                         return model.id
    853                     });
    854                     callback(selection, ids);
    855                 });
    856 
    857 
    858                 // if (options.mediaSidebar === false) {
    859                 //     frame.$el.find('.media-sidebar').hide();
    860                 //     frame.$el.find('.media-sidebar').siblings('.media-toolbar ul').css('right', '0px');
    861                 // } else {
    862                 //     frame.$el.find('.media-sidebar').siblings('.media-toolbar ul').css('right', '');
    863                 //     frame.$el.find('.media-sidebar').show();
    864                 // }
    865 
    866                 interestWindow.jQuery(frame.views.selector).parent().css({
    867                     'z-index': '16000000'
    868                 });
    869 
    870                 if (options.ids.match(/fake-\d+/)) {
    871                     frame.setState('gallery-library')
    872                 }
    873             },
    874 
    875             openMediaBrowser: function (type, callback, data) {
    876                 var cb;
    877                 if (callback instanceof jQuery) {
    878                     cb = function (response) {
    879 
    880                         if (!response) {
    881                             return;
    882                         }
    883 
    884                         var value = response[0].url;
    885                         if (data !== "multiple") {
    886                             if (type == "icon") {
    887                                 value = response[0].mdi;
    888                             }
    889                             callback.val(value).trigger('change');
    890                         }
    891                     };
    892                 } else {
    893                     cb = function () {
    894                         callback.apply(this, arguments);
    895                         CP_Customizer.preview.blur();
    896                     }
    897                 }
    898 
    899                 switch (type) {
    900                     case "image":
    901                         // this.openMultiImageManager('Change image', cb, data);
    902                         this.openCropableImageManager(data.width || this.MAX_SAFE_INTEGER, data.height || this.MAX_SAFE_INTEGER, true, cb);
    903                         break;
    904                     case "cropable":
    905                         this.openCropableImageManager(data.width, data.height, data.flexible, cb);
    906                         break;
    907                     case "icon":
    908                         this.openMIManager(root.CP_Customizer.translateCompanionString('Change Material Icon'), cb);
    909                         break;
    910                     case "gallery":
    911                         this.openGalleryImageManager(data, cb);
    912                         break;
    913                 }
    914             },
    915 
    916             getCustomizerRootEl: function () {
    917                 return root.jQuery(root.document.body).find('form#customize-controls');
    918             },
    919 
    920             openRightSidebar: function (elementId, options) {
    921                 options = options || {};
    922                 this.hideRightSidebar();
    923                 var $form = this.getCustomizerRootEl();
    924                 var $container = $form.find('#' + elementId + '-popup');
    925 
    926                 $('body').addClass('cp-right-section-opened');
    927                 if ($container.length) {
    928                     $container.addClass('active');
    929 
    930                     if (options.floating && !_(options.y).isUndefined()) {
    931                         $container.css({
    932                             top: options.y
    933                         });
    934                     }
    935                 } else {
    936                     $container = $('<li id="' + elementId + '-popup" class="customizer-right-section active"> <span data-close-right-sidebar="true" title="' + root.CP_Customizer.translateCompanionString("Close Panel") + '" class="close-panel"></span> </li>');
    937 
    938                     if (options.floating) {
    939                         $container.addClass('floating');
    940                     }
    941 
    942                     $toAppend = $form.find('li#accordion-section-' + elementId + ' > ul');
    943 
    944                     if ($toAppend.length === 0) {
    945                         $toAppend = $form.find('#sub-accordion-section-' + elementId);
    946                     }
    947 
    948 
    949                     if ($toAppend.length === 0) {
    950                         $toAppend = $('<div class="control-wrapper" />');
    951                         $toAppend.append($form.find('#customize-control-' + elementId).children());
    952                     }
    953 
    954                     $form.append($container);
    955                     $container.append($toAppend);
    956 
    957                     if (options.floating && !_(options.y).isUndefined()) {
    958                         $container.css({
    959                             top: options.y
    960                         });
    961                     }
    962 
    963 
    964                     $container.find('span.close-panel').click(CP_Customizer.hideRightSidebar);
    965 
    966                 }
    967 
    968                 if (options.focus) {
    969                     $container.find(options.focus)[0].scrollIntoViewIfNeeded();
    970                 }
    971 
    972                 $container.css('left', jQuery('#customize-header-actions')[0].offsetWidth + 1);
    973 
    974                 CP_Customizer.hooks.doAction('right_sidebar_opened', elementId, options, $container);
    975 
    976                 $form.find('span[data-close-right-sidebar="true"]').click(function (event) {
    977                     event.preventDefault();
    978                     event.stopPropagation();
    979                     CP_Customizer.hideRightSidebar();
    980                 });
    981 
    982                 $form.find('li.accordion-section').unbind('click.right-section').bind('click.right-section', function (event) {
    983                     if ($(event.target).is('li') || $(event.target).is('.accordion-section-title')) {
    984                         if ($(event.target).closest('.customizer-right-section').length === 0) {
    985                             CP_Customizer.hideRightSidebar();
    986                         }
    987                     }
    988                 });
    989 
    990             },
    991 
    992             hideRightSidebar: function () {
    993                 var $form = root.jQuery(root.document.body).find('#customize-controls');
    994                 var $visibleSection = $form.find('.customizer-right-section.active');
    995                 if ($visibleSection.length) {
    996                     $visibleSection.removeClass('active');
    997                     root.CP_Customizer.trigger(root.CP_Customizer.events.RIGHT_SECTION_CLOSED, [$visibleSection]);
    998                 }
    999 
   1000             },
   1001 
   1002             isRightSidebarVisible: function (sectionID) {
   1003                 var $form = root.jQuery(root.document.body).find('#customize-controls');
   1004                 return $form.find('#' + sectionID + '-popup').hasClass('active');
   1005             },
   1006 
   1007             updateState: function (force, forceOverlays) {
   1008 
   1009                 function callback() {
   1010                     CP_Customizer.trigger('STATE_UPDATED');
   1011                 }
   1012 
   1013                 if (force) {
   1014                     this._setContent(callback);
   1015                 } else {
   1016                     this.setContent(callback);
   1017                 }
   1018 
   1019                 this.overlays.hoverOverlay().hide();
   1020                 this.overlays.updateAllOverlays(forceOverlays);
   1021             },
   1022 
   1023 
   1024             __changesetUpdate: _.debounce(function (callback) {
   1025                 var changeSet = root.CP_Customizer.wpApi.requestChangesetUpdate.apply(root.CP_Customizer.wpApi);
   1026                 if (_.isFunction(callback)) {
   1027                     changeSet.then(callback);
   1028                 }
   1029             }, 10),
   1030 
   1031             __requestCachedCbs: [],
   1032             requestChangesetUpdate: function (cb) {
   1033                 if (_.isFunction(cb)) {
   1034                     this.__requestCachedCbs.push(cb);
   1035                 }
   1036                 var self = this;
   1037                 this.__changesetUpdate(function () {
   1038                     while (self.__requestCachedCbs.length) {
   1039                         var cb = self.__requestCachedCbs.shift();
   1040                         cb.call(self);
   1041                     }
   1042                 });
   1043             },
   1044 
   1045             // if the mod is not set create a dirty one
   1046             __onSetForcedTransport: {},
   1047             setMod: function (mod, value, transport, reqCB) {
   1048 
   1049                 mod = CP_Customizer.utils.phpTrim(mod, "|");
   1050 
   1051                 var initialMod = mod;
   1052                 var modParts = mod.split('|');
   1053                 mod = modParts.shift();
   1054 
   1055                 var setting = root.wp.customize(mod);
   1056                 value = _.clone(value);
   1057                 if (!setting) {
   1058                     mod = "CP_AUTO_SETTING[" + mod + "]";
   1059                     setting = root.wp.customize(mod);
   1060                     if (!setting) {
   1061                         setting = wp.customize.create(mod, mod, {}, {
   1062                             type: 'theme_mod',
   1063                             transport: (transport || 'postMessage'),
   1064                             previewer: wp.customize.previewer
   1065                         });
   1066                     }
   1067                 }
   1068 
   1069                 var oldTransport = setting.transport;
   1070                 if (!this.__onSetForcedTransport[setting.id]) {
   1071                     this.__onSetForcedTransport[setting.id] = oldTransport;
   1072                 }
   1073 
   1074                 if (transport) {
   1075                     setting.transport = transport;
   1076                 }
   1077 
   1078                 var oldValue = _.clone(setting._value);
   1079 
   1080                 var jsonEncoded = false;
   1081                 try {
   1082                     var parsed = decodeURI(oldValue);
   1083                     parsed = JSON.parse(parsed);
   1084 
   1085                     if (_.isObject(parsed) || _.isArray(parsed)) {
   1086                         oldValue = parsed;
   1087                         jsonEncoded = true;
   1088                     }
   1089                 } catch (e) {
   1090 
   1091                 }
   1092 
   1093                 if (_.isObject(oldValue)) {
   1094                     setting._value = undefined; // force no value before set( forces the setting to set the value )
   1095                 }
   1096 
   1097                 if (modParts.length) {
   1098 
   1099                     if (!oldValue || _.isEmpty(oldValue)) {
   1100                         oldValue = CP_Customizer.preview.data('mod_defaults')[mod];
   1101                     }
   1102 
   1103                     var path = modParts.join('.');
   1104                     value = CP_Customizer.utils.setToPath(oldValue, path, value);
   1105                 }
   1106 
   1107                 var control = wp.customize.control(mod);
   1108 
   1109 
   1110                 if (jsonEncoded) {
   1111                     value = encodeURI(JSON.stringify(value));
   1112                 }
   1113 
   1114                 if (_.isBoolean(oldValue)) {
   1115                     try {
   1116                         value = JSON.parse(value);
   1117                     } catch (e) {
   1118 
   1119                     }
   1120                 }
   1121 
   1122                 setting.set(value);
   1123 
   1124                 // update control
   1125 
   1126                 if (control) {
   1127                     var type = control.params.type;
   1128                     if (type === "radio-html") {
   1129                         jQuery(control.container.find('input[value="' + value + '"]')).prop('checked', true);
   1130                     } else {
   1131                         if (type === "kirki-spacing") {
   1132                             for (var prop in value) {
   1133                                 if (value.hasOwnProperty(prop)) {
   1134                                     jQuery(control.container.find('.' + prop + ' input')).prop('value', value[prop]);
   1135                                 }
   1136                             }
   1137                         } else {
   1138                             if (type.match('kirki')) {
   1139                                 kirkiSetSettingValue(mod, value);
   1140                             } else {
   1141                                 if (type == "gradient-control-pro") {
   1142                                     control.setValue(value);
   1143                                 } else {
   1144                                     if (type == "repeater") {
   1145                                         control.setValue(value);
   1146                                     }
   1147                                 }
   1148                             }
   1149                         }
   1150                     }
   1151                 }
   1152 
   1153                 var self = this;
   1154                 var changeSetCB = function () {
   1155                     if (self.__onSetForcedTransport[setting.id]) {
   1156                         setting.transport = self.__onSetForcedTransport[setting.id];
   1157                         self.__onSetForcedTransport[setting.id] = null;
   1158                     }
   1159 
   1160                     if (_.isFunction(reqCB)) {
   1161                         reqCB(initialMod, setting.id);
   1162                     }
   1163 
   1164                 };
   1165 
   1166                 if (_.isFunction(reqCB)) {
   1167                     this.requestChangesetUpdate(changeSetCB);
   1168                 } else {
   1169                     setting.transport = oldTransport;
   1170                 }
   1171 
   1172             },
   1173 
   1174             getMod: function (mod, defaultValue) {
   1175                 var setting = root.wp.customize(mod);
   1176                 if (!setting) {
   1177                     mod = "CP_AUTO_SETTING[" + mod + "]";
   1178                     setting = root.wp.customize(mod);
   1179                 }
   1180 
   1181                 if (!setting) {
   1182                     return defaultValue;
   1183                 }
   1184 
   1185                 return _.clone(setting.get());
   1186             },
   1187 
   1188             cleanModValue: function (value) {
   1189 
   1190                 if (_.isString(value)) {
   1191 
   1192                     // remove extra mdi classes ( e.g. "mdi mdi mdi" )
   1193                     value = value.replace(/(mdi\s(mdi\s)+)/ig, 'mdi ');
   1194 
   1195                     // trim all spaces
   1196                     value = value.trim();
   1197                 }
   1198 
   1199                 return value;
   1200             },
   1201 
   1202             onModChange: function (mod, callback) {
   1203                 var autoMod = "CP_AUTO_SETTING[" + mod + "]";
   1204                 var modCallback = _.debounce(function (value) {
   1205                     if (_.isFunction(callback)) {
   1206                         value.bind(callback);
   1207                     }
   1208                 }, 100);
   1209 
   1210 
   1211                 CP_Customizer.wpApi(mod, modCallback);
   1212                 CP_Customizer.wpApi(autoMod, modCallback);
   1213 
   1214             },
   1215 
   1216             setMultipleMods: function (mods, transport, finishCb) {
   1217 
   1218                 CP_Customizer.log('Set Multiple Mods', mods);
   1219 
   1220                 if (_.isEmpty(mods)) {
   1221                     if (finishCb) finishCb();
   1222                     return;
   1223                 }
   1224 
   1225                 $(root).off('blur.wp-customize-changeset-update');
   1226                 var modsIDs = Object.getOwnPropertyNames(mods);
   1227                 var modsDone = [];
   1228 
   1229                 var reqCB = function (mod) {
   1230                     if (modsDone.indexOf(mod) === -1) {
   1231                         modsDone.push(mod);
   1232                     }
   1233 
   1234                     if (_.difference(modsIDs, modsDone).length === 0) {
   1235                         if (_.isFunction(finishCb)) {
   1236                             finishCb();
   1237                         }
   1238                     }
   1239                 };
   1240 
   1241 
   1242                 _.each(mods, function (value, mod) {
   1243                     CP_Customizer.setMod(mod, value, transport, reqCB);
   1244                 });
   1245             },
   1246 
   1247             _currentContentValues: {},
   1248             _setContent: function (callback) {
   1249                 var previewJQuery = CP_Customizer.preview.jQuery();
   1250 
   1251                 if (root.CP_Customizer.preview.data().maintainable) {
   1252                     var content = root.CP_Customizer.preview.getContent().trim();
   1253                     var setting = root.wp.customize('page_content');
   1254                     if (!setting) {
   1255                         return;
   1256                     }
   1257 
   1258                     var value = setting.get();
   1259                     if (_.isString(value)) {
   1260                         value = JSON.parse(decodeURIComponent(value));
   1261                     }
   1262 
   1263                     if (_.isArray(value) && _.isEmpty(value)) {
   1264                         value = {};
   1265                     }
   1266 
   1267                     if (!value) {
   1268                         value = {};
   1269                     }
   1270 
   1271                     value[root.CP_Customizer.preview.data().pageID] = content;
   1272 
   1273                     setting.set(encodeURIComponent(JSON.stringify(value)));
   1274                 }
   1275 
   1276                 var modsToSet = {};
   1277 
   1278                 this.preview.find("[data-theme-href]").each(function () {
   1279                     var prop = jQuery(this).attr('data-theme-href');
   1280                     var val = jQuery(this).attr('href').trim();
   1281 
   1282                     modsToSet[prop] = CP_Customizer.preview.cleanURL(val);
   1283                 });
   1284 
   1285                 this.preview.find("[data-theme-target]").each(function () {
   1286                     var prop = jQuery(this).attr('data-theme-target');
   1287                     var val = jQuery(this).attr('target') || "_self";
   1288 
   1289                     modsToSet[prop] = val.trim();
   1290                 });
   1291 
   1292 
   1293                 this.preview.find("[data-theme-src]").each(function () {
   1294                     var prop = jQuery(this).attr('data-theme-src');
   1295                     var val = jQuery(this).attr('src');
   1296                     // root.CP_Customizer.setMod(prop, val.trim());
   1297                     modsToSet[prop] = val.trim();
   1298                 });
   1299 
   1300                 this.preview.find("[data-theme-mdi]").each(function () {
   1301                     var prop = jQuery(this).attr('data-theme-mdi');
   1302                     var val = jQuery(this).attr('class').match(/mdi\-[a-z\-]+/ig).pop();
   1303                     // root.CP_Customizer.setMod(prop, val.trim());
   1304                     modsToSet[prop] = val.trim();
   1305                 });
   1306 
   1307                 if (root.CP_Customizer.options().mods) {
   1308                     for (var selector in root.CP_Customizer.options().mods) {
   1309                         var $el = this.preview.find(selector);
   1310                         var modData = root.CP_Customizer.options().mods[selector];
   1311                         if (modData.atts) {
   1312                             for (var attr in modData.atts) {
   1313                                 // $el.attr('data-theme-' + attr, modData.atts[attr]);
   1314                                 var prop = $el.attr('data-theme-' + attr);
   1315                                 var val = root.CP_Customizer.hooks.applyFilters('temp_attr_mod_value', $el.attr(attr) || "", attr, $el);
   1316                                 // root.CP_Customizer.setMod(prop, val.trim());
   1317                                 modsToSet[prop] = val.trim();
   1318                             }
   1319                         }
   1320 
   1321 
   1322                     }
   1323                 }
   1324 
   1325                 this.preview.find("[data-dynamic-mod='true'],[data-dynamic-mod='true'] *").each(function () {
   1326                     var atts = Array.from(this.attributes),
   1327                         $el = root.CP_Customizer.preview.find(this);
   1328 
   1329                     for (var i = 0; i < atts.length; i++) {
   1330                         var attr = atts[i].name,
   1331                             prop = atts[i].value;
   1332 
   1333                         if (attr.indexOf('data-theme-') === 0) {
   1334                             attr = attr.replace('data-theme-', '');
   1335                             var fallback = "";
   1336 
   1337                             var value = $el.attr(attr);
   1338 
   1339                             // logica inversa aici false daca exista, true daca nu
   1340                             if (attr === 'data-reiki-hidden') {
   1341                                 fallback = "true";
   1342 
   1343                                 if (value) {
   1344                                     value = 'false';
   1345                                 }
   1346 
   1347                             }
   1348 
   1349                             if (attr.trim() === 'href') {
   1350                                 value = CP_Customizer.preview.cleanURL(value);
   1351                             }
   1352 
   1353                             var val = root.CP_Customizer.hooks.applyFilters('temp_attr_mod_value', _.isUndefined(value) ? fallback : value, attr, $el);
   1354 
   1355                             modsToSet[prop] = CP_Customizer.cleanModValue(val);
   1356                         }
   1357 
   1358                     }
   1359                 });
   1360 
   1361                 this.preview.find("[data-theme]").each(function () {
   1362 
   1363                     var prop = jQuery(this).attr('data-theme');
   1364 
   1365                     if (!previewJQuery(this).data('was-changed')) {
   1366                         if (previewJQuery('[data-theme="' + prop + '"]').length > 1) {
   1367                             return;
   1368                         }
   1369                     }
   1370 
   1371                     // root.CP_Customizer.preview.cleanNode(toSave);
   1372                     // var toSave = jQuery(this).clone();
   1373 
   1374                     var toSave = jQuery(this).clone();
   1375                     var val = root.CP_Customizer.preview.getContent($(this));
   1376                     // root.CP_Customizer.setMod(prop, val);
   1377                     modsToSet[prop] = val.trim();
   1378                     previewJQuery(this).data('was-changed', false);
   1379                 });
   1380 
   1381                 root.CP_Customizer.cleanClose();
   1382 
   1383                 // update only when you find a change
   1384                 var uniqueMods = {};
   1385                 var self = this;
   1386                 _.each(modsToSet, function (value, mod) {
   1387                     if (self._currentContentValues[mod] !== value) {
   1388                         uniqueMods[mod] = value;
   1389                         self._currentContentValues[mod] = value;
   1390                     }
   1391                 });
   1392 
   1393                 CP_Customizer.setMultipleMods(uniqueMods, 'postMessage', callback);
   1394 
   1395             },
   1396 
   1397             setContent: _.debounce(function (callback) {
   1398                 this._setContent(callback);
   1399             }, 200),
   1400 
   1401             save: function () {
   1402 
   1403                 CP_Customizer.preview.blur();
   1404 
   1405                 $(root.document).find('body').addClass('saving');
   1406                 $(root.document).find('input#save').prop('disabled', true);
   1407 
   1408                 var self = this;
   1409                 var callback = function () {
   1410                     wp.customize.previewer.save();
   1411                 };
   1412                 self._setContent(callback);
   1413 
   1414             },
   1415 
   1416             cleanClose: function () {
   1417 
   1418             },
   1419 
   1420             __saveTimeout: false,
   1421 
   1422             markSave: _.debounce(function () {
   1423                 var self = this;
   1424                 clearTimeout(self.__saveTimeout);
   1425 
   1426                 self.__saveTimeout = setTimeout(function () {
   1427                     self.setContent();
   1428                 }, 500);
   1429             }, 200),
   1430 
   1431 
   1432             parseShortcode: function (shortcode) {
   1433                 shortcode = shortcode.replace('[', '').replace(']', '');
   1434 
   1435                 var tag = shortcode.split(' ')[0].trim();
   1436                 var shortcodeAttrs = shortcode.match(/(\s(.*?)=")(.*?)(")/ig);
   1437                 var response = {
   1438                     tag: tag,
   1439                     attrs: {}
   1440                 };
   1441                 if (!shortcodeAttrs) {
   1442                     return response;
   1443                 }
   1444                 for (var i = 0; i < shortcodeAttrs.length; i++) {
   1445                     var attr = shortcodeAttrs[i].trim();
   1446                     response.attrs[attr.split('=')[0]] = attr.split('="')[1].slice(0, -1)
   1447                 }
   1448                 return response;
   1449 
   1450             },
   1451 
   1452             isShortcodeContent: function ($node) {
   1453                 return root.jQuery($node).closest('[data-content-shortcode]').length > 0;
   1454             },
   1455 
   1456             isShortcodeEditable: function ($node) {
   1457                 var isEditableByTag = root.jQuery($node).closest('[data-content-shortcode][data-editable="true"]').length > 0;
   1458                 var tag = CP_Customizer.getNodeShortcode(root.jQuery($node).closest('[data-content-shortcode]'));
   1459 
   1460                 return CP_Customizer.hooks.applyFilters('is_shortcode_editable', isEditableByTag, tag);
   1461             },
   1462 
   1463             isOnCanvasMod: function (node) {
   1464                 node = $(node)[0];
   1465                 var hasThemeModAtt = Array.from(node.attributes).map(function (a) {
   1466 
   1467                     return (a.name.toLowerCase().indexOf('data-theme') !== -1);
   1468 
   1469                 }).reduce(function (a, b) {
   1470                     return a || b;
   1471                 });
   1472 
   1473                 return hasThemeModAtt;
   1474             },
   1475 
   1476             nodeWrapsShortcode: function ($node, tag) {
   1477                 var shortcode = this.getNodeShortcode($node);
   1478 
   1479                 if (shortcode) {
   1480                     return (shortcode.tag === tag.trim());
   1481                 }
   1482 
   1483                 return false;
   1484             },
   1485 
   1486             getNodeShortcode: function ($node) {
   1487                 if (!$node.attr('data-content-shortcode')) {
   1488                     return undefined;
   1489                 }
   1490 
   1491                 return this.parseShortcode($node.attr('data-content-shortcode'));
   1492             },
   1493 
   1494             nodeContainsShortcode: function ($node, tag) {
   1495                 var $containers = $node.find('[data-content-shortcode]');
   1496 
   1497                 for (var i = 0; i < $containers.length; i++) {
   1498                     if (CP_Customizer.nodeWrapsShortcode($containers.eq(i), tag)) {
   1499                         return true;
   1500                     }
   1501                 }
   1502 
   1503                 return false;
   1504             },
   1505 
   1506             renderNodeShortcodes: function ($node) {
   1507                 $node = $($node); // make sure the node is wrapped with jqury
   1508                 var $nodes = $node.find('[data-content-shortcode]');
   1509                 if ($node.is('[data-content-shortcode]')) {
   1510                     $nodes = $nodes.add($node);
   1511                 }
   1512                 var self = this;
   1513                 $nodes.each(function () {
   1514                     self.updateNodeShortcode($(this), "[" + $(this).attr('data-content-shortcode') + "]");
   1515                 })
   1516             },
   1517             updateNodeShortcode: function ($node, shortcode, noRerender, context) {
   1518                 if (!$node.attr('data-content-shortcode')) {
   1519                     return undefined;
   1520                 }
   1521 
   1522                 var attrShortcode = CP_Customizer.utils.phpTrim(shortcode, '[]');
   1523                 $node.attr('data-content-shortcode', attrShortcode);
   1524 
   1525                 if (noRerender !== true) {
   1526                     if (!context) {
   1527                         context = {
   1528                             query: CP_Customizer.preview.data().queryVars
   1529                         }
   1530                     }
   1531 
   1532                     (function ($node) {
   1533                         CP_Customizer.preview.pauseObserver();
   1534                         CP_Customizer.preview.blur();
   1535 
   1536                         var currentChangeset = CP_Customizer.utils.deepClone(wp.customize.previewer.query());
   1537 
   1538                         var data = _.extend(currentChangeset, {
   1539                             action: 'cp_shortcode_refresh',
   1540                             shortcode: btoa(shortcode),
   1541                             context: context,
   1542                             _: Date.now()
   1543                         });
   1544 
   1545                         $node.html('<div class="shortcode-temp-placeholder"></div>');
   1546                         jQuery.ajax({
   1547                             url: ajaxurl,
   1548                             method: 'POST',
   1549                             data: data
   1550                         }).done(function (response) {
   1551                             $node.empty();
   1552                             $node.html(response);
   1553 
   1554                             CP_Customizer.hideLoader();
   1555                             CP_Customizer.preview.decorateMods($node);
   1556                             CP_Customizer.preview.decorateElements($node);
   1557 
   1558                             _.delay(function () {
   1559                                 root.CP_Customizer.hooks.doAction("shortcode_updated", $node, shortcode);
   1560                                 root.CP_Customizer.updateState();
   1561                             }, 0);
   1562                         });
   1563                         CP_Customizer.preview.restartObserver();
   1564                     })($node);
   1565                 }
   1566 
   1567                 CP_Customizer.updateState();
   1568                 return true;
   1569             },
   1570 
   1571             updateNodeFromShortcodeObject: function ($node, shortcodeObj, noRerender, context) {
   1572                 var shortcode = '[' + shortcodeObj.tag + ' ';
   1573 
   1574                 for (var a in shortcodeObj.attrs) {
   1575                     shortcode += a + '="' + shortcodeObj.attrs[a] + '" ';
   1576                 }
   1577 
   1578                 shortcode += ']';
   1579 
   1580                 return this.updateNodeShortcode($node, shortcode, noRerender, context);
   1581             },
   1582 
   1583             preview: {
   1584                 frame: function () {
   1585                     var frame = wp.customize.previewer.targetWindow.get();
   1586 
   1587                     if (!frame) {
   1588                         frame = wp.customize.previewer.container.find('iframe')[0];
   1589 
   1590                         if (frame) {
   1591                             frame = frame.contentWindow;
   1592                         } else {
   1593                             frame = null;
   1594                         }
   1595                     }
   1596 
   1597                     return frame;
   1598                 },
   1599 
   1600                 currentDevice: function () {
   1601                     return jQuery('.active[data-device]').data('device');
   1602                 },
   1603 
   1604 
   1605                 __observerFunctionsToPause: ["prepareFormPreview", "prepareLinkPreview"],
   1606                 __observerOriginalFunctions: {},
   1607 
   1608                 pauseObserver: function () {
   1609                     var previewApi = CP_Customizer.preview.frame().wp.customize;
   1610 
   1611                     this.__observerOriginalFunctions = {};
   1612                     var self = CP_Customizer.preview;
   1613                     _.each(self.__observerFunctionsToPause, function (fn) {
   1614                         if (_.isFunction(previewApi[fn])) {
   1615                             self.__observerOriginalFunctions[fn] = previewApi[fn];
   1616                             previewApi[fn] = function () {
   1617                             };
   1618                         }
   1619                     });
   1620                 },
   1621 
   1622                 restartObserver: _.debounce(function () {
   1623                     var previewApi = CP_Customizer.preview.frame().wp.customize;
   1624 
   1625                     var self = CP_Customizer.preview;
   1626                     _.each(self.__observerFunctionsToPause, function (fn) {
   1627                         if (_.isFunction(previewApi[fn]) && _.isFunction(self.__observerOriginalFunctions[fn])) {
   1628                             previewApi[fn] = self.__observerOriginalFunctions[fn];
   1629                         }
   1630                     });
   1631                 }, 100),
   1632 
   1633 
   1634                 addSilentExecution: function (callback) {
   1635                     return _.compose(this.pauseObserver, callback, this.restartObserver);
   1636                 },
   1637 
   1638                 silentCall: function (callback) {
   1639                     var args = arguments.length > 1 ? arguments[1] : undefined;
   1640                     var context = arguments.length > 2 ? arguments[2] : this;
   1641 
   1642                     callback = this.addSilentExecution(callback);
   1643 
   1644                     return callback.apply(context, arguments);
   1645                 },
   1646 
   1647 
   1648                 refresh: _.throttle(function () {
   1649                     CP_Customizer.wpApi.previewer.refresh();
   1650                 }, 100),
   1651 
   1652                 data: function (key, defaultValue) {
   1653 
   1654                     if (!this.frame()) {
   1655                         return {};
   1656                     }
   1657 
   1658                     var result = this.frame().cpCustomizerPreview || {};
   1659 
   1660                     if (key) {
   1661                         var keyParts = key.split(':');
   1662                         for (var i = 0; i < keyParts.length; i++) {
   1663                             var part = keyParts[i];
   1664 
   1665                             if (!_.isUndefined(result[part])) {
   1666                                 result = result[part];
   1667                             } else {
   1668                                 result = defaultValue;
   1669                                 break;
   1670                             }
   1671                         }
   1672                     }
   1673 
   1674                     return result;
   1675                 },
   1676 
   1677                 getChangesetURL: function () {
   1678                     var changeset = wp.customize.settings.changeset.uuid ? "?changeset_uuid=" + wp.customize.settings.changeset.uuid : "";
   1679 
   1680                     if (changeset) {
   1681                         changeset += "&cp__changeset__preview=" + Date.now();
   1682                     }
   1683 
   1684                     return window.location.origin + window.location.pathname + changeset;
   1685                 },
   1686 
   1687                 isPageMaintainable: function () {
   1688                     return this.data.maintainable;
   1689                 },
   1690 
   1691                 // http://stackoverflow.com/questions/7451468/contenteditable-div-how-can-i-determine-if-the-cursor-is-at-the-start-or-end-o/7478420#7478420
   1692                 getSelectionTextInfo: function (el) {
   1693                     var atStart = false, atEnd = false;
   1694                     var window = this.frame();
   1695                     var document = this.frame().document;
   1696                     var selRange, testRange;
   1697                     if (window.getSelection) {
   1698                         var sel = window.getSelection();
   1699                         if (sel.rangeCount) {
   1700                             selRange = sel.getRangeAt(0);
   1701                             testRange = selRange.cloneRange();
   1702 
   1703                             testRange.selectNodeContents(el);
   1704                             testRange.setEnd(selRange.startContainer, selRange.startOffset);
   1705                             atStart = (testRange.toString() == "");
   1706 
   1707                             testRange.selectNodeContents(el);
   1708                             testRange.setStart(selRange.endContainer, selRange.endOffset);
   1709                             atEnd = (testRange.toString() == "");
   1710                         }
   1711                     } else if (document.selection && document.selection.type != "Control") {
   1712                         selRange = document.selection.createRange();
   1713                         testRange = selRange.duplicate();
   1714 
   1715                         testRange.moveToElementText(el);
   1716                         testRange.setEndPoint("EndToStart", selRange);
   1717                         atStart = (testRange.text == "");
   1718 
   1719                         testRange.moveToElementText(el);
   1720                         testRange.setEndPoint("StartToEnd", selRange);
   1721                         atEnd = (testRange.text == "");
   1722                     }
   1723 
   1724                     return {atStart: atStart, atEnd: atEnd};
   1725                 },
   1726 
   1727                 isCustomFrontPage: function () {
   1728                     return this.data.isFrontPage;
   1729                 },
   1730 
   1731                 jQuery: function (data) {
   1732                     if (data) {
   1733                         return this.frame().jQuery(data);
   1734                     }
   1735                     return this.frame().jQuery;
   1736                 },
   1737 
   1738                 getPageContainerSelector: function () {
   1739 
   1740                     if (!root.CP_Customizer.preview.data().maintainable) {
   1741                         '';
   1742                     }
   1743 
   1744                     var startSelector = "#cp_customizer_content_area_start";
   1745 
   1746                     var attrName = 'data-cp-content-container-' + top.CP_Customizer.slugPrefix();
   1747                     var $parent = this.jQuery(startSelector).parent();
   1748                     if (!$parent.attr(attrName)) {
   1749                         $parent.attr(attrName, _.uniqueId("page-content-container-"));
   1750                     }
   1751 
   1752                     selector = "[" + attrName + "='" + $parent.attr(attrName) + "']";
   1753 
   1754                     selector = CP_Customizer.hooks.applyFilters('page_content_container_selector', selector);
   1755 
   1756                     return selector;
   1757                 },
   1758 
   1759                 getRootNode: function () {
   1760                     if (!wp.customize('page_content')) {
   1761                         return this.jQuery("<div/>");
   1762                     }
   1763 
   1764                     return this.find(this.getPageContainerSelector());
   1765                 },
   1766 
   1767                 find: function (query) {
   1768                     var $ = this.jQuery();
   1769                     return $(query);
   1770                 },
   1771 
   1772                 getSectionByDataId: function (id) {
   1773                     return this.find('[data-id="' + id + '"]');
   1774                 },
   1775 
   1776                 getNodeSection: function (node) {
   1777                     var $node = CP_Customizer.preview.jQuery(node);
   1778                     if ($node.is('[data-id]')) {
   1779                         return $node;
   1780                     } else {
   1781                         return $node.closest('[data-id]');
   1782                     }
   1783                 },
   1784 
   1785                 getNodeAbsSelector: function (node, relativeSelector) {
   1786                     var section = this.getNodeSection(node),
   1787                         sectionId = "[data-id='" + section.attr('data-id') + "']",
   1788                         absSelector = sectionId + ' ' + relativeSelector;
   1789 
   1790                     return absSelector.replace(/\s\s?/, ' ').trim();
   1791                 },
   1792 
   1793                 getNodeSectionId: function (node) {
   1794                     var section = this.getNodeSection(node);
   1795                     return section.attr('data-id');
   1796                 },
   1797 
   1798                 getNodeExportId: function (node) {
   1799                     var section = this.getNodeSection(node);
   1800                     return section.attr('data-export-id');
   1801                 },
   1802 
   1803                 getThemeMods: function ($container) {
   1804                     if (!$container || $container.is(this.getRootNode())) {
   1805                         $container = this.jQuery('body');
   1806                     }
   1807 
   1808                     var themeModNodesSelector = root.CP_Customizer.hooks.applyFilters('theme_mod_nodes_selector', root.CP_Customizer.THEME_MOD_NODES);
   1809 
   1810                     if (root.CP_Customizer.options().mods) {
   1811                         for (var m in root.CP_Customizer.options().mods) {
   1812                             themeModNodesSelector += ',' + m;
   1813                         }
   1814                     }
   1815 
   1816                     $themeModNodes = $container.find(themeModNodesSelector);
   1817 
   1818                     if ($container.is(themeModNodesSelector)) {
   1819                         $themeModNodes.add($container);
   1820                     }
   1821 
   1822                     return $themeModNodes;
   1823                 },
   1824 
   1825                 getContentNodes: function (filter) {
   1826                 //replaced children() with contents() to also get html comments for gutenberg blocks
   1827                 var nodes = this.getRootNode().contents().toArray();
   1828                     nodes.html = function () {
   1829                         return this.map(function (node) {
   1830                         if (node.nodeType == Node.COMMENT_NODE) {
   1831                             return "<!--" + node.textContent + "-->";
   1832                         } else {
   1833                             return node.outerHTML;
   1834                         }
   1835                         }).join('');
   1836                     };
   1837 
   1838                     return nodes;
   1839                 },
   1840 
   1841                 getContent: function ($node) {
   1842 
   1843                     $node = $node || this.getContentNodes();
   1844                     var nodesHML = $node.html().//remove all gutenberg block comments they will be added back by decorate
   1845                     replace(/<!-- \/?wp:extendstudio\/materialis -->/gi, '').
   1846                     replace(/[\w-]+="gutenberg-section-\d+"/gi, '').
   1847                     replace(/[\w-]+="Gutenberg"/gi, '');
   1848                                         
   1849                     var $currentNodes = $('<div/>').append(nodesHML);
   1850 
   1851                     $currentNodes.find('.reiki-customizer-ordering-overlay').remove();
   1852 
   1853                     // cleanup inline styling, leaving only background properties and typography
   1854                     $currentNodes[0].querySelectorAll('[style]').forEach(function (el) {
   1855                         var style = el.getAttribute('style'),
   1856                             whitelistedProps = root.CP_Customizer.options('cssAllowedProperties'),
   1857                             inlineCss = {},
   1858                             styleProps = style.split(';');
   1859 
   1860                         for (var i = 0; i < styleProps.length; i++) {
   1861                             var propParts = styleProps[i].split(':'),
   1862                                 prop = (propParts.shift() || "").trim(),
   1863                                 value = (propParts || []).join(':').trim();
   1864 
   1865                             if (prop && value) {
   1866                                 inlineCss[prop] = value;
   1867                             }
   1868 
   1869                         }
   1870 
   1871                         var inlineCssText = "";
   1872 
   1873                         for (var prop in inlineCss) {
   1874                             inlineCssText += prop + ': ' + inlineCss[prop] + '; ';
   1875                         }
   1876 
   1877                         if (inlineCssText.trim()) {
   1878                             el.setAttribute('style', inlineCssText.trim());
   1879                         } else {
   1880                             el.removeAttribute('style');
   1881                         }
   1882 
   1883                         el.removeAttribute('data-mce-style');
   1884 
   1885                     });
   1886 
   1887 
   1888                     $currentNodes[0].querySelectorAll('[data-content-shortcode]').forEach(function (el) {
   1889                         el.innerHTML = '[' + CP_Customizer.utils.phpTrim(el.getAttribute('data-content-shortcode')) + ']';
   1890                     });
   1891 
   1892 
   1893                     $currentNodes[0].querySelectorAll('[data-attr-shortcode]').forEach(function (el) {
   1894                         var attr = el.getAttribute('data-attr-shortcode');
   1895                         var parts = attr.split(',');
   1896 
   1897                         for (var i = 0; i < parts.length; i++) {
   1898                             var part = parts[i].trim();
   1899                             part = part.split(':');
   1900                             el.setAttribute(part[0].trim(), '[' + part[1].trim() + ']');
   1901                         }
   1902                     });
   1903 
   1904 
   1905                     this.cleanNode($currentNodes);
   1906 
   1907                     CP_Customizer.hooks.doAction('clean_nodes', $currentNodes);
   1908 
   1909                     $currentNodes[0].querySelectorAll('*').forEach(function (el) {
   1910                         var attributes = el.attributes;
   1911                         for (var i = 0; i < attributes.length; i++) {
   1912                             var attrName = attributes.item(i).name;
   1913                             if (attrName.match(/scrollreveal/)) {
   1914                                 el.removeAttribute(attrName);
   1915                             }
   1916                         }
   1917                     });
   1918 
   1919                     $currentNodes.find('*').not('[data-cpid]').remove();
   1920 
   1921                     // $currentNodes.find('*').not('[data-cpid]').each(function () {
   1922                     //     var $el = $(this);
   1923 
   1924                     //     if ($el.attr('data-cp-remove-this')) {
   1925                     //         $el.remove();
   1926                     //     }
   1927 
   1928                     //     if (this.previousSibling && this.previousSibling.nodeType === 8) {
   1929                     //         var commentText = this.previousSibling.textContent,
   1930                     //             shortcode = "",
   1931                     //             startComment = "";
   1932 
   1933                     //         this.previousSibling.parentNode.removeChild(this.previousSibling);
   1934                     //         if (commentText.match(/cp-shortcode:(.*?):(.*)/)) {
   1935                     //             shortcode = commentText.match(/cp-shortcode:(.*?):(.*)/).pop();
   1936                     //             startComment = commentText;
   1937                     //         }
   1938 
   1939                     //         var nextSibling = this.nextSibling;
   1940 
   1941                     //         while (nextSibling) {
   1942                     //             if (nextSibling.nodeType === 8) {
   1943                     //                 var commentText = nextSibling.textContent;
   1944 
   1945                     //                 if (commentText.trim() === startComment.trim()) {
   1946                     //                     nextSibling.parentNode.removeChild(nextSibling);
   1947                     //                     break;
   1948                     //                 }
   1949                     //             }
   1950 
   1951                     //             $(nextSibling).attr('data-cp-remove-this', '1');
   1952                     //             nextSibling = nextSibling.nextSibling;
   1953                     //         }
   1954 
   1955                     //         this.outerHTML = shortcode;
   1956                     //     } else {
   1957                     //         $el.remove();
   1958                     //     }
   1959                     // });
   1960 
   1961                     $currentNodes.find('br').each(function () {
   1962                         if (!this.nextSibling) {
   1963                             $(this).remove();
   1964                         }
   1965                     });
   1966 
   1967                     CP_Customizer.hooks.applyFilters('get_content', $currentNodes);
   1968                 
   1969 	                //gutenberg
   1970                     this.decorateSectionsForGutenberg($currentNodes.find('[data-id][data-export-id]'));
   1971                     return $currentNodes.html().replace(/data-cpid="[^"]+"/gi, '');                    ;
   1972                 },
   1973 
   1974                 __cleanNode: function (el) {
   1975                     el.removeAttribute('data-content-editable');
   1976                     el.removeAttribute('data-content-code-editable');
   1977                     el.removeAttribute('data-container-editable');
   1978 	                el.removeAttribute('data-non-editable');
   1979                     el.removeAttribute('contenteditable');
   1980                     el.removeAttribute('spellcheck');
   1981 
   1982                     el.classList.remove('ui-sortable');
   1983                     el.classList.remove('ui-sortable-disabled');
   1984                     el.classList.remove('ui-sortable-handle');
   1985                     el.classList.remove('customize-unpreviewable');
   1986 
   1987                     var elClass = el.getAttribute('class');
   1988                     if (elClass) {
   1989                         // remove the tinymce (mce-*) classes;
   1990                         elClass = elClass.replace(/mce\-[a-z\-]+/ig, "").trim();
   1991 
   1992                         // remove multiple spaces in class names
   1993                         elClass = elClass.replace(/\s\s+/g, ' ');
   1994 
   1995                         el.setAttribute('class', elClass);
   1996                     }
   1997 
   1998                     if (el.id && el.id.indexOf('mce_') === 0) {
   1999                         el.removeAttribute('id');
   2000                     }
   2001 
   2002                     // preview styles
   2003                     el.removeAttribute('data-preview-empty');
   2004 
   2005                     // clean node url
   2006 
   2007                     if (el.getAttribute('href')) {
   2008                         var href = CP_Customizer.preview.cleanURL(el.getAttribute('href'));
   2009                         el.setAttribute('href', href)
   2010                     }
   2011                 },
   2012 
   2013 
   2014                 getNodeClasses: function (node) {
   2015                     var $clone = $(node).clone();
   2016                     this.__cleanNode($clone[0]);
   2017                     return Array.from($clone[0].classList);
   2018                 },
   2019 
   2020                 cleanNode: function ($node) {
   2021 
   2022                 $node[0].querySelectorAll('[data-content-editable], [data-content-code-editable], [data-container-editable], [data-non-editable]').forEach(function (el) {
   2023                         root.CP_Customizer.preview.__cleanNode(el);
   2024                     });
   2025 
   2026                     $node[0].querySelectorAll('.ui-sortable,.ui-sortable-disabled,.ui-sortable-handle').forEach(function (el) {
   2027                         root.CP_Customizer.preview.__cleanNode(el);
   2028                     });
   2029 
   2030                     root.CP_Customizer.preview.__cleanNode($node[0]);
   2031 
   2032                     return $node;
   2033                 },
   2034 
   2035                 cleanURL: function (url) {
   2036 
   2037                     var startsWithDoubleSlash = (url.indexOf('//') === 0);
   2038                     var startsWithSlash = (url.indexOf('/') === 0);
   2039 
   2040                     var queryKeys = Object.getOwnPropertyNames(CP_Customizer.wpApi.previewer.query());
   2041                     queryKeys = _.unique(queryKeys.concat([
   2042                         'customize_theme',
   2043                         'customize_changeset_uuid',
   2044                         'customize_messenger_channel',
   2045                         'customize_autosaved'
   2046                     ]));
   2047 
   2048                     url = CP_Customizer.utils.removeUrlQueryStrings(url, queryKeys);
   2049 
   2050                     // clean url
   2051                     url = CP_Customizer.utils.phpTrim(url, '/').trim() || "#";
   2052 
   2053                     // add // or / depending on how url received
   2054                     if (startsWithDoubleSlash) {
   2055                         url = '//' + url;
   2056                     } else {
   2057                         if (startsWithSlash) {
   2058                             url = '/' + url;
   2059                         }
   2060                     }
   2061 
   2062                     return url;
   2063                 },
   2064 
   2065                 fixWronglyWrappedTextNodes: function ($node) {
   2066                     $($node).find('div').each(function () {
   2067                         var hasOnlyTextInside = Array.from(this).map(function (item) {
   2068                             return ([8, 3].indexOf(item.nodeType) !== -1)
   2069                         }).reduce(function (a, b) {
   2070                             return a && b
   2071                         }, true);
   2072 
   2073                         if (hasOnlyTextInside) {
   2074                             if (this.innerHTML.trim().length) {
   2075                                 this.outerHTML = this.innerHTML + '<br/>';
   2076                             } else {
   2077                                 $(this).remove();
   2078                             }
   2079                         }
   2080                     });
   2081                 },
   2082 
   2083                 markNode: function ($node, prefix) {
   2084 
   2085                     CP_Customizer.preview.pauseObserver();
   2086                     prefix = prefix || 'new_cp_node_';
   2087 
   2088                     $($node).find("*").addBack().each(function () {
   2089                         $(this).attr('data-cpid', _.uniqueId(prefix));
   2090                     });
   2091 
   2092                     CP_Customizer.preview.restartObserver();
   2093                 },
   2094 
   2095                 insertNode: function ($node, $parent, index) {
   2096 
   2097                     CP_Customizer.preview.silentCall(function () {
   2098                         index = (index !== undefined) ? index : $parent.children().length;
   2099                         jQuery($node).insertAt(index, $parent);
   2100 
   2101                         this.decorateElements($node);
   2102                         this.markNode($node);
   2103 
   2104                         root.CP_Customizer.updateState();
   2105 
   2106                         $parent.removeAttr('data-preview-empty');
   2107 
   2108                         CP_Customizer.hooks.doAction('after_node_insert', $node);
   2109                     });
   2110                 },
   2111 
   2112                 replaceNode: function ($node, $newNode) {
   2113 
   2114                     CP_Customizer.preview.silentCall(function () {
   2115                         jQuery($node).replaceWith($newNode);
   2116 
   2117                         this.decorateElements($newNode);
   2118                         this.markNode($newNode);
   2119 
   2120                         root.CP_Customizer.updateState();
   2121 
   2122                     });
   2123                 },
   2124 
   2125                 hideNode: function ($node) {
   2126                     $node.attr('data-reiki-hidden', 'true');
   2127 
   2128                     var $parent = $node.parent();
   2129                     if ($parent.children(':visible').length === 0) {
   2130                         $parent.attr('data-preview-empty', 1);
   2131                     } else {
   2132                         $parent.removeAttr('data-preview-empty');
   2133                     }
   2134                 },
   2135 
   2136                 showNode: function ($node) {
   2137                     $node.removeAttr('data-reiki-hidden');
   2138 
   2139                     var $parent = $node.parent();
   2140                     if ($parent.children(':visible').length === 0) {
   2141                         $parent.attr('data-preview-empty', 1);
   2142                     } else {
   2143                         $parent.removeAttr('data-preview-empty');
   2144                     }
   2145                 },
   2146 
   2147                 isNodeVisible: function ($node) {
   2148                     return !($node.is('[data-reiki-hidden]'));
   2149                 },
   2150 
   2151                 removeNode: function ($node, skipUpdate) {
   2152                     CP_Customizer.preview.pauseObserver();
   2153                     var $parent = $node.parent();
   2154                     $node.remove();
   2155 
   2156                     if (!skipUpdate) {
   2157                         root.CP_Customizer.updateState();
   2158                     }
   2159 
   2160                     if ($parent.children().length === 0) {
   2161                         $parent.attr('data-preview-empty', 1);
   2162                     } else {
   2163                         $parent.removeAttr('data-preview-empty');
   2164                     }
   2165 
   2166                     _.delay(function () {
   2167                         root.CP_Customizer.overlays.hideMovableOverlays();
   2168                         var addOverlay = root.CP_Customizer.overlays.addOverlay();
   2169                         root.CP_Customizer.overlays.updateOverlay(addOverlay, addOverlay.data().node, false, true);
   2170                     }, 10);
   2171 
   2172                     CP_Customizer.preview.restartObserver();
   2173                 },
   2174 
   2175 
   2176                 insertContentSection: function (newRow, index) {
   2177                     index = _.isNumber(index) ? index : undefined;
   2178 
   2179                     if (_.isUndefined(index) && this.getRootNode().children('[data-id][data-label]').length) {
   2180                         index = this.getRootNode().children('[data-id][data-label]').last().index() + 1;
   2181                     }
   2182 
   2183                     this.insertNode(newRow, this.getRootNode(), index);
   2184                 	//this.decorateSectionsForGutenberg(newRow);
   2185                     this.decorateElements(newRow);
   2186 
   2187 
   2188                     function colorize(row) {
   2189                         var hasColor = (tinycolor(row.css('background-color')).getAlpha() !== 0);
   2190 
   2191                         if (!hasColor && !row.is('[data-bg="transparent"]')) {
   2192                             var prevSection = row.prev('[data-id][data-label]');
   2193 
   2194                             if (!prevSection.length) {
   2195                                 row.css('background-color', '#ffffff');
   2196                                 return;
   2197                             }
   2198 
   2199                             var isPrevTransparent = (tinycolor(prevSection.css('background-color')).getAlpha() === 0);
   2200                             var isPrevWhite = (tinycolor(prevSection.css('background-color')).toHex().toUpperCase() === "FFFFFF" || tinycolor(prevSection.css('background-color')).toHex().toUpperCase() === "FFF");
   2201 
   2202                             if (isPrevTransparent || isPrevWhite) {
   2203                                 row.css('background-color', '#F5FAFD');
   2204                             } else {
   2205                                 row.css('background-color', '#ffffff');
   2206                             }
   2207                         }
   2208                     }
   2209 
   2210                     colorize(newRow);
   2211 
   2212 
   2213                     CP_Customizer.renderNodeShortcodes(newRow);
   2214                     // CP_Customizer.hooks.doAction('after_node_insert', newRow);
   2215                     this.jQuery('html, body').animate({
   2216                         'scrollTop': newRow.offset().top
   2217                     });
   2218 
   2219                     var exports = CP_Customizer.getSectionExports(newRow.attr('data-export-id'));
   2220                     if (exports.afterInsert && _.isFunction(exports.afterInsert)) {
   2221                         CP_Customizer.one(CP_Customizer.events.STATE_UPDATED, function () {
   2222                             exports.afterInsert(newRow);
   2223                         });
   2224                     }
   2225 
   2226                     CP_Customizer.updateState();
   2227 
   2228                 },
   2229 
   2230                 editContainerData: function () {
   2231                     var item = $(this),
   2232                         fields = [],
   2233                         elements = item.find('[data-content-code-editable],[data-theme-href],[data-theme],[data-theme-mdi]');
   2234 
   2235 
   2236                     item.blur();
   2237 
   2238                     if (CP_Customizer.hooks.applyFilters('custom_container_data_handle', false, item)) {
   2239                         CP_Customizer.hooks.doAction('custom_container_data_handle', item);
   2240                         CP_Customizer.preview.blur();
   2241                         return;
   2242                     }
   2243 
   2244                     if (!elements.length) {
   2245                         elements = item.filter('.mdi');
   2246                     }
   2247 
   2248                     CP_Customizer.overlays.updateOverlay(CP_Customizer.overlays.hoverOverlay(), item);
   2249 
   2250                     if (item.is('[data-content-code-editable]') || item.is('[data-bg="image"]')) {
   2251                         elements = elements.add(item);
   2252                     }
   2253 
   2254                     elements = elements.filter(function (index, elem) {
   2255                         var result = true;
   2256                         elem = $(elem);
   2257 
   2258                         for (var i = 0; i < CP_Customizer.__containerDataFilters.length; i++) {
   2259                             var filter = CP_Customizer.__containerDataFilters[i];
   2260                             if (false === filter.call(elem, elem)) {
   2261                                 result = false;
   2262                                 break;
   2263                             }
   2264                         }
   2265                         return result;
   2266 
   2267                     });
   2268 
   2269                     elements.each(function (index, elem) {
   2270                         var result = false,
   2271                             setter = false,
   2272                             $elem = $(this);
   2273 
   2274                         for (var selector in CP_Customizer.__containerDataHandlers) {
   2275                             if ($elem.is(selector)) {
   2276                                 result = CP_Customizer.__containerDataHandlers[selector].getter.call($elem, $elem);
   2277                                 setter = CP_Customizer.__containerDataHandlers[selector].setter;
   2278                                 break;
   2279                             }
   2280                         }
   2281 
   2282                         result = root.CP_Customizer.hooks.applyFilters('container_data_element', result, $elem);
   2283                         if (result !== false) {
   2284                             if (!_.isArray(result)) {
   2285                                 result = [result];
   2286                             }
   2287 
   2288                             for (var i = 0; i < result.length; i++) {
   2289                                 result[i].id = 'item_no_' + index + '_' + i;
   2290                                 result[i].setter = setter;
   2291                                 result[i].node = $elem;
   2292                             }
   2293 
   2294                             fields = fields.concat(result);
   2295                         }
   2296 
   2297                     });
   2298 
   2299                     var content = '';
   2300                     for (var i = 0; i < fields.length; i++) {
   2301                         var field = fields[i],
   2302                             type = field.type || 'text';
   2303 
   2304                         var $fieldContent = $(CP_Customizer.jsTPL[type] ? CP_Customizer.jsTPL[type](field) : '');
   2305 
   2306                         if (field.classes) {
   2307                             $fieldContent.addClass(field.classes);
   2308                         }
   2309 
   2310                         if (field.ready && _.isFunction(field.ready)) {
   2311                             field.ready($fieldContent);
   2312                         }
   2313 
   2314                         $fieldContent.addClass(type);
   2315 
   2316                         content += $('<div />').append($fieldContent).html();
   2317                     }
   2318 
   2319                     var popupContainer = $('#cp-container-editor');
   2320 
   2321 
   2322                     function setContent() {
   2323                         for (var i = 0; i < fields.length; i++) {
   2324                             var field = fields[i],
   2325                                 value = {},
   2326                                 node = field.node
   2327                             if (field.getValue) {
   2328                                 value = field.getValue($('[id="' + field.id + '"]'));
   2329                             } else {
   2330                                 var _values = $('[id^="' + field.id + '"]').filter('input,textarea,select').map(function (index, elem) {
   2331                                     return {
   2332                                         key: $(this).attr('id').replace(field.id + "__", ''),
   2333                                         value: $(this).is('[type=checkbox]') ? this.checked : $(this).val()
   2334                                     };
   2335                                 }).toArray();
   2336 
   2337                                 _(_values).each(function (v) {
   2338                                     value[v.key] = v.value;
   2339                                 });
   2340 
   2341                                 if (_values.length === 1 && value.hasOwnProperty(field.id)) {
   2342                                     value = value[field.id];
   2343                                 }
   2344                             }
   2345 
   2346                             if (field.setter) {
   2347                                 field.setter.call(node, node, value, field.type, field);
   2348                                 root.CP_Customizer.hooks.doAction('container_data_element_setter', node, value, field);
   2349                             }
   2350                         }
   2351 
   2352                         if (node.is('[data-theme]')) {
   2353                             CP_Customizer.preview.jQuery(node).data('was-changed', true);
   2354                         }
   2355 
   2356 
   2357                         if (node.closest('[data-theme]').length) {
   2358                             CP_Customizer.preview.jQuery(node.closest('[data-theme]')).data('was-changed', true);
   2359                         }
   2360 
   2361 
   2362                         CP_Customizer.closePopUps();
   2363                         CP_Customizer.updateState();
   2364                     }
   2365 
   2366 
   2367                     setContent = CP_Customizer.preview.addSilentExecution(setContent);
   2368 
   2369                     popupContainer.find('[id="cp-item-ok"]').off().click(setContent);
   2370 
   2371                     popupContainer.find('[id="cp-item-cancel"]').off().click(function () {
   2372                         CP_Customizer.closePopUps();
   2373                     });
   2374 
   2375                     popupContainer.find('#cp-items').html(content);
   2376 
   2377                     CP_Customizer.popUp(root.CP_Customizer.translateCompanionString('Manage Content'), "cp-container-editor", {
   2378                         class: "data-edit-popup"
   2379                     });
   2380 
   2381                     CP_Customizer.preview.blur(true);
   2382 
   2383                 },
   2384 
   2385                 __dataContainers: ['[data-container-editable]', '[data-type=group]'],
   2386 
   2387                 addDataContainerSelector: function (selector) {
   2388                     this.__dataContainers.push(selector);
   2389                 },
   2390 
   2391                 registerContainerDataHandler: function (selector, handler) {
   2392                     CP_Customizer.preview.addDataContainerSelector(selector);
   2393                     var context = {
   2394                         selector: selector,
   2395                         handler: handler
   2396                     };
   2397 
   2398                     CP_Customizer.hooks.addFilter('custom_container_data_handle', function (value, $item) {
   2399                         if ($item.is(this.selector)) {
   2400                             value = true;
   2401                         }
   2402                         return value;
   2403 
   2404                     }.bind(context));
   2405 
   2406                     CP_Customizer.hooks.addAction('custom_container_data_handle', function ($item) {
   2407                         if ($item.is(this.selector)) {
   2408                             this.handler($item);
   2409                         }
   2410                     }.bind(context));
   2411                 },
   2412 
   2413 
   2414                 getContainersSelector: function (addSelectors) {
   2415                     var result = _.clone(this.__dataContainers);
   2416 
   2417                     if (_.isArray(addSelectors)) {
   2418                         result = result.concat(addSelectors);
   2419                     } else {
   2420                         if (_.isString(addSelectors)) {
   2421                             result.push(addSelectors);
   2422                         }
   2423                     }
   2424 
   2425                     return result.join(',');
   2426                 },
   2427 
   2428 
   2429                 addContentBinds: function () {
   2430                     var $ = this.jQuery(),
   2431                         document = this.frame().document,
   2432                         window = this.frame();
   2433 
   2434                     $(document).on('mouseover.hoveroverlay', this.getContainersSelector('[data-widgets-area],[data-bg="image"]'), _.debounce(function () {
   2435                    		if (this.hasAttribute("data-non-editable")) return false;
   2436                         var node = $(this);
   2437                         var hoverOverlay = root.CP_Customizer.overlays.hoverOverlay();
   2438 
   2439                         if (node.closest('[data-type=group]').length) {
   2440                             node = $(this).closest('[data-type=group]');
   2441                         }
   2442 
   2443                         if (node.closest('[data-content-shortcode]').length) {
   2444                             node = node.closest('[data-content-shortcode]');
   2445                         }
   2446 
   2447                         root.CP_Customizer.overlays.assignNode(hoverOverlay, node, true);
   2448                         hoverOverlay.show();
   2449 
   2450                         var structureAllowsRemoving = (node.parents('[data-type=row]').length || node.parents('[data-type=column]').length)/* && node.siblings().length*/;
   2451                         var isFixed = (node.is('[data-fixed]') || node.parents('[data-fixed]').length);
   2452 
   2453                         isFixed = CP_Customizer.hooks.applyFilters('is_fixed_element', isFixed, node);
   2454 
   2455                         if (structureAllowsRemoving && !isFixed && node.is(root.CP_Customizer.CONTENT_ELEMENTS)) {
   2456                             hoverOverlay.find('.remove').show();
   2457                         } else {
   2458                             hoverOverlay.find('.remove').hide();
   2459                         }
   2460                     }, 1));
   2461 
   2462 
   2463                     $(document).on('mouseover.hoveroverlay', '[data-content-editable], .page-content i.mdi, body [data-content-item-container="true"]', _.debounce(function () {
   2464 						if (this.hasAttribute("data-non-editable")) return false;
   2465                         var node = $(this);
   2466 
   2467                         if (node.parent().is('[data-content-item-container="true"]')) {
   2468                             return;
   2469                         }
   2470 
   2471                         var hoverOverlay = root.CP_Customizer.overlays.hoverOverlay();
   2472 
   2473                         if (node.closest('[data-type=group]').length) {
   2474                             node = $(this).closest('[data-type=group]');
   2475                         }
   2476 
   2477                         root.CP_Customizer.overlays.assignNode(hoverOverlay, node);
   2478                         hoverOverlay.show();
   2479 
   2480                         if (CP_Customizer.isShortcodeContent(node)) {
   2481                             hoverOverlay.find('.remove').hide();
   2482 
   2483                             if (!CP_Customizer.isOnCanvasMod(node)) {
   2484                                 hoverOverlay.hide();
   2485                             }
   2486                         } else {
   2487                             var inRow = node.parents('[data-type=row]').length || node.parents('[data-type=column]').length;
   2488                             if (inRow && !node.is('[data-fixed]') && !node.closest('[data-fixed]').length) {
   2489                                 hoverOverlay.find('.remove').show();
   2490                             } else {
   2491                                 hoverOverlay.find('.remove').hide();
   2492                             }
   2493                         }
   2494 
   2495 
   2496                     }, 1));
   2497 
   2498                     $(document).on('mouseover.hoveroverlay', '.page-content [data-content-shortcode]', function () {
   2499 
   2500                         if (CP_Customizer.isShortcodeEditable($(this))) {
   2501                             var overlay = root.CP_Customizer.overlays.hoverOverlay();
   2502                             root.CP_Customizer.overlays.assignNode(overlay, $(this));
   2503                             overlay.show();
   2504                         }
   2505                     });
   2506 
   2507 
   2508                     $(document).on('mouseover', root.CP_Customizer.preview.getPageContainerSelector() + ' > div', function () {
   2509                         root.CP_Customizer.trigger('content.section.hovered', [$(this)]);
   2510                     });
   2511 
   2512 
   2513                     $(document).on('mouseover', '[data-type="richtext"]', function () {
   2514                         var hoverOverlay = root.CP_Customizer.overlays.hoverOverlay();
   2515                         root.CP_Customizer.overlays.assignNode(hoverOverlay, $(this), true);
   2516 
   2517                     });
   2518 
   2519 
   2520                     $(document).on('mouseover.addoverlay', '.page-content [data-type="row"] > div, [data-theme] [data-type="row"] > div, .page-content [data-type="column"]', function () {
   2521 
   2522                         if ($(this).closest("[data-type=\"row\"]").is('[data-fixed]')) {
   2523                             return;
   2524                         }
   2525 
   2526                         if ($(this).find('[data-type=column]').length) {
   2527                             return;
   2528                         }
   2529 
   2530                         if ($(this).closest('[data-content-shortcode]').length) {
   2531                             return;
   2532                         }
   2533 
   2534                         var addOverlay = root.CP_Customizer.overlays.addOverlay();
   2535                         root.CP_Customizer.overlays.assignNode(addOverlay, $(this));
   2536                         addOverlay.show();
   2537                     });
   2538 
   2539 
   2540                     $(document).on('mouseover.rowitemoverlay', '.page-content [data-type="row"] > div, [data-theme] [data-type="row"] > div, .page-content [data-type="row"] > div, [data-theme] [data-type="row"] > div * ', function () {
   2541                             var node = $(this);
   2542 
   2543                             if (!node.parent().is('[data-type="row"]')) {
   2544                                 var parents = node.parentsUntil('[data-type="row"]');
   2545                                 node = parents.last();
   2546                             }
   2547 
   2548                             if (CP_Customizer.isShortcodeContent(node)) {
   2549                                 return;
   2550                             }
   2551 
   2552 
   2553                             var itemOverlay = root.CP_Customizer.overlays.rowItemHoverOverlay();
   2554                             root.CP_Customizer.overlays.assignNode(itemOverlay, node);
   2555                             itemOverlay.show();
   2556                         }
   2557                     );
   2558 
   2559                     $(window).on('scroll', root.CP_Customizer.overlays.updateAllOverlays);
   2560                     $(window).on('resize', _(root.CP_Customizer.overlays.updateAllOverlays).debounce(50));
   2561 
   2562                     $(document).on('click', this.getContainersSelector(), root.CP_Customizer.preview.editContainerData);
   2563 
   2564                     $(document).on('click', 'body [data-content-editable]', function () {
   2565                         $(this).focus();
   2566                     });
   2567 
   2568                     $(document).on('click', 'img[data-content-editable], [data-bg="image"]', function () {
   2569 
   2570 
   2571                         var self = $(this),
   2572                             type = "image",
   2573                             data = {};
   2574 
   2575                         if (self.is(CP_Customizer.preview.getContainersSelector())) {
   2576                             return;
   2577                         }
   2578 
   2579                         var section = CP_Customizer.preview.getNodeSection(self);
   2580                         var sectionExports = CP_Customizer.getSectionExports(section);
   2581 
   2582                         var flexible = _.isUndefined(sectionExports.maintainCropPropotion) ? true : sectionExports.maintainCropPropotion;
   2583 
   2584                         if (self.is('[data-size-flexible=false]')) {
   2585                             flexible = false;
   2586                         }
   2587 
   2588                         if (self.attr('data-size')) {
   2589                             var size = self.attr('data-size').split('x');
   2590                             type = "cropable";
   2591                             data = {
   2592                                 width: size[0],
   2593                                 height: size[1] ? size[1] : size[0],
   2594                                 flexible: flexible
   2595                             };
   2596                         } else {
   2597                             data = {
   2598                                 width: self.width(),
   2599                                 height: self.height(),
   2600                                 flexible: true
   2601                             };
   2602                         }
   2603 
   2604                         root.CP_Customizer.openMediaBrowser(type, setterCB, data);
   2605 
   2606                         function setterCB(src) {
   2607                             if (!src) {
   2608                                 return;
   2609                             }
   2610                             if (self.is('img')) {
   2611                                 self.attr('src', src[0].url);
   2612 
   2613                                 // remove attributes added by other plugins like JetPack
   2614                                 self.removeAttr('srcset');
   2615                                 self.removeAttr('src-orig');
   2616                                 self.removeAttr('width');
   2617                                 self.removeAttr('height');
   2618 
   2619                             } else {
   2620                                 self.css('background-image', 'url(' + src[0].url + ')');
   2621                             }
   2622 
   2623                             root.CP_Customizer.markSave();
   2624                         }
   2625                     });
   2626 
   2627                     $(document).on('click', 'i.mdi', function () {
   2628                         if (CP_Customizer.hooks.applyFilters('can_edit_icon', true, $(this))) {
   2629                             CP_Customizer.preview.editContainerData.apply(this);
   2630                         }
   2631                     });
   2632 
   2633                     var cachedValue = "";
   2634                     $(document).on('mousedown', '.page-content [data-content-editable]', function (event) {
   2635                         cachedValue = $(this).text();
   2636                     });
   2637 
   2638 
   2639                     $(document).on('mouseup', '.page-content [data-content-editable]', function () {
   2640                         if ($(this).text() !== cachedValue) {
   2641                             root.CP_Customizer.markSave();
   2642                             cachedValue = $(this).text();
   2643                         } else {
   2644                             cachedValue = "";
   2645                         }
   2646                     });
   2647 
   2648                     //Check for IE ('Trident')
   2649                     var contentEditableInputEvent = /Trident/.test(navigator.userAgent) ? 'textinput' : 'input';
   2650 
   2651 
   2652                     $(document).on(contentEditableInputEvent, 'body [data-content-editable]', function () {
   2653                         if ($(this).is('[data-theme]')) {
   2654                             $(this).data('was-changed', true);
   2655                             return;
   2656                         }
   2657 
   2658                         root.CP_Customizer.overlays.updateOverlay(root.CP_Customizer.overlays.hoverOverlay(), $(this), false, true);
   2659                         root.CP_Customizer.markSave();
   2660                     });
   2661 
   2662 
   2663                     $(document).on('blur', 'body [data-theme]', function () {
   2664                         if ($(this).data('was-changed')) {
   2665                             root.CP_Customizer.markSave();
   2666                         }
   2667                     });
   2668 
   2669                     var elementsSpecificSelector = CP_Customizer.TEXT_ELEMENTS.split(',').map(function (item) {
   2670                         var result = CP_Customizer.preview.getPageContainerSelector() + ' ' + item;
   2671 
   2672                         result += ", [data-theme] " + item;
   2673                         return result;
   2674                     });
   2675 
   2676                     elementsSpecificSelector.push('[data-theme]');
   2677 
   2678                     elementsSpecificSelector = elementsSpecificSelector.join(',');
   2679 
   2680                     var elementsOnFocusLeave = _.debounce(function () {
   2681                         var $this = $(this);
   2682                         root.CP_Customizer.preview.markNode($this);
   2683 
   2684                         if ($this.is(root.CP_Customizer.CONTENT_ELEMENTS) && $this.html().trim().length === 0) {
   2685                             $this.attr('data-preview-empty', 1);
   2686                         }
   2687                     }, 10);
   2688 
   2689                     $(document).on('blur focusout', elementsSpecificSelector, elementsOnFocusLeave);
   2690 
   2691                     $(document).on('focus', elementsSpecificSelector, function (event) {
   2692                         var $this = $(this);
   2693                         $this.removeAttr('data-preview-empty');
   2694 
   2695                         if ($this.is('.mdi')) {
   2696                             event.preventDefault();
   2697                             event.stopPropagation();
   2698                             return false;
   2699                         }
   2700                     });
   2701 
   2702 
   2703                     $(document).on('keydown.cp', '[contenteditable=true]', function (event) {
   2704 
   2705                         var editedNode = this;
   2706 
   2707                         _.delay(function () {
   2708                             root.CP_Customizer.overlays.updateOverlay(root.CP_Customizer.overlays.hoverOverlay(), $(editedNode), false, true);
   2709                             $(editedNode).removeAttr('data-preview-empty');
   2710                         }, 20);
   2711 
   2712                     });
   2713 
   2714                     $(document).on('keypress.cp', '[contenteditable=true]', function (event) {
   2715 
   2716                         if (event.which !== 13)
   2717                             return true;
   2718 
   2719                         var document = CP_Customizer.preview.frame().document;
   2720 
   2721                         var docFragment = document.createDocumentFragment();
   2722                         //add a new line
   2723                         var newEle = document.createTextNode('\n');
   2724                         docFragment.appendChild(newEle);
   2725                         //add the br, or p, or something else
   2726                         newEle = document.createElement('br');
   2727                         docFragment.appendChild(newEle);
   2728 
   2729                         var caretPosition = root.CP_Customizer.preview.getSelectionTextInfo(this);
   2730 
   2731                         //make the br replace selection
   2732                         var range = window.getSelection().getRangeAt(0);
   2733                         range.deleteContents();
   2734                         range.insertNode(docFragment);
   2735                         //create a new range
   2736                         range = document.createRange();
   2737                         range.setStartAfter(newEle);
   2738                         range.collapse(true);
   2739                         //make the cursor there
   2740                         var sel = window.getSelection();
   2741                         sel.removeAllRanges();
   2742                         sel.addRange(range);
   2743 
   2744                         event.preventDefault();
   2745 
   2746                         $(this).trim();
   2747 
   2748                         root.CP_Customizer.overlays.updateOverlay(root.CP_Customizer.overlays.hoverOverlay(), $(this), false, true);
   2749 
   2750                         return false;
   2751 
   2752                     });
   2753 
   2754                     $(document).on('blur.cpmarksave', '[contenteditable=true]', _.debounce(function (event) {
   2755 
   2756                         if (!$(this).data('cpFocused')) {
   2757                             return;
   2758                         }
   2759 
   2760                         $(this).data('cpFocused', false);
   2761 
   2762                         root.CP_Customizer.preview.markNode($(this));
   2763                         root.CP_Customizer.markSave();
   2764                     }, 800));
   2765 
   2766                     $(window).bind('keydown', function (event) {
   2767                         if (event.ctrlKey || event.metaKey) {
   2768                             var key = String.fromCharCode(event.which).toLowerCase();
   2769                             if (key === "s") {
   2770                                 event.preventDefault();
   2771                                 event.stopPropagation();
   2772                                 root.CP_Customizer.save();
   2773                             }
   2774                         }
   2775                     });
   2776 
   2777 
   2778                 },
   2779                 // http://stackoverflow.com/questions/1125292/how-to-move-cursor-to-end-of-contenteditable-entity
   2780                 placeCursorAtEnd: function (contentEditableElement) {
   2781                     try {
   2782                         var range, selection,
   2783                             document = this.frame().document,
   2784                             window = this.frame();
   2785                         if (document.createRange) //Firefox, Chrome, Opera, Safari, IE 9+
   2786                         {
   2787                             range = document.createRange(); //Create a range (a range is a like the selection but invisible)
   2788                             range.selectNodeContents(contentEditableElement); //Select the entire contents of the element with the range
   2789                             range.collapse(false); //collapse the range to the end point. false means collapse to end rather than the start
   2790                             selection = window.getSelection(); //get the selection object (allows you to change selection)
   2791                             selection.removeAllRanges(); //remove any selections already made
   2792                             selection.addRange(range); //make the range you have just created the visible selection
   2793                         } else if (document.selection) //IE 8 and lower
   2794                         {
   2795                             range = document.body.createTextRange(); //Create a range (a range is a like the selection but invisible)
   2796                             range.moveToElementText(contentEditableElement); //Select the entire contents of the element with the range
   2797                             range.collapse(false); //collapse the range to the end point. false means collapse to end rather than the start
   2798                             range.select(); //Select the range (make it the visible selection
   2799                         }
   2800                     } catch (e) {
   2801 
   2802                     }
   2803                 },
   2804 
   2805 
   2806                 decorateMods: function ($container) {
   2807 
   2808                     // decorate default mods
   2809                     CP_Customizer.preview.pauseObserver();
   2810                     $container = $container ? this.jQuery($container) : this.find('body');
   2811                     var defaultMods = root.CP_Customizer.preview.getThemeMods($container);
   2812                     var preview = this;
   2813                     defaultMods.each(function () {
   2814                         var $el = $(this);
   2815                         if ($el.is('[data-theme]')) {
   2816                             preview.markNode($el);
   2817                             $el.find('[data-type="row"] > div').each(preview.enableSortable);
   2818                         }
   2819                     });
   2820 
   2821                     if (root.CP_Customizer.options().mods) {
   2822                         for (var selector in root.CP_Customizer.options().mods) {
   2823                             var $el = this.find(selector);
   2824                             var modData = root.CP_Customizer.options().mods[selector];
   2825                             if (modData.type) {
   2826                                 $el.attr(modData.type, modData.mod);
   2827 
   2828                                 if (modData.type === "data-theme") {
   2829                                     preview.markNode($el);
   2830                                     $el.find('[data-type="row"] > div').each(this.enableSortable);
   2831                                 }
   2832                             }
   2833 
   2834                             if (modData.atts) {
   2835                                 for (var attr in modData.atts) {
   2836                                     $el.attr('data-theme-' + attr, modData.atts[attr]);
   2837                                 }
   2838                             }
   2839 
   2840                         }
   2841                     }
   2842 
   2843                     CP_Customizer.preview.restartObserver();
   2844                 },
   2845 
   2846                 //scan siblings and parent siblings until a comment node is found
   2847                 getGutenbergBlockCommentStart:function (node)
   2848                 {
   2849                     if (!node || (node && node.tagName == "body")) return false;
   2850                     if (node.nodeType == Node.COMMENT_NODE) return node;
   2851 
   2852                     var previousSibling = node.previousSibling;
   2853                     var maxDepth = 10;
   2854                     while (previousSibling && 
   2855                         previousSibling.nodeType != Node.COMMENT_NODE &&
   2856                         maxDepth-- > 0)
   2857                     {
   2858                         previousSibling = previousSibling.previousSibling;
   2859                     }
   2860 
   2861                     if (!previousSibling || previousSibling.nodeType != Node.COMMENT_NODE) 
   2862                         previousSibling = this.getGutenbergBlockCommentStart(node.parentNode);
   2863                     
   2864                     if (previousSibling.nodeType == Node.COMMENT_NODE)
   2865                     return previousSibling;
   2866                     
   2867                     return false;
   2868                 },
   2869 
   2870                 getGutenbergBlockCommentEnd:function (node)
   2871                 {
   2872                     if (!node || (node && node.tagName == "body")) return false;
   2873                     if (node.nodeType == Node.COMMENT_NODE) return node;
   2874 
   2875                     var nextSibling = node.nextSibling;
   2876                     var maxDepth = 10;
   2877                     while (nextSibling && 
   2878                         nextSibling.nodeType != Node.COMMENT_NODE &&
   2879                         maxDepth-- > 0)
   2880                     {
   2881                         nextSibling = nextSibling.nextSibling;
   2882                     }
   2883 
   2884                     if (!nextSibling || nextSibling.nodeType != Node.COMMENT_NODE) 
   2885                         nextSibling =  this.getGutenbergBlockCommentEnd(node.parentNode);
   2886                     
   2887                     if (nextSibling.nodeType == Node.COMMENT_NODE)
   2888                     return nextSibling;
   2889                     
   2890                     return false;
   2891                 },
   2892 
   2893 	            disableGutenbergBlocks: function (contentEditableElements)
   2894 	            {
   2895                     var self = this;
   2896                     console.log(self);
   2897                     var dataIdCounter = 1;
   2898 	                contentEditableElements.each(function (i, node) {
   2899 
   2900 	                    //add data-non-editable also for node children for gutenberg figure > img case    
   2901 	                    function setNonEditableNodes(node, parent)
   2902 	                    {
   2903 	                        function setNode(node, parent)
   2904 	                        {
   2905 	                            $(node).removeAttr("data-content-editable data-container-editable data-content-code-editable contenteditable srcset sizes data-category data-label data-export-id");
   2906                                 if (parent === true) 
   2907                                 {
   2908                                     $(node).attr("data-non-editable", true);
   2909                                 }
   2910 	                        }
   2911 	                        
   2912 
   2913 	                        setNode(node, parent);
   2914 	                        for (var i = 0; i < node.childNodes.length; i++) {
   2915 	                            var child = node.childNodes[i];
   2916 	                            setNonEditableNodes(child);
   2917 	                             //delete srcset andsizes attributes so that Gutenberg does not say invalid content
   2918 	                             setNode(node);
   2919 	                          }
   2920 	                    }
   2921 	                    
   2922 
   2923 	                    
   2924 	                    //check previous sibling nodes until reaching comment node to skip eventual text nodes
   2925 	                    function nextNonTextNode(node)
   2926 	                    {
   2927 	                        var nextSibling = node;
   2928 	                        var maxDepth = 10;
   2929 	                        while (nextSibling && 
   2930 	                            (nextSibling.nodeType == Node.COMMENT_NODE ||
   2931 	                            nextSibling.nodeType == Node.TEXT_NODE) &&
   2932 	                            maxDepth-- > 0)
   2933 	                        {
   2934 	                            nextSibling = nextSibling.nextSibling;
   2935 	                        }
   2936 
   2937 	                        return nextSibling;
   2938 	                    }
   2939 
   2940 	                    var commentNode = self.getGutenbergBlockCommentStart(node);
   2941 	                    var sectionNode;
   2942 	                    
   2943 	                    if ((commentNode && commentNode.nodeType == Node.COMMENT_NODE) && //check if section has wp:comment
   2944 	                    commentNode.textContent.indexOf("wp:") != -1 && //check if gutenberg block
   2945                         commentNode.textContent.indexOf("wp:extendstudio/materialis") == -1 && //check if not materialis block
   2946                         commentNode.textContent.indexOf("wp:extendstudio/mesmerize") == -1) //check if not mesmerize block
   2947 	                    {
   2948 	                        //set gutenberg block as non editable
   2949 	                        sectionNode = nextNonTextNode(commentNode);
   2950 	                        setNonEditableNodes(sectionNode, true);
   2951 	                    }
   2952 	                });                
   2953 	            },
   2954 	            
   2955                 decorateElements: function ($container) {
   2956 
   2957 
   2958                     CP_Customizer.preview.pauseObserver();
   2959 
   2960                     var $ = root.CP_Customizer.preview.jQuery(),
   2961                         self = this;
   2962 
   2963                     var elementsContainers = root.CP_Customizer.hooks.applyFilters('decorable_elements_containers', [root.CP_Customizer.preview.getPageContainerSelector(), '[data-dynamic-mod-container]']);
   2964                     $container = $container ? $($container) : root.CP_Customizer.preview.find(elementsContainers.join(','));
   2965 
   2966 
   2967                     $(function () {
   2968                         var $toDecorate = $("");
   2969                         $toDecorate = $toDecorate.add($container);
   2970                         // $toDecorate = $toDecorate.add($('[data-theme]'));
   2971                         CP_Customizer.overlays.addFixedOverlays($toDecorate);
   2972                     });
   2973 
   2974 
   2975                     $container.find('a').unbind('click').click(function (event) {
   2976                         event.preventDefault();
   2977                         event.stopImmediatePropagation();
   2978                         event.stopPropagation();
   2979 
   2980                         if ($(this).is('[data-container-editable]') || $(this).is('[data-type=group]')) {
   2981                             self.editContainerData.apply(this);
   2982                         }
   2983 
   2984                         return false;
   2985                     });
   2986                     var elements = $container.find(root.CP_Customizer.CONTENT_ELEMENTS).filter(function () {
   2987                         return root.CP_Customizer.preview.data().maintainable;
   2988                     });
   2989 
   2990                     if ($container.is(root.CP_Customizer.CONTENT_ELEMENTS)) {
   2991                         if (elements.length) {
   2992                             elements.add($container);
   2993                         } else {
   2994                             elements = $container;
   2995                         }
   2996                     }
   2997 
   2998 
   2999                     elements = elements.filter(function (item) {
   3000                         if ($(this).closest('[data-content-shortcode]').length) {
   3001                             return false;
   3002                         }
   3003                         return true;
   3004                     });
   3005                     elements = elements.add(root.CP_Customizer.preview.getThemeMods($container).filter(root.CP_Customizer.CONTENT_ELEMENTS));
   3006                     elements.filter('a').each(function () {
   3007                         var $el = $(this);
   3008 
   3009                         if ($el.closest(root.CP_Customizer.preview.getPageContainerSelector()).length) {
   3010                             $el.attr('data-container-editable', true);
   3011                         }
   3012 
   3013                         if ($el.is('[data-theme]')) {
   3014                             $el.attr('data-container-editable', true);
   3015                         }
   3016 
   3017                     });
   3018                     elements.filter('ul').attr('data-container-editable', true);
   3019                     elements = elements.filter(function (item) {
   3020                         if (this.tagName === "SPAN" && $(this).parents(CP_Customizer.TEXT_ELEMENTS).length) {
   3021                             return false;
   3022                         }
   3023 
   3024                         if ($(this).parents(root.CP_Customizer.preview.getContainersSelector()).length) {
   3025                             $(this).attr('data-content-code-editable', true);
   3026                             return false;
   3027                         }
   3028 
   3029                         if ($(this).is(root.CP_Customizer.preview.getContainersSelector())) {
   3030                             $(this).attr('data-content-code-editable', true);
   3031                             return false;
   3032                         }
   3033 
   3034                         return true;
   3035                     });
   3036 
   3037                     elements.not('i.mdi,a').attr('data-content-editable', true);
   3038                     elements.not('i.mdi,hr,a').attr('contenteditable', true);
   3039 
   3040                     elements.filter('i.mdi').each(function () {
   3041                         if ($(this).parent().is(root.CP_Customizer.CONTENT_ELEMENTS)) {
   3042                             return;
   3043                         }
   3044 
   3045                         $(this).attr('data-content-editable', true);
   3046                         $(this).attr('contenteditable', true);
   3047                     });
   3048 
   3049                     var contentEditableElements = $container.find('[contenteditable="true"]');
   3050 
   3051                     if ($container.is('[contentededitable=true]')) {
   3052                         contentEditableElements.add($container);
   3053                     }
   3054 
   3055                     contentEditableElements = contentEditableElements.add(root.CP_Customizer.preview.getThemeMods($container).filter('[contenteditable="true"]'));
   3056 
   3057 
   3058                     var handlePasteEvent = function (e) {
   3059                         var $ = CP_Customizer.preview.jQuery();
   3060 
   3061                         var text = '';
   3062                         var that = $(this);
   3063                         var document = CP_Customizer.preview.frame().document;
   3064 
   3065                         e.preventDefault();
   3066                         e.stopPropagation();
   3067 
   3068                         if (e.clipboardData) {
   3069                             text = e.clipboardData.getData('text/plain');
   3070                         } else if (window.clipboardData) {
   3071                             text = window.clipboardData.getData('Text');
   3072                         } else if (e.originalEvent.clipboardData) {
   3073                             text = $('<div></div>').text(e.originalEvent.clipboardData.getData('text'));
   3074                         }
   3075 
   3076                         var textContainer = $('<div/>').append(text);
   3077 
   3078                         CP_Customizer.preview.fixWronglyWrappedTextNodes(textContainer);
   3079 
   3080                         text = textContainer[0].innerHTML.replace(/\r\n/g, '<br/>').replace(/\r/g, '<br/>').replace(/\n/g, '<br/>');
   3081 
   3082                         if (document.queryCommandSupported('insertText')) {
   3083                             document.execCommand('insertHTML', false, text);
   3084                             return false;
   3085                         }
   3086                         else { // IE > 7
   3087                             that.find('*').each(function () {
   3088                                 $(this).addClass('within');
   3089                             });
   3090 
   3091                             setTimeout(function () {
   3092                                 // nochmal alle durchlaufen
   3093                                 that.find('*').each(function () {
   3094                                     // wenn das element keine klasse 'within' hat, dann unwrap
   3095                                     // http://api.jquery.com/unwrap/
   3096                                     $(this).not('.within').contents().unwrap();
   3097                                 });
   3098                                 root.CP_Customizer.preview.markNode(that);
   3099                             }, 1);
   3100                         }
   3101                         root.CP_Customizer.markSave();
   3102                     };
   3103 
   3104                     contentEditableElements.filter('*').each(function () {
   3105                         if (!CP_Customizer.IS_PRO) {
   3106                             this.addEventListener('paste', handlePasteEvent);
   3107                         }
   3108                     });
   3109 
   3110                     $container.find('[data-type="row"] > div, [data-type=column]').each(this.enableSortable);
   3111 
   3112                     if ($container.is('[data-type="row"] > div, [data-type=column]')) {
   3113                         this.enableSortable.call($container);
   3114                     }
   3115 
   3116                     if ($container.closest('.ui-sortable').length) {
   3117                         try {
   3118                             $container.closest('.ui-sortable').sortable('refresh');
   3119                             $container.closest('.ui-sortable').sortable('disable');
   3120                         } catch (e) {
   3121 
   3122                         }
   3123                     }
   3124 
   3125                	    this.disableGutenbergBlocks($container.find('[contenteditable="true"], [data-content-code-editable="true"], [class^=wp-]'));
   3126                     root.CP_Customizer.trigger(root.CP_Customizer.events.ELEMENT_DECORATED, [$container]);
   3127                     CP_Customizer.preview.restartObserver();
   3128    		         },
   3129 
   3130 	            decorateSectionsForGutenberg: function(sections){
   3131 	                 var sections = sections ? sections : CP_Customizer.preview.getSections();
   3132 
   3133 	                 //adds gutenberg block html comment
   3134 	                sections.each(function (i, node) {
   3135 	                    //skip decorate if node already has comment
   3136 	                    if (node.previousSibling && 
   3137 	                        node.previousSibling.nodeType == Node.COMMENT_NODE &&
   3138 	                        node.previousSibling.textContent.indexOf(" wp:extendstudio/materialis") != -1) 
   3139 	                    return;
   3140 
   3141 	                    var commentOpen = document.createComment(" wp:extendstudio/materialis ");
   3142 	                    var commentClose = document.createComment(" /wp:extendstudio/materialis ");
   3143 	                    node.before(commentOpen);
   3144 	                    node.after(commentClose);
   3145 	                 });
   3146                 },
   3147 
   3148                 enableSortable: function () {
   3149                     var $ = CP_Customizer.preview.jQuery();
   3150                     var $this = $(this);
   3151 
   3152                     if ($this.find('[data-type=column]').length) {
   3153                         return;
   3154                     }
   3155 
   3156                     if ($this.parent().is('[data-content-shortcode]')) {
   3157                         return;
   3158                     }
   3159 
   3160 
   3161                     if ($this.children().length === 0) {
   3162                         if ($this.is(root.CP_Customizer.CONTENT_ELEMENTS) && $this.html().trim().length === 0) {
   3163                             $this.attr('data-preview-empty', 1);
   3164                         }
   3165                     }
   3166 
   3167                     $this.sortable({
   3168                         axis: "y",
   3169                         start: function (event, ui) {
   3170                             ui.helper.css({
   3171                                 'display': 'block',
   3172                             });
   3173                         },
   3174                         stop: function (evt, ui) {
   3175                             $this.sortable('disable');
   3176                             $('.node-hover-overlay[is-dragging=true]').removeAttr('is-dragging');
   3177                             $(ui.item).data('reikidragging', false);
   3178                             ui.item.removeAttr("style");//button drag left:0px fix
   3179 
   3180                             function refreshOverlay() {
   3181                                 root.CP_Customizer.overlays.assignNode(root.CP_Customizer.overlays.hoverOverlay(), $(ui.item));
   3182                                 root.CP_Customizer.overlays.updateOverlay(root.CP_Customizer.overlays.hoverOverlay(), $(ui.item));
   3183                             }
   3184 
   3185                             ui.item.css('display', '');
   3186                             ui.item.css('transition', '');
   3187                             setTimeout(refreshOverlay, 10);
   3188                             $('[contenteditable]').attr('contenteditable', true);
   3189                             root.CP_Customizer.isSorting = false;
   3190                             root.CP_Customizer.updateState();
   3191                         },
   3192                         deactivate: function (evt, ui) {
   3193                             $('.node-hover-overlay[is-dragging=true]').removeAttr('is-dragging');
   3194                         },
   3195                         cursorAt: {
   3196                             left: 0,
   3197                             top: 0
   3198                         }
   3199 
   3200                     });
   3201                     $this.sortable('disable');
   3202                 },
   3203 
   3204                 showTextElementCUI: function (node) {
   3205                     CP_Customizer.preview.pauseObserver();
   3206 
   3207                     $(node).off('paste.cp_customizer').on('paste.cp_customizer', function (event) {
   3208                         var clipboardData = null;
   3209                         var mimeType = "";
   3210                         var window = CP_Customizer.preview.frame();
   3211                         var document = window.document;
   3212 
   3213 
   3214                         event.preventDefault();
   3215                         // event.stopPropagation();
   3216                         // event.stopImmediatePropagation();
   3217 
   3218                         if (event.clipboardData) {
   3219                             clipboardData = event.clipboardData;
   3220                             mimeType = 'text/plain';
   3221                         } else if (window.clipboardData) {
   3222                             clipboardData = window.clipboardData;
   3223                             mimeType = 'Text';
   3224                         } else if (event.originalEvent.clipboardData) {
   3225                             clipboardData = event.originalEvent.clipboardData;
   3226                             mimeType = 'text';
   3227                         }
   3228 
   3229                         var text = clipboardData.getData(mimeType);
   3230                         text = CP_Customizer.utils.wpautop(text.replace(/\n\s*\n/g, '\n'));
   3231                         var textContainer = $('<div/>').append(text);
   3232 
   3233                         CP_Customizer.preview.fixWronglyWrappedTextNodes(textContainer);
   3234 
   3235                         text = textContainer[0].innerHTML;
   3236 
   3237                         if (document.queryCommandSupported('insertText')) {
   3238                             document.execCommand('insertHTML', false, text);
   3239                             return false;
   3240                         }
   3241                         else { // IE > 7
   3242                             that.find('*').each(function () {
   3243                                 $(this).addClass('within');
   3244                             });
   3245 
   3246                             setTimeout(function () {
   3247                                 // nochmal alle durchlaufen
   3248                                 that.find('*').each(function () {
   3249                                     // wenn das element keine klasse 'within' hat, dann unwrap
   3250                                     // http://api.jquery.com/unwrap/
   3251                                     $(this).not('.within').contents().unwrap();
   3252                                 });
   3253                             }, 1);
   3254                         }
   3255 
   3256                     });
   3257 
   3258                     node = $(node)[0];
   3259 
   3260                     var cui = this.getTextElementCUI();
   3261 
   3262                     if (!cui) {
   3263                         CP_Customizer.logError('TinyMCE Editor not found');
   3264                         return;
   3265                     }
   3266 
   3267                     cui.hidden = false;
   3268                     cui.target = node;
   3269                     cui.bodyElement = node;
   3270                     cui.show();
   3271                     cui.fire('focusin');
   3272                     cui.undoManager.clear();
   3273                     cui.theme.panel.getEl().classList.add('cp-tinymce-inline');
   3274                     cui.theme.panel.getEl().style.display = "block";
   3275 
   3276 
   3277                     var docWidth = Math.min(CP_Customizer.preview.frame().innerWidth, CP_Customizer.preview.jQuery('html').width()),
   3278                         cuiRect = cui.theme.panel.getEl().getBoundingClientRect(),
   3279                         nodeWidth = CP_Customizer.preview.jQuery(node).width(),
   3280                         nodeOffsetLeft = CP_Customizer.preview.jQuery(node).offset().left;
   3281 
   3282 
   3283                     var newLeft = (nodeOffsetLeft - (cuiRect.width - nodeWidth) * 0.5);
   3284 
   3285                     if (newLeft < 0) {
   3286                         newLeft = nodeOffsetLeft;
   3287                     }
   3288 
   3289                     if (newLeft + cuiRect.width > docWidth) {
   3290                         newLeft = nodeOffsetLeft + nodeWidth - cuiRect.width;
   3291 
   3292                     }
   3293                     cui.theme.panel.getEl().style.left = newLeft + 'px';
   3294 
   3295                 },
   3296 
   3297                 hideTextElementCUI: function () {
   3298                     var cui = this.getTextElementCUI();
   3299 
   3300                     if (!cui) {
   3301                         CP_Customizer.logError('TinyMCE Editor not found');
   3302                         return;
   3303                     }
   3304 
   3305 
   3306                     if (cui.theme && cui.theme.panel) {
   3307                         cui.theme.panel.getEl().style.display = "none";
   3308                     }
   3309 
   3310                     if (cui.getBody()) {
   3311                         cui.fire('focusout');
   3312                         // cui.hide();
   3313                     }
   3314                 },
   3315 
   3316                 getFonts: function () {
   3317 
   3318                     var defaultFonts = {
   3319                         "Arial": "arial,helvetica,sans-serif",
   3320                         "Arial Black": "arial black,sans-serif",
   3321                         "Andale Mono": "andale mono,monospace",
   3322                         // "Book Antiqua": "book antiqua,palatino,serif",
   3323                         // "Comic Sans MS": "comic sans ms,sans-serif",
   3324                         // "Courier New": "courier new,courier,monospace",
   3325                         // "Georgia": "georgia,palatino,serif",
   3326                         // "Helvetica": "helvetica,arial,sans-serif",
   3327                         // "Impact": "impact,sans-serif",
   3328                         // "Symbol": "symbol",
   3329                         "Tahoma": "tahoma,arial,helvetica,sans-serif",
   3330                         "Terminal": "terminal,monaco,monospace",
   3331                         "Times New Roman": "times new roman,times,serif",
   3332                         // "Trebuchet MS": "trebuchet ms,geneva,sans-serif",
   3333                         "Verdana": "verdana,geneva,sans-serif"
   3334                         // "Webdings": "webdings",
   3335                         // "Wingdings": "wingdings,zapf dingbats"
   3336                     };
   3337 
   3338                     var googleFonts = {};
   3339 
   3340                     if (root.CP_Customizer.pluginOptions.data.fonts) {
   3341                         for (var font in root.CP_Customizer.pluginOptions.data.fonts) {
   3342                             googleFonts[font] = font + ",arial,helvetica,sans-serif";
   3343                         }
   3344                     }
   3345 
   3346                     googleFonts = root.CP_Customizer.hooks.applyFilters('tinymce_google_fonts', googleFonts);
   3347 
   3348                     var fonts = _.extend(googleFonts, defaultFonts);
   3349 
   3350                     fonts.toTinyMCEFormat = function () {
   3351                         var result = [];
   3352                         for (var font in this) {
   3353                             if (_.isString(this[font])) {
   3354                                 result.push(font + "=" + this[font]);
   3355                             }
   3356                         }
   3357 
   3358                         return result.join(';');
   3359                     };
   3360 
   3361                     return fonts;
   3362                 },
   3363 
   3364                 getNodeFont: function (node) {
   3365                     var $node = this.jQuery(node)
   3366                     var font = $node.css('font-family');
   3367                     var fontArray = font.replace(/[\'\"]/g, '').replace(/\s/g, '').toLowerCase().split(',');
   3368                     var fonts = this.getFonts();
   3369 
   3370                     if (_.isObject(fonts)) {
   3371                         for (var name in fonts) {
   3372                             if (_.isString(fonts[name])) {
   3373                                 var _fontArray = fonts[name].replace(/[\'\"]/g, '').replace(/\s/g, '').toLowerCase().split(',');
   3374                                 if (_.difference(_fontArray, fontArray).length === 0) {
   3375                                     return name;
   3376                                 }
   3377                             }
   3378                         }
   3379                     }
   3380 
   3381                     return font;
   3382                 },
   3383 
   3384                 getFontWeights: function (font) {
   3385                     var fonts = CP_Customizer.utils.getValue('web_fonts');
   3386 
   3387                     if (fonts) {
   3388                         for (var i = 0; i < fonts.length; i++) {
   3389                             var _font = fonts[i];
   3390                             if (_font.family.toLowerCase() === font.toLowerCase()) {
   3391                                 var weights = [];
   3392                                 for (var w = 0; w < _font.weights.length; w++) {
   3393                                     var weight = _font.weights[w];
   3394                                     if (weight === 'normal' || weight === 'regular') {
   3395                                         weight = '400';
   3396                                     } else {
   3397                                         try {
   3398                                             weight = parseInt(weight).toString();
   3399                                         } catch (e) {
   3400 
   3401                                         }
   3402                                     }
   3403 
   3404                                     if (weights.indexOf(weight) === -1) {
   3405                                         weights.push(weight);
   3406                                     }
   3407                                 }
   3408                                 return weights;
   3409                             }
   3410                         }
   3411                     }
   3412 
   3413                     return ['100', '200', '300', '400', '500', '600', '700', '800', '900'];
   3414                 },
   3415 
   3416                 getTextElementCUI: function () {
   3417                     var editorID = 'cp-tinymce-cui-editor';
   3418                     var editor = root.CP_Customizer.preview.frame().tinymce ? root.CP_Customizer.preview.frame().tinymce.get(editorID) : 'cp-editor-not-found';
   3419 
   3420                     if (editor === 'cp-editor-not-found') {
   3421                         return undefined;
   3422                     }
   3423 
   3424                     var self = this;
   3425                     if (!editor) {
   3426                         this.jQuery('body').after('<div id="' + editorID + '"></div>');
   3427                         var options = {
   3428                             "selector": "#" + editorID,
   3429                             inline: true,
   3430                             style_formats_merge: true,
   3431                             extended_valid_elements: 'span',
   3432                             "formats": {
   3433                                 alignment: {selector: 'p,h1,h2,h3,h4,h5,h6', styles: {textAlign: '%value'}},
   3434                                 fontweight: {inline: 'span', styles: {fontWeight: '%value'}},
   3435                                 fontsize: {inline: 'span', styles: {fontSize: '%value'}},
   3436                                 fontcolor: {inline: 'span', styles: {color: '%value'}},
   3437                                 italic: {inline: 'span', styles: {fontStyle: 'italic'}},
   3438 
   3439                             },
   3440                             "menubar": false,
   3441                             "theme": "modern",
   3442                             "skin": "lightgray",
   3443                             "toolbar": 'fontselect addwebfont font-weight font-size-popup | italic underline strikethrough superscript subscript alignment  font-color-popup | removeformat',
   3444                             "font_formats": this.getFonts().toTinyMCEFormat(),
   3445                             "paste_as_text": true,
   3446                             "forced_root_block": false,
   3447                             setup: function (ed) {
   3448                                 var bm;
   3449 
   3450                                 ed.addButton('font-weight', {
   3451                                     type: 'listbox',
   3452                                     text: root.CP_Customizer.translateCompanionString('Font Weight'),
   3453                                     icon: false,
   3454                                     onselect: function (e) {
   3455                                         ed.formatter.apply('fontweight', {value: this.value()});
   3456                                     },
   3457                                     values: [
   3458                                         {text: 'Thin (100)', value: '100'},
   3459                                         {text: 'Extra light (200)', value: '200'},
   3460                                         {text: 'Light (300)', value: '300'},
   3461                                         {text: 'Normal (400)', value: '400'},
   3462                                         {text: 'Medium (500)', value: '500'},
   3463                                         {text: 'Semi Bold (600)', value: '600'},
   3464                                         {text: 'Bold (700)', value: '700'},
   3465                                         {text: 'Extra Bold (800)', value: '800'},
   3466                                         {text: 'Black (900)', value: '900'}
   3467                                     ],
   3468                                     onPostRender: function () {
   3469 
   3470                                         // add font control separator//
   3471                                         var fontControl = ed.theme.panel.controlIdLookup['mceu_0'];
   3472                                         fontControl.on('showMenu', function (e) {
   3473                                             var items = this.menu.items();
   3474                                             for (var i in items) {
   3475                                                 var item = items[i];
   3476 
   3477                                                 if (!_.isFunction(item.text)) {
   3478                                                     continue;
   3479                                                 }
   3480 
   3481                                                 if (item.text().raw.toLowerCase() == 'arial') {
   3482                                                     item.$el.addClass('first-system-font');
   3483                                                 }
   3484                                             }
   3485                                         });
   3486 
   3487                                         var btn = this;
   3488                                         ed.on('NodeChange', _.debounce(function (e) {
   3489                                             var weight = jQuery(e.element || ed.selection.getNode()).css('font-weight');
   3490                                             if (weight === "bold") weight = "700";
   3491                                             if (weight === "normal") weight = "400";
   3492                                             btn.value(weight);
   3493                                         }, 10));
   3494 
   3495                                         btn.on('show', function (e) {
   3496                                             ed.theme.panel.getEl().style.display = "block";
   3497                                             e.control.$el.css({top: this.$el.offset().top + 34, left: this.$el.offset().left})
   3498                                         });
   3499 
   3500                                         btn.on('showMenu', function () {
   3501                                             var font = CP_Customizer.preview.getNodeFont(ed.selection.getNode());
   3502                                             var weights = CP_Customizer.preview.getFontWeights(font);
   3503                                             for (var i in btn.menu.items()) {
   3504                                                 var item = btn.menu.items()[i];
   3505 
   3506                                                 if (!_.isFunction(item.value)) {
   3507                                                     continue;
   3508                                                 }
   3509 
   3510                                                 if (weights.indexOf(item.value()) === -1) {
   3511                                                     item.$el.hide();
   3512                                                 } else {
   3513                                                     item.$el.show();
   3514                                                 }
   3515                                             }
   3516                                         });
   3517                                     }
   3518                                 });
   3519 
   3520 
   3521                                 ed.addButton('alignment', {
   3522                                     type: 'listbox',
   3523                                     text: root.CP_Customizer.translateCompanionString(''),
   3524                                     icon: true,
   3525                                     onselect: function (e) {
   3526                                         ed.formatter.apply('alignment', {value: this.value()});
   3527                                     },
   3528                                     values: [
   3529                                         {
   3530                                             icon: 'alignleft',
   3531                                             text: root.CP_Customizer.translateCompanionString(''),
   3532                                             value: 'left'
   3533                                         },
   3534                                         {
   3535                                             icon: 'aligncenter',
   3536                                             text: root.CP_Customizer.translateCompanionString(''),
   3537                                             value: 'center'
   3538                                         },
   3539                                         {
   3540                                             icon: 'alignright',
   3541                                             text: root.CP_Customizer.translateCompanionString(''),
   3542                                             value: 'right'
   3543                                         },
   3544                                         {
   3545                                             icon: 'alignjustify',
   3546                                             text: root.CP_Customizer.translateCompanionString(''),
   3547                                             value: 'justify'
   3548                                         }
   3549                                     ],
   3550                                     onPostRender: function () {
   3551                                         var btn = this;
   3552                                         ed.on('NodeChange', function (e) {
   3553                                             var textAlign = jQuery(ed.selection.getNode()).css('text-align');
   3554                                             btn.value(textAlign);
   3555                                             btn.icon('align' + textAlign);
   3556 
   3557                                             //Disable text alignment for header elements
   3558                                             if (jQuery(e.element).parents('.header-wrapper').length)
   3559                                             {
   3560                                                 btn.$el.hide();
   3561                                             } else
   3562                                             {
   3563                                                 btn.$el.show();
   3564                                             }
   3565                                         });
   3566 
   3567                                         btn.on('show', function (e) {
   3568                                             ed.theme.panel.getEl().style.display = "block";
   3569                                             e.control.$el.css({top: this.$el.offset().top + 34, left: this.$el.offset().left})
   3570                                             e.control.$el.eq(0).css('min-width', '10px');
   3571                                         });
   3572                                     }
   3573                                 });
   3574 
   3575                                 ed.addButton('addwebfont', {
   3576                                     type: 'button',
   3577                                     icon: 'insert',
   3578                                     tooltip: root.CP_Customizer.translateCompanionString("Add web font"),
   3579                                     onPostRender: function () {
   3580                                         this.on("click", function () {
   3581                                             top.wp.customize.control('web_fonts').focus()
   3582                                         });
   3583                                     }
   3584                                 });
   3585                                 ed.addButton('font-color-popup', {
   3586                                     type: "colorbutton",
   3587                                     icon: false,
   3588 
   3589 
   3590                                     onPostRender: function () {
   3591                                         var btn = this;
   3592 
   3593                                         self.jQuery(this.getEl()).spectrum({
   3594                                             showAlpha: true,
   3595 
   3596                                             preferredFormat: "rgb",
   3597                                             showInput: true,
   3598                                             show: function () {
   3599                                                 //console.log(this);
   3600 
   3601                                                 var colorPalette = CP_Customizer.hooks.applyFilters('spectrum_color_palette', []);
   3602 
   3603 
   3604                                                 var color = jQuery(ed.selection.getNode()).css('color');
   3605                                                 var spectrumEl = self.jQuery(btn.getEl());
   3606 
   3607                                                 var container = spectrumEl.spectrum("container");
   3608                                                 spectrumEl.spectrum("set", color);
   3609 
   3610                                                 spectrumEl.spectrum("option", "showPalette", colorPalette.length > 0);
   3611 
   3612                                                 if (colorPalette.length > 0) {
   3613 
   3614                                                     // group colors a 3 per row
   3615                                                     colorPalette = CP_Customizer.utils.arrayChunk(colorPalette, 3);
   3616 
   3617                                                     spectrumEl.spectrum("option", "palette", colorPalette);
   3618                                                 }
   3619 
   3620 
   3621                                                 var offTop = container.offset().top
   3622                                                 var scrollTop = self.frame().scrollY;
   3623 
   3624                                                 container.css({
   3625                                                     top: self.jQuery(btn.getEl()).offset().top - scrollTop + 30,
   3626                                                     "left": "auto",
   3627                                                     "right": CP_Customizer.preview.frame().innerWidth - jQuery(btn.getEl()).offset().left - 40
   3628                                                 });
   3629 
   3630                                                 self.jQuery(self.jQuery('body')[0].ownerDocument).scroll(function () {
   3631                                                     var offTop = container.offset().top
   3632                                                     var scrollTop = self.jQuery('body').scrollTop();
   3633 
   3634                                                     container.offset({
   3635                                                         top: self.jQuery(btn.getEl()).offset().top - scrollTop + 30
   3636                                                     });
   3637                                                 });
   3638 
   3639                                             },
   3640                                             change: function (color) {
   3641                                                 var col = color.toRgbString();
   3642                                                 btn.value(col);
   3643 
   3644                                                 ed.selection.moveToBookmark(bm);
   3645                                                 ed.formatter.apply('fontcolor', {value: col});
   3646                                             }
   3647                                         });
   3648 
   3649                                         btn.on("click", function () {
   3650                                             bm = ed.selection.getBookmark();
   3651                                         });
   3652 
   3653                                         ed.on('NodeChange', function (e) {
   3654                                             var color = jQuery(ed.selection.getNode()).css('color');
   3655                                             btn.color(color);
   3656                                             self.jQuery(btn.getEl()).spectrum("set", color);
   3657                                         });
   3658 
   3659                                         function onEditorBlur(e) {
   3660                                             self.jQuery(btn.getEl()).spectrum('hide');
   3661                                             CP_Customizer.preview.restartObserver();
   3662                                         }
   3663 
   3664                                         ed.on('blur', onEditorBlur);
   3665 
   3666 
   3667                                     }
   3668                                 });
   3669                                 ed.on('focus', function (e) {
   3670                                     // _.delay(function () {
   3671                                     //     var editorEL = e.target.theme.panel.getEl(),
   3672                                     //         node = e.target.bodyElement,
   3673                                     //         margin = ($(node).width() - $(editorEL).width()) / 2;
   3674                                     //
   3675                                     //     $(editorEL).css({
   3676                                     //         'margin-left': margin
   3677                                     //     });
   3678                                     // }, 0);
   3679                                 });
   3680 
   3681                                 updateOnEditorBlur = _.debounce(function (e) {
   3682                                     _.delay(function () {
   3683                                         var $node = $(e.target.bodyElement);
   3684                                         CP_Customizer.preview.markNode($node);
   3685 
   3686                                         if ($node.is('[data-theme]')) {
   3687                                             CP_Customizer.preview.jQuery($node).data('was-changed', true);
   3688                                         }
   3689                                         CP_Customizer.updateState();
   3690                                     }, 0);
   3691                                 }, 100);
   3692 
   3693                                 ed.on('blur', updateOnEditorBlur);
   3694 
   3695                             }
   3696                         };
   3697                         root.CP_Customizer.preview.frame().tinymce.init(options);
   3698                         editor = root.CP_Customizer.preview.frame().tinymce.get(editorID);
   3699 
   3700                     }
   3701 
   3702                     return editor;
   3703                 },
   3704 
   3705                 blur: function (overlayOnly) {
   3706                     var hoverOverlay = CP_Customizer.overlays.hoverOverlay();
   3707                     var hoveredNode = CP_Customizer.preview.jQuery(hoverOverlay.data().node);
   3708 
   3709                     // hoverOverlay.deactivateHeatZone();
   3710 
   3711                     var fakeNode = CP_Customizer.preview.jQuery("<p contenteditable='true' style='display: none;' />");
   3712 
   3713                     CP_Customizer.overlays.assignNode(hoverOverlay, fakeNode);
   3714 
   3715                     if (overlayOnly) {
   3716                         return;
   3717                     }
   3718 
   3719                     if (CP_Customizer.preview.getTextElementCUI()) {
   3720                         CP_Customizer.preview.getTextElementCUI().fire('blur');
   3721                     }
   3722 
   3723 
   3724                 }
   3725             },
   3726 
   3727             overlays: {
   3728 
   3729 
   3730                 addFixedOverlays: function ($startNode) {
   3731                     var $ = root.CP_Customizer.preview.jQuery();
   3732 
   3733                     if ($startNode.length > 1) {
   3734 
   3735                         var self = this;
   3736                         $startNode.each(function () {
   3737                             self.addFixedOverlays($(this));
   3738                         });
   3739                         return;
   3740 
   3741                     }
   3742                     $startNode = $startNode || $('body');
   3743 
   3744                     if ($startNode.closest('[data-type="row"]').length || $startNode.closest('[data-type="column"]').length) {
   3745                         return;
   3746                     }
   3747 
   3748                     root.CP_Customizer.trigger(root.CP_Customizer.events.ADD_FIXED_OVERLAYS, [$startNode]);
   3749 
   3750                 },
   3751 
   3752 
   3753                 __fixedOverlayOptions: {},
   3754                 registerFixedOverlayOptions: function (name, options) {
   3755 
   3756                     if (_.isObject(name)) {
   3757                         _.each(name, function (options, key) {
   3758                             CP_Customizer.overlays.registerFixedOverlayOptions(key, options);
   3759                         });
   3760                     } else {
   3761 
   3762                         if (!this.__fixedOverlayOptions.hasOwnProperty(name)) {
   3763                             this.__fixedOverlayOptions[name] = options;
   3764                         } else {
   3765                             // console.error("Overlay options name '" + name + "' already exists");
   3766                         }
   3767                     }
   3768 
   3769                 },
   3770 
   3771                 getOverlayOptionButton: getButtonElement,
   3772 
   3773                 addOptionsToFixedOverlay:
   3774                     function ($container, type, node, callback) {
   3775                         var typeOptions = this.__fixedOverlayOptions[type],
   3776                             $toAppend;
   3777 
   3778                         typeOptions = CP_Customizer.hooks.applyFilters('section_fixed_overlay_options', _.clone(typeOptions), type);
   3779 
   3780                         if (!typeOptions) {
   3781                             console.error('Undefined typeoptions', type, node);
   3782                             return;
   3783                         }
   3784 
   3785                         var jQuery = CP_Customizer.preview.jQuery();
   3786                         var _node = (typeOptions.nodeOverrider || _.identity)(node);
   3787                         for (var key in typeOptions) {
   3788                             var filteredOptions = CP_Customizer.hooks.applyFilters('section_fixed_overlay', typeOptions[key], key);
   3789                             if (typeOptions.hasOwnProperty(key)) {
   3790                                 switch (key) {
   3791                                     case 'title':
   3792                                         $toAppend = getTitleElement(filteredOptions, _node, type);
   3793                                         if ($toAppend) {
   3794                                             $container.append($toAppend);
   3795                                         }
   3796                                         break;
   3797                                     case 'items':
   3798                                         $toAppend = getItemsElements(filteredOptions, _node, type);
   3799                                         $container.append($toAppend);
   3800                                         break;
   3801                                     case 'node_binds':
   3802                                         var nodeBinds = filteredOptions;
   3803                                         jQuery.each(nodeBinds, function (bind, callbacks) {
   3804                                             if (bind === "hover") {
   3805                                                 _node.hover(
   3806                                                     function (event) {
   3807                                                         callbacks[0].bind(this)(event, jQuery(this).data().overlay);
   3808                                                     },
   3809                                                     function (event) {
   3810                                                         var isNodeRelated = jQuery(this).data().overlay.find("*").addBack().is(event.relatedTarget);
   3811                                                         if (isNodeRelated) {
   3812                                                             event.preventDefault();
   3813                                                             event.stopPropagation();
   3814                                                             return false;
   3815                                                         }
   3816 
   3817                                                         callbacks[1].bind(this)(event, jQuery(this).data().overlay);
   3818                                                     }
   3819                                                 );
   3820                                             } else {
   3821                                                 _node.bind(bind, callbacks);
   3822                                             }
   3823                                         });
   3824                                         break;
   3825                                     case 'toolbar_binds':
   3826                                         var toolbarBinds = typeOptions[key];
   3827                                         var overlay = jQuery(node).data().overlay;
   3828                                         jQuery.each(toolbarBinds, function (bind, callbacks) {
   3829                                             if (bind === "hover") {
   3830                                                 overlay.find('.overlay-toolbar').hover(
   3831                                                     function (event) {
   3832                                                         callbacks[0].bind(node)(event, overlay);
   3833                                                     },
   3834                                                     function (event) {
   3835                                                         callbacks[1].bind(node)(event, overlay);
   3836                                                     }
   3837                                                 );
   3838                                             } else {
   3839                                                 overlay.bind(bind, callbacks);
   3840                                             }
   3841                                         });
   3842                                         break;
   3843                                 }
   3844                             }
   3845                         }
   3846 
   3847                         if (callback) {
   3848                             callback(typeOptions);
   3849                         }
   3850                     }
   3851 
   3852                 ,
   3853 
   3854                 updateOverlay: function (overlay, node, cover, positionOnly) {
   3855                     var $ = root.CP_Customizer.preview.jQuery();
   3856                     node = $(node);
   3857                     updateControls = !positionOnly;
   3858 
   3859                     if (!node || !node.length) {
   3860                         return;
   3861                     }
   3862 
   3863 
   3864                     if (updateControls) {
   3865                         overlay.find('.pen-overlay').css({
   3866                             width: node.outerWidth(),
   3867                             height: node.outerHeight(),
   3868                             'pointer-events': 'all',
   3869                             'display': 'block'
   3870                         });
   3871 
   3872                         overlay.find('.add-element-bubble.visible').removeClass('visible');
   3873                         overlay.find('.add-element-bubble .expanded').removeClass('expanded');
   3874 
   3875                         if (node.outerHeight() < 30) {
   3876                             overlay.find('.pen-overlay').addClass('small');
   3877                         } else {
   3878                             overlay.find('.pen-overlay').removeClass('small');
   3879                         }
   3880 
   3881 
   3882                         if (node.parent().is('.ui-sortable') && node.siblings(root.CP_Customizer.CONTENT_ELEMENTS).length && node.closest(".page-content,[data-theme]").length) {
   3883                             overlay.find('.move').show();
   3884                         } else {
   3885                             overlay.find('.move').hide();
   3886                         }
   3887 
   3888 
   3889                         if (!node.is(':visible')) {
   3890                             overlay.hide();
   3891                         } else {
   3892                             overlay.show();
   3893                         }
   3894 
   3895                         overlay.find('.add').show();
   3896                         if (node.closest('[data-add-content]').length) {
   3897                             value = node.closest('[data-add-content]').attr('data-add-content');
   3898 
   3899                             if (value === "false") {
   3900                                 overlay.find('.add').hide();
   3901                             }
   3902                         }
   3903 
   3904 
   3905                         if (node.closest('[data-type="row"]').length && node.closest('[data-type="row"]').is('[data-custom-items]')) {
   3906                             overlay.find('.top-container').hide();
   3907                             overlay.find('[h-align-center]').hide();
   3908                         } else {
   3909                             overlay.find('.top-container').show();
   3910                             overlay.find('[h-align-center]').show();
   3911                         }
   3912 
   3913 
   3914                         if (overlay.is('.add-content-overlay')) {
   3915                             if (node.is('[data-type="column"]') && node.closest('[data-type=row]').length === 0) {
   3916                                 overlay.find('.remove').hide();
   3917                             } else {
   3918                                 if (node.closest('[data-type=row]').children().length > 1) {
   3919                                     overlay.find('.remove').show();
   3920                                 } else {
   3921                                     overlay.find('.remove').hide();
   3922                                 }
   3923                             }
   3924                         }
   3925 
   3926                         if (overlay.is('.node-hover-overlay')) {
   3927                             if (node.siblings().length === 0) {
   3928                                 overlay.find('.remove').hide();
   3929                             } else {
   3930                                 if (node.is(root.CP_Customizer.CONTENT_ELEMENTS)) {
   3931                                     overlay.find('.remove').show();
   3932                                 } else {
   3933                                     overlay.find('.remove').hide();
   3934                                 }
   3935                             }
   3936                         }
   3937 
   3938                         if (overlay.is('.item-hover-overlay')) {
   3939                             if (node.closest('[data-type=row]').children().length > 1) {
   3940                                 overlay.find('.remove').show();
   3941                             } else {
   3942                                 overlay.find('.remove').hide();
   3943                             }
   3944                         }
   3945 
   3946                     }
   3947 
   3948                     var bounds = node[0].getBoundingClientRect();
   3949                     var scrollTop = root.CP_Customizer.preview.frame().pageYOffset;
   3950                     var scrollLeft = root.CP_Customizer.preview.frame().pageXOffset;
   3951                     overlay.css({
   3952                         left: (parseInt(bounds.left) + scrollLeft) + "px",
   3953                         top: (parseInt(bounds.top) + scrollTop) + "px"
   3954                     });
   3955 
   3956                     overlay.css({
   3957                         width: node.outerWidth(),
   3958                         'position': 'absolute'
   3959                     });
   3960 
   3961                     if (!cover) {
   3962                         overlay.css({
   3963                             height: 'auto',
   3964                             'background-color': ''
   3965                         });
   3966                     }
   3967 
   3968                     overlay.children('.overlay-left, .overlay-right').css({
   3969                         height: node.outerHeight(),
   3970                         width: '0px'
   3971                     });
   3972                     overlay.children('.overlay-right').css({
   3973                         left: node.outerWidth() - 1,
   3974                         width: '0px'
   3975                     });
   3976                     overlay.children('.overlay-top, .overlay-bottom').css({
   3977                         height: '0px',
   3978                         width: node.outerWidth()
   3979                     });
   3980                     overlay.children('.overlay-bottom').css({
   3981                         top: node.outerHeight()
   3982                     });
   3983 
   3984                     overlay.children('[align-bottom]').each(function () {
   3985                         $(this).css({
   3986                             top: node.outerHeight() - 5
   3987                         });
   3988                     });
   3989 
   3990                     overlay.children('[align-top]').css({
   3991                         top: 0
   3992                     });
   3993 
   3994                     overlay.children('[h-align-center]').each(function () {
   3995                         $(this).css({
   3996                             left: (node.outerWidth() - $(this).outerWidth()) / 2
   3997                         });
   3998                     });
   3999 
   4000                 },
   4001 
   4002 
   4003                 updateAllOverlays: function (event) {
   4004                     var updateOnlySections = Array.from(arguments).length === 0;
   4005                     var update = function () {
   4006                         var $ = CP_Customizer.preview.jQuery();
   4007                         this.overlaysContainer.children().each(function () {
   4008                             var isSection = $(this).is('.section-overlay');
   4009 
   4010                             if (updateOnlySections && !isSection) {
   4011                                 return;
   4012                             }
   4013 
   4014                             var node = $(this).data('node');
   4015                             if (node) {
   4016 
   4017 
   4018                                 root.CP_Customizer.overlays.updateOverlay($(this), $(node), false, true);
   4019 
   4020                                 var isScrollEvent = event && event.type == 'scroll';
   4021 
   4022                                 if ($(this).is('.heatzone') && !isScrollEvent) {
   4023                                     $(this).removeClass('heatzone');
   4024                                 }
   4025                                 if (event === true) {
   4026                                     $(this).hide();
   4027                                 }
   4028                             }
   4029                         });
   4030                     }.bind({
   4031                         overlaysContainer: root.CP_Customizer.overlays.overlaysContainer()
   4032                     });
   4033 
   4034                     update();
   4035                     return true;
   4036                 },
   4037 
   4038                 overlaysContainer: function () {
   4039                     var overlaysContainer = CP_Customizer.preview.find('#cp-overlays');
   4040 
   4041                     if (!overlaysContainer.length) {
   4042                         overlaysContainer = CP_Customizer.preview.jQuery()('<div id="cp-overlays"></div>');
   4043                         CP_Customizer.preview.find('body').append(overlaysContainer);
   4044                     }
   4045 
   4046                     return overlaysContainer;
   4047                 },
   4048 
   4049                 hoverOverlay: function () {
   4050                     var $ = root.CP_Customizer.preview.jQuery();
   4051                     var hoverOverlay = $('[data-overlay="cp-hoveroverlay"]');
   4052 
   4053                     if (hoverOverlay.length) {
   4054                         return hoverOverlay;
   4055                     }
   4056 
   4057                     hoverOverlay = $('<div data-overlay="cp-hoveroverlay" class="node-hover-overlay"><div class="pen-overlay"><svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 0 20 20"><path d="M13.89 3.39l2.71 2.72c.46.46.42 1.24.03 1.64l-8.01 8.02-5.56 1.16 1.16-5.58s7.6-7.63 7.99-8.03c.39-.39 1.22-.39 1.68.07zm-2.73 2.79l-5.59 5.61 1.11 1.11 5.54-5.65zm-2.97 8.23l5.58-5.6-1.07-1.08-5.59 5.6z"></path></svg></div><span title="' + root.CP_Customizer.translateCompanionString("Move element") + '" class="move"></span><span title="' + root.CP_Customizer.translateCompanionString("Delete element") + '" class=" remove"></span><div class="overlay-top overlay-border"></div><div class="overlay-left overlay-border"></div><div class="overlay-right overlay-border"></div><div class="overlay-bottom overlay-border"></div></div>');
   4058 
   4059                     root.CP_Customizer.overlays.overlaysContainer().append(hoverOverlay);
   4060                     hoverOverlay.hide();
   4061 
   4062                     hoverOverlay.find('.remove').click(function () {
   4063                         root.CP_Customizer.preview.removeNode($(hoverOverlay.data('node')));
   4064                         hoverOverlay.hide();
   4065                     });
   4066 
   4067                     hoverOverlay.find('.pen-overlay').unbind('click').click(function (event) {
   4068                         var $node = $(hoverOverlay.data('node'));
   4069 
   4070                         if ($node.is('[data-focus-control]')) {
   4071                             var setting = wp.customize($node.attr('data-focus-control'));
   4072                             var control = setting ? setting.findControls()[0] : null;
   4073 
   4074                             if (control) {
   4075                                 control.focus();
   4076                                 if (control.container.closest('.customizer-right-section').length) {
   4077                                     var sidebarID = control.container.closest('.customizer-right-section').attr('id').replace('-popup', '');
   4078                                     jQuery('[data-sidebar-container="' + sidebarID + '"]').click();
   4079                                     // control.container.closest('.customizer-right-section').addClass('active');
   4080                                 }
   4081                             }
   4082 
   4083                             return;
   4084                         }
   4085 
   4086                         if ($node.is('[data-widgets-area]')) {
   4087                             root.wp.customize.section('sidebar-widgets-' + $node.attr('data-widgets-area')).focus();
   4088                             return;
   4089                         }
   4090 
   4091                         if ($node.is('hr')) {
   4092                             return;
   4093                         }
   4094 
   4095                         if ($node.is('[data-content-shortcode]')) {
   4096                             var shortcodeData = CP_Customizer.parseShortcode($node.attr('data-content-shortcode'));
   4097                             CP_Customizer.hooks.doAction('shortcode_edit', $node, shortcodeData);
   4098                             CP_Customizer.hooks.doAction('shortcode_edit_' + shortcodeData.tag, $node, shortcodeData);
   4099                             return;
   4100                         }
   4101 
   4102                         if (!$node.data('container-editable')) {
   4103                             $node.off();
   4104                             $(this).hide();
   4105                         }
   4106 
   4107                         if ($node.is('[data-content-item-container="true"]')) {
   4108                             $node = $node.children().eq(0);
   4109                         }
   4110 
   4111                         $node.click();
   4112                         $node.data('cpFocused', true);
   4113 
   4114                         if ($node.is(root.CP_Customizer.TEXT_ELEMENTS)) {
   4115                             $node.focus();
   4116 
   4117                             _.delay(function () {
   4118                                 root.CP_Customizer.preview.placeCursorAtEnd($node[0]);
   4119                             }, 5);
   4120 
   4121                             CP_Customizer.hooks.doAction('text_element_clicked', $node);
   4122 
   4123                             hoverOverlay.activateHeatZone();
   4124                         } else {
   4125                             CP_Customizer.hooks.doAction('element_clicked', $node);
   4126                         }
   4127 
   4128                     });
   4129 
   4130                     function findCenter($, el) {
   4131                         el = $(el);
   4132                         var o = el.offset();
   4133                         return {
   4134                             x: o.left + el.outerWidth() / 2,
   4135                             y: o.top + el.outerHeight() / 2
   4136                         };
   4137                     }
   4138 
   4139                     function triggerDrag(el, ev) {
   4140                         var target = el,
   4141                             $ = root.CP_Customizer.preview.jQuery(),
   4142                             frame = root.CP_Customizer.preview.frame();
   4143 
   4144                         var self = this,
   4145                             center = findCenter($, target),
   4146                             options = {},
   4147                             x = Math.floor(center.x),
   4148                             y = Math.floor(center.y),
   4149                             dx = options.dx || 0,
   4150                             dy = options.dy || 0;
   4151                         var coord = {
   4152                             clientX: x,
   4153                             clientY: y
   4154                         };
   4155 
   4156                         var type = "mousedown";
   4157 
   4158                         var e = $.extend({
   4159                             bubbles: true,
   4160                             cancelable: (type != "mousemove"),
   4161                             view: frame,
   4162                             detail: 0,
   4163                             screenX: 0,
   4164                             screenY: 0,
   4165                             clientX: 0,
   4166                             clientY: 0,
   4167                             ctrlKey: false,
   4168                             altKey: false,
   4169                             shiftKey: false,
   4170                             metaKey: false,
   4171                             button: 0,
   4172                             relatedTarget: el
   4173                         }, coord);
   4174 
   4175                         // var relatedTarget = $(el).parent().data('node');
   4176 
   4177                         var evt = document.createEvent("MouseEvents");
   4178                         evt.initMouseEvent(type, e.bubbles, e.cancelable, e.view, e.detail,
   4179                             e.screenX, e.screenY, ev.clientX, ev.clientY,
   4180                             e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
   4181                             e.button, null);
   4182 
   4183                         el.dispatchEvent(evt);
   4184                     }
   4185 
   4186 
   4187                     var moveHandlerCallback = function ($handle, event) {
   4188 
   4189                         if (event.which !== 1) {
   4190                             return;
   4191                         }
   4192 
   4193                         var overlay = $handle.closest('.node-hover-overlay');
   4194 
   4195                         var $node = $(hoverOverlay.data('node'));
   4196 
   4197                         if ($node.siblings().length === 0) {
   4198                             return;
   4199                         }
   4200 
   4201                         $node.blur();
   4202 
   4203                         if ($node.data('reikidragging')) {
   4204                             overlay.attr('is-dragging', false);
   4205                             $node.data('reikidragging', false);
   4206                             return;
   4207                         }
   4208 
   4209                         var $first = $node.parents('.ui-sortable').first();
   4210                         if ($first.data("ui-sortable")) {
   4211                             $first.sortable('enable');
   4212                         }
   4213 
   4214                         $node.data('reikidragging', true);
   4215                         overlay.attr('is-dragging', true);
   4216 
   4217                         $('[contenteditable="true"]').attr('contenteditable', false);
   4218                         $('[contenteditable="true"]').blur();
   4219                         triggerDrag($node[0], event);
   4220                         root.CP_Customizer.isSorting = true;
   4221 
   4222                         root.CP_Customizer.preview.hideTextElementCUI();
   4223                     };
   4224 
   4225 
   4226                     hoverOverlay.find('.move').off('mousedown.cp').on('mousedown.cp', function (event) {
   4227                         _(moveHandlerCallback).delay(50, $(this), event);
   4228                     });
   4229 
   4230 
   4231                     hoverOverlay.find('.move').off('mouseup.cp').on('mouseup.cp', function (event) {
   4232                         var overlay = $(this).closest('.node-hover-overlay');
   4233                         overlay.attr('is-dragging', false);
   4234                     });
   4235 
   4236                     hoverOverlay.activateHeatZone = function () {
   4237                         var $this = $(this);
   4238                         $this.addClass('heatzone');
   4239 
   4240                         var top = $this.find('.overlay-top'),
   4241                             left = $this.find('.overlay-left'),
   4242                             right = $this.find('.overlay-right'),
   4243                             bottom = $this.find('.overlay-bottom');
   4244 
   4245                         if (top.find('.zone').length === 0) {
   4246                             top.append('<div class="zone" />');
   4247                         }
   4248 
   4249                         if (left.find('.zone').length === 0) {
   4250                             left.append('<div class="zone" />');
   4251                         }
   4252 
   4253                         if (right.find('.zone').length === 0) {
   4254                             right.append('<div class="zone" />');
   4255                         }
   4256 
   4257                         if (bottom.find('.zone').length === 0) {
   4258                             bottom.append('<div class="zone" />');
   4259                         }
   4260 
   4261                         var node = $this.data('node');
   4262                         var $node = CP_Customizer.preview.jQuery(node);
   4263 
   4264                         var nodeRect = {
   4265                             top: $node.offset().top,
   4266                             bottom: $node.offset().top + node.offsetHeight,
   4267                             height: node.offsetHeight,
   4268                             left: node.getBoundingClientRect().left,
   4269                             right: node.getBoundingClientRect().left + node.offsetWidth,
   4270                             width: node.offsetWidth
   4271                         };
   4272 
   4273                         var docHeight = $(node).closest('body').height();
   4274                         var docWidth = Math.min(CP_Customizer.preview.frame().innerWidth, CP_Customizer.preview.jQuery('html').width());
   4275 
   4276 
   4277                         top.find('.zone').css({
   4278                                 height: nodeRect.top,
   4279                                 width: docWidth,
   4280                                 left: -1 * nodeRect.left
   4281                             }
   4282                         );
   4283 
   4284                         bottom.find('.zone').css({
   4285                                 height: docHeight - nodeRect.bottom,
   4286                                 width: docWidth,
   4287                                 left: -1 * nodeRect.left,
   4288                                 top: '-1px'
   4289                             }
   4290                         );
   4291 
   4292                         left.find('.zone').css({
   4293                                 height: nodeRect.height,
   4294                                 width: nodeRect.left
   4295                                 //top: -1 * nodeRect.top - nodeRect.height / 2
   4296                             }
   4297                         );
   4298 
   4299                         right.find('.zone').css({
   4300                                 height: nodeRect.height,
   4301                                 width: docWidth - nodeRect.right
   4302                                 // top: -1 * nodeRect.top - nodeRect.height / 2
   4303                             }
   4304                         );
   4305 
   4306                         hoverOverlay.off('click.zone').on('click.zone', '.zone', function (event) {
   4307                             hoverOverlay.removeClass('heatzone');
   4308 
   4309                             event.preventDefault();
   4310                             event.stopPropagation();
   4311 
   4312                             var x = event.clientX,
   4313                                 y = event.clientY,
   4314                                 elementMouseIsOver = CP_Customizer.preview.frame().document.elementFromPoint(x, y);
   4315 
   4316                             //
   4317                             hoverOverlay.addClass('heatzone');
   4318                             CP_Customizer.preview.blur();
   4319                             _.delay(function () {
   4320                                 hoverOverlay.removeClass('heatzone');
   4321                                 CP_Customizer.preview.jQuery(elementMouseIsOver).trigger('mouseover');
   4322                             }, 10);
   4323                             return false;
   4324                         });
   4325                     };
   4326 
   4327                     // hoverOverlay.deactivateHeatZone = function () {
   4328                     //     hoverOverlay.removeClass('heatzone');
   4329                     // };
   4330 
   4331                     return hoverOverlay;
   4332 
   4333                 },
   4334 
   4335                 rowItemHoverOverlay: function () {
   4336                     var $ = root.CP_Customizer.preview.jQuery();
   4337                     var itemHoverOverlay = $('[data-overlay="cp-item-hover-overlay"]');
   4338 
   4339                     if (itemHoverOverlay.length) {
   4340                         return itemHoverOverlay;
   4341                     }
   4342 
   4343                     itemHoverOverlay = $('<div data-overlay="cp-item-hover-overlay" class="item-hover-overlay"> <div h-align-right title="' + root.CP_Customizer.translateCompanionString("Delete item") + '" class="remove"></div> </div>');
   4344 
   4345                     root.CP_Customizer.overlays.overlaysContainer().append(itemHoverOverlay);
   4346 
   4347                     itemHoverOverlay.hide();
   4348 
   4349                     itemHoverOverlay.find('.remove').click(function () {
   4350                         var node = $(itemHoverOverlay.data('node'));
   4351                         root.CP_Customizer.preview.removeNode(node);
   4352                         root.CP_Customizer.hooks.doAction('section_list_item_refresh');
   4353                         itemHoverOverlay.hide();
   4354                     });
   4355 
   4356                     return itemHoverOverlay;
   4357                 },
   4358 
   4359 
   4360                 addOverlay: function () {
   4361 
   4362                     var $ = root.CP_Customizer.preview.jQuery();
   4363                     var addOverlay = $('[data-overlay="cp-addoverlay"]');
   4364 
   4365                     if (addOverlay.length) {
   4366                         return addOverlay;
   4367                     }
   4368 
   4369                     addOverlay = $('<div data-overlay="cp-addoverlay" class="add-content-overlay"><div class="buttons" align-bottom h-align-center><div class="add" title="' + root.CP_Customizer.translateCompanionString("Add element") + '">' + root.CP_Customizer.translateCompanionString("Add element") + '</div></div></div>');
   4370                     root.CP_Customizer.overlays.overlaysContainer().append(addOverlay);
   4371                     addOverlay.hide();
   4372 
   4373                     //addOverlay.find('.add').prepend('<div class="add-element-bubble"><div class="elements-container"></div><i class="element-bubble-close"></i></div>');
   4374                     // let's add the close button in a future update
   4375                     addOverlay.find('.add').prepend('<div class="add-element-bubble"><div class="elements-container"></div></div>');
   4376 
   4377 
   4378                     addOverlay.find('.add').click(function (event) {
   4379                         addOverlay.find('.add').find('.add-element-bubble').toggleClass('visible');
   4380                     });
   4381 
   4382                     root.CP_Customizer.content.addContentItemsTo(addOverlay.find('.elements-container'));
   4383 
   4384                     addOverlay.find('.elements-container').on('cp-insert-content-item', function (event, type, insertHandler) {
   4385                         event.preventDefault();
   4386                         var $node = $(addOverlay.data('node'));
   4387                         var index = $node.children().length;
   4388 
   4389                         insertHandler(type, $node, index, after);
   4390 
   4391                         function after($node) {
   4392                             root.CP_Customizer.preview.decorateElements($node);
   4393                             root.CP_Customizer.overlays.updateOverlay(addOverlay, $(addOverlay.data('node')));
   4394                             CP_Customizer.renderNodeShortcodes($node);
   4395                             // CP_Customizer.hooks.doAction('after_node_insert', $node);
   4396                         }
   4397                     });
   4398 
   4399                     return addOverlay;
   4400                 },
   4401 
   4402                 assignNode: function (overlay, node, cover) {
   4403                     var $ = root.CP_Customizer.preview.jQuery();
   4404                     if (overlay.attr('is-dragging') && overlay.attr('is-dragging') === "true") {
   4405                         return;
   4406                     }
   4407                     if ($(overlay.data('node')).is(node)) {
   4408                         return;
   4409                     } else {
   4410                         /*if (overlay.data('node') && overlay.data('node').ownerDocument.activeElement == overlay.data('node')) {
   4411                             debugger;
   4412                         $(overlay.data('node')).blur();
   4413                         }*/
   4414                     }
   4415 
   4416                     overlay.data('node', $(node)[0]);
   4417 
   4418                     function updateOverlay() {
   4419                         root.CP_Customizer.overlays.updateOverlay(overlay, $(node), cover);
   4420                     }
   4421 
   4422                     overlay.on('reiki.update_overlays', '*', function (event) {
   4423                         setTimeout(updateOverlay, 0);
   4424                     });
   4425 
   4426                     root.CP_Customizer.preview.hideTextElementCUI();
   4427                     updateOverlay();
   4428                 },
   4429 
   4430                 hideMovableOverlays: function () {
   4431                     CP_Customizer.overlays.addOverlay().hide();
   4432                     CP_Customizer.overlays.hoverOverlay().hide();
   4433                     CP_Customizer.overlays.rowItemHoverOverlay().hide()
   4434                 }
   4435 
   4436             }
   4437             ,
   4438 
   4439             content: {
   4440                 __registeredItems: {
   4441                     'link':
   4442                         {
   4443                             icon: 'mdi-link-variant',
   4444                             tooltip: translateCompanionString('link'),
   4445                             data:
   4446                             '<a class="link" data-cpid="new" data-container-editable="true" data-content-code-editable href="#">' + translateCompanionString('new link') + '</a>',
   4447                             'after': function ($item) {
   4448                                 $item.unbind('click').click(function (event) {
   4449                                     event.preventDefault();
   4450                                     event.stopImmediatePropagation();
   4451                                     event.stopPropagation();
   4452 
   4453                                     if ($(this).is('[data-container-editable]') || $(this).is('[data-type=group]')) {
   4454                                         CP_Customizer.preview.editContainerData.apply(this);
   4455                                     }
   4456 
   4457                                     return false;
   4458                                 });
   4459                             }
   4460                         }
   4461                     ,
   4462                     'button':
   4463                         {
   4464                             icon: 'mdi-open-in-new',
   4465                             tooltip: translateCompanionString('button'),
   4466                             data:
   4467                             '<a data-cpid="new" data-container-editable="true" data-content-code-editable class="button blue" href="#">' + translateCompanionString('new button') + '</a>',
   4468                             'after': function ($item) {
   4469                                 $item.unbind('click').click(function (event) {
   4470                                     event.preventDefault();
   4471                                     event.stopImmediatePropagation();
   4472                                     event.stopPropagation();
   4473 
   4474                                     if ($(this).is('[data-container-editable]') || $(this).is('[data-type=group]')) {
   4475                                         CP_Customizer.preview.editContainerData.apply(this);
   4476                                     }
   4477 
   4478                                     return false;
   4479                                 });
   4480                             }
   4481                         }
   4482                     ,
   4483                     'heading':
   4484                         {
   4485                             icon: 'mdi-format-header-pound larger',
   4486                             tooltip: translateCompanionString('heading'),
   4487                             items:
   4488                                 function () {
   4489                                     var result = {};
   4490                                     for (var i = 1; i <= 6; i++) {
   4491                                         result['h' + i] = {
   4492                                             label: "H" + i,
   4493                                             data: '<h' + i + '>' + translateCompanionString("Heading") + ' ' + i + '</h' + i + '>',
   4494                                             tooltip: translateCompanionString('Heading') + ' ' + i
   4495                                         };
   4496                                     }
   4497 
   4498                                     return result;
   4499                                 }
   4500                         }
   4501                     ,
   4502 
   4503                     'lead':
   4504                         {
   4505                             icon: 'mdi-format-align-left',
   4506                             tooltip: translateCompanionString('lead'),
   4507                             data:
   4508                                 '<p data-cpid="new" class="lead" data-content-editable="true" contenteditable="true">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>'
   4509                         }
   4510                     ,
   4511 
   4512                     'paragraph':
   4513                         {
   4514                             icon: 'mdi-format-paragraph larger',
   4515                             tooltip: translateCompanionString('paragraph'),
   4516                             data:
   4517                                 '<p data-cpid="new" data-content-editable="true" contenteditable="true">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>'
   4518                         }
   4519                     ,
   4520 
   4521                     'image':
   4522                         {
   4523                             icon: 'mdi-image-area big',
   4524                             tooltip: translateCompanionString('image'),
   4525                             data:
   4526                                 '<img data-cpid="new" class="custom-image" data-content-code-editable="true" data-content-editable="true" contenteditable="true" src="#"/>'
   4527                         }
   4528                     // ,
   4529 
   4530                     // 'icon':
   4531                     //     {
   4532                     //         icon: 'mdi-adjust',
   4533                     //         items:
   4534                     //             function () {
   4535                     //                 var result = {};
   4536                     //                 for (var i = 1; i <= 6; i++) {
   4537                     //                     result['mdi' + i] = {
   4538                     //                         icon: 'mdi-flag mdi' + i,
   4539                     //                         data: '<i class="mdi cp-icon mdi' + i + ' mdi-adjust"></i>',
   4540                     //                         tooltip: "Font Icon " + i
   4541                     //                     };
   4542                     //                 }
   4543                     //
   4544                     //                 return result;
   4545                     //             }
   4546                     //     }
   4547                     // ,
   4548                     // 'separator':
   4549                     //     {
   4550                     //         'icon':
   4551                     //             "mdi-adjust",
   4552                     //         data:
   4553                     //             '<div class="spacer" data-type="group"><span class="mdi before"></span><i data-content-code-editable="true" class="mdi mdi-adjust"></i><span class="mdi after"></span></div>'
   4554                     //     }
   4555                 },
   4556 
   4557                 registerItem: function (data) {
   4558 
   4559                     if (data) {
   4560                         for (var key in data) {
   4561                             if (data[key].contentElementSelector) {
   4562                                 CP_Customizer.addContentElementsSelectors(data[key].contentElementSelector);
   4563                             }
   4564                         }
   4565                     }
   4566 
   4567                     _.extend(this.__registeredItems, data);
   4568                 },
   4569 
   4570                 getItemData: function (type) {
   4571                     types = type.split('.');
   4572                     var start = this.__registeredItems;
   4573 
   4574                     for (var i = 0; i < types.length; i++) {
   4575                         var _type = types[i];
   4576 
   4577                         if (i + 1 < types.length) {
   4578                             var _items = start[_type].items;
   4579                             if (_(_items).isFunction()) {
   4580                                 _items = _items.call();
   4581 
   4582                             }
   4583                             start = _items;
   4584                         } else {
   4585                             return start[_type].data;
   4586                         }
   4587                     }
   4588                 },
   4589 
   4590                 getItemAfter: function (type) {
   4591                     types = type.split('.');
   4592                     var start = this.__registeredItems;
   4593 
   4594                     for (var i = 0; i < types.length; i++) {
   4595                         var _type = types[i];
   4596 
   4597                         if (i + 1 < types.length) {
   4598                             var _items = start[_type].items;
   4599                             if (_(_items).isFunction()) {
   4600                                 _items = _items.call();
   4601 
   4602                             }
   4603                             start = _items;
   4604                         } else {
   4605                             return start[_type].after;
   4606                         }
   4607                     }
   4608                 },
   4609 
   4610                 getContentItems: function (data, subitems, parentId) {
   4611                     data = data || this.__registeredItems;
   4612                     subitems = subitems || false;
   4613                     var self = this;
   4614                     var $result = $("<div />");
   4615                     $.each(data, function (id, option) {
   4616                         var title = option.toolip || option.tooltip || id; // || for old typo :D
   4617                         var idAttr = parentId ? parentId + "." + id : id;
   4618                         var _item = $('<i class="mdi ' + (option.icon || "") + '" title="' + title + '" data-' + (option.items ? "parent" : "content") + '-id="' + idAttr + '"></i>');
   4619 
   4620                         if (option.label) {
   4621                             _item.append('<span class="item-label">' + option.label + '</span>');
   4622                         }
   4623 
   4624                         if (option.items) {
   4625 
   4626                             var _items = option.items;
   4627 
   4628                             if (_(_items).isFunction()) {
   4629                                 _items = option.items.call();
   4630                             }
   4631 
   4632                             var subitemsContainer = $('<div class="subitems-container" />');
   4633                             subitemsContainer.append(self.getContentItems(_items, true, idAttr));
   4634                             _item.append(subitemsContainer);
   4635                         }
   4636 
   4637                         $result.append(_item);
   4638                     });
   4639 
   4640                     return $result.html();
   4641 
   4642                 },
   4643 
   4644 
   4645                 addContentItemsTo: function ($container) {
   4646                     $container.append(CP_Customizer.content.getContentItems());
   4647                     var self = this;
   4648                     $container.off('click.cp-new-content').on('click.cp-new-content', 'i.mdi[data-content-id]', function (event) {
   4649                         event.preventDefault();
   4650                         event.stopPropagation();
   4651 
   4652                         var node_type = $(this).data('content-id');
   4653                         $container.trigger('cp-insert-content-item', [node_type, self.insertNewContent]);
   4654                     });
   4655 
   4656                     $container.off('click.cp-new-parent').on('click.cp-new-parent', 'i.mdi[data-parent-id]', function (event) {
   4657                         event.preventDefault();
   4658                         event.stopPropagation();
   4659                         $(this).toggleClass('expanded');
   4660                         $(this).siblings().removeClass('expanded');
   4661                     });
   4662                 },
   4663 
   4664                 insertNewContent: function (type, $container, index, after) {
   4665                     var $ = CP_Customizer.preview.jQuery();
   4666                     var $new = $(CP_Customizer.content.getItemData(type));
   4667                     var itemAfter = CP_Customizer.content.getItemAfter(type);
   4668                     CP_Customizer.preview.insertNode($new, $container, index);
   4669                     setTimeout(function () {
   4670                         $new.trigger('click');
   4671                         if (_(after).isFunction()) {
   4672                             after($new);
   4673 
   4674 
   4675                         }
   4676                         if (_.isFunction(itemAfter)) {
   4677                             itemAfter($new);
   4678                         }
   4679                     }, 100);
   4680                 }
   4681             }
   4682 
   4683         }
   4684     ;
   4685 
   4686     CP_Customizer = _.extend(CP_Customizer, {
   4687         closePopUps: root.Materialis.closePopUps,
   4688         popUp: root.Materialis.popUp,
   4689         openRightSidebar: root.Materialis.openRightSidebar,
   4690         hideRightSidebar: root.Materialis.hideRightSidebar,
   4691 
   4692     });
   4693     top.CP_Customizer = root.CP_Customizer = CP_Customizer;
   4694 
   4695 
   4696     var previewLoadedMessageCallback = function (event) {
   4697         if (event.data === 'cloudpress_update_customizer') {
   4698 
   4699             if (root.__isCPChangesetPreview) {
   4700                 CP_Customizer.preview.jQuery('html').addClass('cp__changeset__preview');
   4701                 return;
   4702             }
   4703 
   4704             setTimeout(function () {
   4705                 CP_Customizer.hideLoader();
   4706                 CP_Customizer.preview.frame().wp.customize.preview.bind('loading-initiated', function () {
   4707                     CP_Customizer.showLoader();
   4708                     CP_Customizer.trigger('PREVIEW_LOADING_START');
   4709                 });
   4710 
   4711             }, 300);
   4712 
   4713             _(CP_Customizer).extend(window.cpCustomizerGlobal);
   4714             CP_Customizer.trigger('PREVIEW_LOADED');
   4715 
   4716             CP_Customizer.preview.addContentBinds();
   4717 
   4718             CP_Customizer.preview.jQuery('a').on('click', function (event) {
   4719                 event.preventDefault();
   4720                 event.stopPropagation();
   4721             });
   4722 
   4723             CP_Customizer.preview.decorateMods();
   4724             CP_Customizer.preview.decorateElements();
   4725 
   4726 
   4727             // make the save button use CP_Customizer save wrapper
   4728             $(root.document).find('input#save').unbind('click').bind('click', function (event) {
   4729 
   4730                 event.preventDefault();
   4731                 event.stopPropagation();
   4732                 root.CP_Customizer.save();
   4733             });
   4734 
   4735         }
   4736     };
   4737 
   4738     root.addEventListener('message', previewLoadedMessageCallback);
   4739 
   4740 
   4741     $(root).bind('keydown', function (event) {
   4742         if (event.ctrlKey || event.metaKey) {
   4743             var key = String.fromCharCode(event.which).toLowerCase();
   4744             if (key === "s") {
   4745                 event.preventDefault();
   4746                 event.stopPropagation();
   4747                 root.CP_Customizer.save();
   4748             }
   4749         }
   4750     });
   4751 
   4752     $(root.document).find('input#save').unbind('click').bind('click', function (event) {
   4753         event.preventDefault();
   4754         event.stopPropagation();
   4755         root.CP_Customizer.save();
   4756     });
   4757 
   4758 
   4759     $(root.document).ready(function () {
   4760 
   4761         for (var i = 0; i < CP_Customizer.__modules.length; i++) {
   4762             var callback = CP_Customizer.__modules[i];
   4763             callback(CP_Customizer);
   4764         }
   4765 
   4766         CP_Customizer.__modulesLoaded = true;
   4767         CP_Customizer.trigger('DOCUMENT_READY');
   4768     });
   4769 
   4770     // UTILS
   4771 
   4772     function getTitleElement(name, node, category) {
   4773         var label = "";
   4774         if (typeof name === "function") {
   4775             label = name(node);
   4776         } else {
   4777             if (!_.isUndefined(name)) {
   4778                 label = name;
   4779             } else {
   4780                 return "";
   4781             }
   4782         }
   4783 
   4784         return "<span data-category=\"" + category + "\" class=\"cog-item title\">" + label + "</span>";
   4785     }
   4786 
   4787     function getButtonElement(itemData, node, category) {
   4788         var template = '<span data-category="' + category + '" class="cog-item ' + (itemData.classes || "") + '"></span>';
   4789 
   4790         var $button = $(template).attr({
   4791             'data-name': (itemData.name || 'button')
   4792         });
   4793         $button.text(itemData.title || 'Button');
   4794 
   4795 
   4796         // key is event handler
   4797         $.each(itemData, function (key, data) {
   4798             if (key === 'on_hover') {
   4799                 var callbackIn = function () {
   4800                     data[0].call($button, node);
   4801                 };
   4802                 var callbackOut = function () {
   4803 
   4804                     data[1].call($button, node);
   4805                 };
   4806                 $button.hover(callbackIn, callbackOut);
   4807 
   4808             } else if (key.indexOf('on_') === 0) {
   4809                 var ev = key.replace('on_', '');
   4810                 var callback = function (event) {
   4811                     event.preventDefault();
   4812                     event.stopPropagation();
   4813                     data.call($button, node);
   4814                 };
   4815                 $button.bind(ev, callback);
   4816             }
   4817         });
   4818 
   4819         return $button;
   4820     }
   4821 
   4822     function getItemsElements(itemsArray, node, category) {
   4823         result = [];
   4824         for (var i = 0; i < itemsArray.length; i++) {
   4825             var itemData = itemsArray[i];
   4826             var $item = getButtonElement(itemData, node, category);
   4827             result.push($item);
   4828         }
   4829         return result;
   4830     }
   4831 
   4832 })(jQuery, window);