This commit is contained in:
Rachit Bhargava
2024-01-10 11:53:33 -05:00
parent 83d223b0df
commit 054b4fffc9
16481 changed files with 0 additions and 3473867 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,2 +0,0 @@
!function(e){var t={};function o(n){if(t[n])return t[n].exports;var r=t[n]={i:n,l:!1,exports:{}};return e[n].call(r.exports,r,r.exports,o),r.l=!0,r.exports}o.m=e,o.c=t,o.d=function(e,t,n){o.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.t=function(e,t){if(1&t&&(e=o(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(o.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)o.d(n,r,function(t){return e[t]}.bind(null,r));return n},o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,"a",t),t},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.p="",o(o.s=297)}({297:function(e,t,o){"use strict";(function(e){var t,n=(t=o(68))&&t.__esModule?t:{default:t};window.et_error_modal_shown=!1,window.et_builder_version=window.et_builder_version||"";var r=e("#et-builder-cache-notice-template");et_pb_notice_options.product_version!==window.et_builder_version&&(e("body").addClass("et_pb_stop_scroll").append(r.html()),(0,n.default)(e(".et_pb_prompt_modal")),window.et_error_modal_shown=!0)}).call(this,o(5))},5:function(e,t){e.exports=jQuery},68:function(e,t,o){"use strict";(function(e){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=function(t,o){var n=e(window),r=e("#wpadminbar"),i=n.height(),u=t.outerHeight(),l=r.outerHeight(),a=0-u/2+l/2;u>i-l?t.css({top:"".concat(l+15,"px"),bottom:15,marginTop:0,minHeight:0}):t.css({top:"50%",marginTop:"".concat(a,"px")}),t.addClass("et_pb_auto_centerize_modal")};t.default=o}).call(this,o(5))}});
//# sourceMappingURL=cache_notice.js.map
@@ -1,2 +0,0 @@
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=298)}({298:function(e,t,n){"use strict";(function(e){et_modules_wrapper.builderCssContainerPrefix;var t=et_modules_wrapper.builderCssLayoutPrefix,n=e(".et_pb_module:not(".concat(t," .et_pb_module, .et_pb_section .et_pb_module), .et_pb_row:not(").concat(t," .et_pb_row, .et_pb_section .et_pb_row), .et_pb_section:not(").concat(t," .et_pb_section)"));n.length>0&&n.each((function(){var t=e(this);0===t.closest("#et-boc").length&&t.wrap('<div id="et-boc"></div>'),0===t.closest(".et-l").length&&t.wrap('<div class="et-l"></div>')}))}).call(this,n(5))},5:function(e,t){e.exports=jQuery}});
//# sourceMappingURL=cpt-modules-wrapper.js.map
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
@@ -1,365 +0,0 @@
/*!
* easyPieChart
* Lightweight plugin to render simple, animated and retina optimized pie charts
*
* @author Robert Fleischmann <rendro87@gmail.com> (http://robert-fleischmann.de)
* @version 2.1.5
*
* Modified to adapt the latest jQuery version (v3 above) included on WordPress 5.6:
* - (2020-12-15) - jQuery isFunction method is deprecated.
*/
(function(root, factory) {
if(typeof exports === 'object') {
module.exports = factory(require('jquery'));
}
else if(typeof define === 'function' && define.amd) {
define(['jquery'], factory);
}
else {
factory(root.jQuery);
}
}(this, function($) {
/**
* Renderer to render the chart on a canvas object
* @param {DOMElement} el DOM element to host the canvas (root of the plugin)
* @param {object} options options object of the plugin
*/
var CanvasRenderer = function(el, options) {
var cachedBackground;
var canvas = document.createElement('canvas');
el.appendChild(canvas);
if (typeof(G_vmlCanvasManager) !== 'undefined') {
G_vmlCanvasManager.initElement(canvas);
}
var ctx = canvas.getContext('2d');
canvas.width = canvas.height = options.size;
// canvas on retina devices
var scaleBy = 1;
if (window.devicePixelRatio > 1) {
scaleBy = window.devicePixelRatio;
canvas.style.width = canvas.style.height = [options.size, 'px'].join('');
canvas.width = canvas.height = options.size * scaleBy;
ctx.scale(scaleBy, scaleBy);
}
// move 0,0 coordinates to the center
ctx.translate(options.size / 2, options.size / 2);
// rotate canvas -90deg
ctx.rotate((-1 / 2 + options.rotate / 180) * Math.PI);
var radius = (options.size - options.lineWidth) / 2;
if (options.scaleColor && options.scaleLength) {
radius -= options.scaleLength + 2; // 2 is the distance between scale and bar
}
// IE polyfill for Date
Date.now = Date.now || function() {
return +(new Date());
};
/**
* Draw a circle around the center of the canvas
* @param {strong} color Valid CSS color string
* @param {number} lineWidth Width of the line in px
* @param {number} percent Percentage to draw (float between -1 and 1)
*/
var drawCircle = function(color, lineWidth, percent, alpha ) {
percent = Math.min(Math.max(-1, percent || 0), 1);
var isNegative = percent <= 0 ? true : false;
ctx.beginPath();
ctx.arc(0, 0, radius, 0, Math.PI * 2 * percent, isNegative);
ctx.strokeStyle = color;
ctx.globalAlpha = alpha;
ctx.lineWidth = lineWidth;
ctx.stroke();
};
/**
* Draw the scale of the chart
*/
var drawScale = function() {
var offset;
var length;
ctx.lineWidth = 1;
ctx.fillStyle = options.scaleColor;
ctx.save();
for (var i = 24; i > 0; --i) {
if (i % 6 === 0) {
length = options.scaleLength;
offset = 0;
} else {
length = options.scaleLength * 0.6;
offset = options.scaleLength - length;
}
ctx.fillRect(-options.size/2 + offset, 0, length, 1);
ctx.rotate(Math.PI / 12);
}
ctx.restore();
};
/**
* Request animation frame wrapper with polyfill
* @return {function} Request animation frame method or timeout fallback
*/
var reqAnimationFrame = (function() {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
}());
/**
* Draw the background of the plugin including the scale and the track
*/
var drawBackground = function() {
if(options.scaleColor) drawScale();
if(options.trackColor) drawCircle(options.trackColor, options.lineWidth, 1, options.trackAlpha );
};
/**
* Canvas accessor
*/
this.getCanvas = function() {
return canvas;
};
/**
* Canvas 2D context 'ctx' accessor
*/
this.getCtx = function() {
return ctx;
};
/**
* Clear the complete canvas
*/
this.clear = function() {
ctx.clearRect(options.size / -2, options.size / -2, options.size, options.size);
};
/**
* Draw the complete chart
* @param {number} percent Percent shown by the chart between -100 and 100
*/
this.draw = function(percent) {
// do we need to render a background
if (!!options.scaleColor || !!options.trackColor) {
// getImageData and putImageData are supported
if (ctx.getImageData && ctx.putImageData) {
if (!cachedBackground) {
drawBackground();
cachedBackground = ctx.getImageData(0, 0, options.size * scaleBy, options.size * scaleBy);
} else {
ctx.putImageData(cachedBackground, 0, 0);
}
} else {
this.clear();
drawBackground();
}
} else {
this.clear();
}
ctx.lineCap = options.lineCap;
// if barcolor is a function execute it and pass the percent as a value
var color;
if (typeof(options.barColor) === 'function') {
color = options.barColor(percent);
} else {
color = options.barColor;
}
// draw bar
drawCircle(color, options.lineWidth, percent / 100, options.barAlpha );
}.bind(this);
/**
* Animate from some percent to some other percentage
* @param {number} from Starting percentage
* @param {number} to Final percentage
*/
this.animate = function(from, to) {
var startTime = Date.now();
options.onStart(from, to);
var animation = function() {
var process = Math.min(Date.now() - startTime, options.animate.duration);
var currentValue = options.easing(this, process, from, to - from, options.animate.duration);
this.draw(currentValue);
options.onStep(from, to, currentValue);
if (process >= options.animate.duration) {
options.onStop(from, to);
} else {
reqAnimationFrame(animation);
}
}.bind(this);
reqAnimationFrame(animation);
}.bind(this);
};
var EasyPieChart = function(el, opts) {
var defaultOptions = {
barColor: '#ef1e25',
barAlpha: 1.0,
trackColor: '#f9f9f9',
trackAlpha: 1.0,
scaleColor: '#dfe0e0',
scaleLength: 5,
lineCap: 'round',
lineWidth: 3,
size: 110,
rotate: 0,
render: true,
animate: {
duration: 1000,
enabled: true
},
easing: function (x, t, b, c, d) { // more can be found here: http://gsgd.co.uk/sandbox/jquery/easing/
t = t / (d/2);
if (t < 1) {
return c / 2 * t * t + b;
}
return -c/2 * ((--t)*(t-2) - 1) + b;
},
onStart: function(from, to) {
return;
},
onStep: function(from, to, currentValue) {
return;
},
onStop: function(from, to) {
return;
}
};
// detect present renderer
if (typeof(CanvasRenderer) !== 'undefined') {
defaultOptions.renderer = CanvasRenderer;
} else if (typeof(SVGRenderer) !== 'undefined') {
defaultOptions.renderer = SVGRenderer;
} else {
throw new Error('Please load either the SVG- or the CanvasRenderer');
}
var options = {};
var currentValue = 0;
/**
* Initialize the plugin by creating the options object and initialize rendering
*/
var init = function() {
this.el = el;
this.options = options;
// merge user options into default options
for (var i in defaultOptions) {
if (defaultOptions.hasOwnProperty(i)) {
options[i] = opts && typeof(opts[i]) !== 'undefined' ? opts[i] : defaultOptions[i];
if (typeof(options[i]) === 'function') {
options[i] = options[i].bind(this);
}
}
}
// check for jQuery easing
if (typeof(options.easing) === 'string' && typeof(jQuery) !== 'undefined' && 'function' === typeof jQuery.easing[options.easing]) {
options.easing = jQuery.easing[options.easing];
} else {
options.easing = defaultOptions.easing;
}
// process earlier animate option to avoid bc breaks
if (typeof(options.animate) === 'number') {
options.animate = {
duration: options.animate,
enabled: true
};
}
if (typeof(options.animate) === 'boolean' && !options.animate) {
options.animate = {
duration: 1000,
enabled: options.animate
};
}
// create renderer
this.renderer = new options.renderer(el, options);
// initial draw
this.renderer.draw(currentValue);
// initial update
if (el.dataset && el.dataset.percent) {
this.update(parseFloat(el.dataset.percent));
} else if (el.getAttribute && el.getAttribute('data-percent')) {
this.update(parseFloat(el.getAttribute('data-percent')));
}
}.bind(this);
/**
* Update the value of the chart
* @param {number} newValue Number between 0 and 100
* @return {object} Instance of the plugin for method chaining
*/
this.update = function(newValue) {
newValue = parseFloat(newValue);
if (options.animate.enabled) {
this.renderer.animate(currentValue, newValue);
} else {
this.renderer.draw(newValue);
}
currentValue = newValue;
return this;
}.bind(this);
/**
* Disable animation
* @return {object} Instance of the plugin for method chaining
*/
this.disableAnimation = function() {
options.animate.enabled = false;
return this;
};
/**
* Enable animation
* @return {object} Instance of the plugin for method chaining
*/
this.enableAnimation = function() {
options.animate.enabled = true;
return this;
};
init();
};
$.fn.easyPieChart = function(options) {
return this.each(function() {
var instanceOptions;
if (!$.data(this, 'easyPieChart')) {
instanceOptions = $.extend({}, options, $(this).data());
$.data(this, 'easyPieChart', new EasyPieChart(this, instanceOptions));
}
});
};
}));
@@ -1,46 +0,0 @@
/*global jQuery */
/*!
* FitText.js 1.2
*
* Copyright 2011, Dave Rupert http://daverupert.com
* Released under the WTFPL license
* http://sam.zoy.org/wtfpl/
*
* Date: Thu May 05 14:23:00 2011 -0600
*
* Modified to adapt the latest jQuery version (v3 above) included on WordPress 5.6:
* - (2021-02-05) - Number type value passed to css method is deprecated.
*/
(function( $ ){
$.fn.fitText = function( kompressor, options ) {
// Setup options
var compressor = kompressor || 1,
settings = $.extend({
'minFontSize' : Number.NEGATIVE_INFINITY,
'maxFontSize' : $(this).css('font-size')
}, options);
return this.each(function(){
// Store the object
var $this = $(this);
// Resizer() resizes items based on the object width divided by the compressor * 10
var resizer = function () {
$this.css('font-size', Math.max(Math.min($this.width() / (compressor*10), parseFloat(settings.maxFontSize)), parseFloat(settings.minFontSize)) + 'px');
};
// Call once to set.
resizer();
// Call on resize. Opera debounces their resize by default.
$(window).on('resize.fittext orientationchange.fittext', resizer);
});
};
})( jQuery );
@@ -1,87 +0,0 @@
/*jshint browser:true */
/*!
* FitVids 1.1
*
* Copyright 2013, Chris Coyier - http://css-tricks.com + Dave Rupert - http://daverupert.com
* Credit to Thierry Koblentz - http://www.alistapart.com/articles/creating-intrinsic-ratios-for-video/
* Released under the WTFPL license - http://sam.zoy.org/wtfpl/
*
*/
;(function( $ ){
'use strict';
$.fn.fitVids = function( options ) {
var settings = {
customSelector: null,
ignore: null
};
if(!document.getElementById('fit-vids-style')) {
// appendStyles: https://github.com/toddmotto/fluidvids/blob/master/dist/fluidvids.js
var head = document.head || document.getElementsByTagName('head')[0];
var css = '.fluid-width-video-wrapper{width:100%;position:relative;padding:0;}.fluid-width-video-wrapper iframe,.fluid-width-video-wrapper object,.fluid-width-video-wrapper embed {position:absolute;top:0;left:0;width:100%;height:100%;}';
var div = document.createElement("div");
div.innerHTML = '<p>x</p><style id="fit-vids-style">' + css + '</style>';
head.appendChild(div.childNodes[1]);
}
if ( options ) {
$.extend( settings, options );
}
return this.each(function(){
var selectors = [
'iframe[src*="player.vimeo.com"]',
'iframe[src*="youtube.com"]',
'iframe[src*="youtube-nocookie.com"]',
'iframe[src*="kickstarter.com"][src*="video.html"]',
'object',
'embed'
];
if (settings.customSelector) {
selectors.push(settings.customSelector);
}
var ignoreList = '.fitvidsignore';
if(settings.ignore) {
ignoreList = ignoreList + ', ' + settings.ignore;
}
var $allVideos = $(this).find(selectors.join(','));
$allVideos = $allVideos.not('object object'); // SwfObj conflict patch
$allVideos = $allVideos.not(ignoreList); // Disable FitVids on this video.
$allVideos.each(function(){
var $this = $(this);
if($this.parents(ignoreList).length > 0) {
return; // Disable FitVids on this video.
}
if (this.tagName.toLowerCase() === 'embed' && $this.parent('object').length || $this.parent('.fluid-width-video-wrapper').length) { return; }
if ((!$this.css('height') && !$this.css('width')) && (isNaN($this.attr('height')) || isNaN($this.attr('width'))))
{
$this.attr('height', 9);
$this.attr('width', 16);
}
var height = ( this.tagName.toLowerCase() === 'object' || ($this.attr('height') && !isNaN(parseInt($this.attr('height'), 10))) ) ? parseInt($this.attr('height'), 10) : $this.height(),
width = !isNaN(parseInt($this.attr('width'), 10)) ? parseInt($this.attr('width'), 10) : $this.width(),
aspectRatio = height / width;
if(!$this.attr('name')){
var videoName = 'fitvid' + $.fn.fitVids._count;
$this.attr('name', videoName);
$.fn.fitVids._count++;
}
$this.wrap('<div class="fluid-width-video-wrapper"></div>').parent('.fluid-width-video-wrapper').css('padding-top', (aspectRatio * 100)+'%');
$this.removeAttr('height').removeAttr('width');
});
});
};
// Internal counter for unique video names.
$.fn.fitVids._count = 0;
// Works with either jQuery or Zepto
})( window.jQuery || window.Zepto );
@@ -1,393 +0,0 @@
/*!
* jQuery hashchange event - v1.3 - 7/21/2010
* http://benalman.com/projects/jquery-hashchange-plugin/
*
* Copyright (c) 2010 "Cowboy" Ben Alman
* Dual licensed under the MIT and GPL licenses.
* http://benalman.com/about/license/
*
* Modified to adapt the latest jQuery version (v3 above) included on WordPress 5.6:
* - (2021-02-03) - jQuery bind method is deprecated.
*/
// Script: jQuery hashchange event
//
// *Version: 1.3, Last updated: 7/21/2010*
//
// Project Home - http://benalman.com/projects/jquery-hashchange-plugin/
// GitHub - http://github.com/cowboy/jquery-hashchange/
// Source - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js
// (Minified) - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (0.8kb gzipped)
//
// About: License
//
// Copyright (c) 2010 "Cowboy" Ben Alman,
// Dual licensed under the MIT and GPL licenses.
// http://benalman.com/about/license/
//
// About: Examples
//
// These working examples, complete with fully commented code, illustrate a few
// ways in which this plugin can be used.
//
// hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/
// document.domain - http://benalman.com/code/projects/jquery-hashchange/examples/document_domain/
//
// About: Support and Testing
//
// Information about what version or versions of jQuery this plugin has been
// tested with, what browsers it has been tested in, and where the unit tests
// reside (so you can test it yourself).
//
// jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2
// Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5,
// Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5.
// Unit Tests - http://benalman.com/code/projects/jquery-hashchange/unit/
//
// About: Known issues
//
// While this jQuery hashchange event implementation is quite stable and
// robust, there are a few unfortunate browser bugs surrounding expected
// hashchange event-based behaviors, independent of any JavaScript
// window.onhashchange abstraction. See the following examples for more
// information:
//
// Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/
// Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/
// WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/
// Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/
//
// Also note that should a browser natively support the window.onhashchange
// event, but not report that it does, the fallback polling loop will be used.
//
// About: Release History
//
// 1.3 - (7/21/2010) Reorganized IE6/7 Iframe code to make it more
// "removable" for mobile-only development. Added IE6/7 document.title
// support. Attempted to make Iframe as hidden as possible by using
// techniques from http://www.paciellogroup.com/blog/?p=604. Added
// support for the "shortcut" format $(window).hashchange( fn ) and
// $(window).hashchange() like jQuery provides for built-in events.
// Renamed jQuery.hashchangeDelay to <jQuery.fn.hashchange.delay> and
// lowered its default value to 50. Added <jQuery.fn.hashchange.domain>
// and <jQuery.fn.hashchange.src> properties plus document-domain.html
// file to address access denied issues when setting document.domain in
// IE6/7.
// 1.2 - (2/11/2010) Fixed a bug where coming back to a page using this plugin
// from a page on another domain would cause an error in Safari 4. Also,
// IE6/7 Iframe is now inserted after the body (this actually works),
// which prevents the page from scrolling when the event is first bound.
// Event can also now be bound before DOM ready, but it won't be usable
// before then in IE6/7.
// 1.1 - (1/21/2010) Incorporated document.documentMode test to fix IE8 bug
// where browser version is incorrectly reported as 8.0, despite
// inclusion of the X-UA-Compatible IE=EmulateIE7 meta tag.
// 1.0 - (1/9/2010) Initial Release. Broke out the jQuery BBQ event.special
// window.onhashchange functionality into a separate plugin for users
// who want just the basic event & back button support, without all the
// extra awesomeness that BBQ provides. This plugin will be included as
// part of jQuery BBQ, but also be available separately.
(function($,window,undefined){
'$:nomunge'; // Used by YUI compressor.
// Reused string.
var str_hashchange = 'hashchange',
// Method / object references.
doc = document,
fake_onhashchange,
special = $.event.special,
// Does the browser support window.onhashchange? Note that IE8 running in
// IE7 compatibility mode reports true for 'onhashchange' in window, even
// though the event isn't supported, so also test document.documentMode.
doc_mode = doc.documentMode,
supports_onhashchange = 'on' + str_hashchange in window && ( doc_mode === undefined || doc_mode > 7 );
// Get location.hash (or what you'd expect location.hash to be) sans any
// leading #. Thanks for making this necessary, Firefox!
function get_fragment( url ) {
url = url || location.href;
return '#' + url.replace( /^[^#]*#?(.*)$/, '$1' );
};
// Method: jQuery.fn.hashchange
//
// Bind a handler to the window.onhashchange event or trigger all bound
// window.onhashchange event handlers. This behavior is consistent with
// jQuery's built-in event handlers.
//
// Usage:
//
// > jQuery(window).hashchange( [ handler ] );
//
// Arguments:
//
// handler - (Function) Optional handler to be bound to the hashchange
// event. This is a "shortcut" for the more verbose form:
// jQuery(window).on( 'hashchange', handler ). If handler is omitted,
// all bound window.onhashchange event handlers will be triggered. This
// is a shortcut for the more verbose
// jQuery(window).trigger( 'hashchange' ). These forms are described in
// the <hashchange event> section.
//
// Returns:
//
// (jQuery) The initial jQuery collection of elements.
// Allow the "shortcut" format $(elem).hashchange( fn ) for binding and
// $(elem).hashchange() for triggering, like jQuery does for built-in events.
$.fn[ str_hashchange ] = function( fn ) {
return fn ? this.on( str_hashchange, fn ) : this.trigger( str_hashchange );
};
// Property: jQuery.fn.hashchange.delay
//
// The numeric interval (in milliseconds) at which the <hashchange event>
// polling loop executes. Defaults to 50.
// Property: jQuery.fn.hashchange.domain
//
// If you're setting document.domain in your JavaScript, and you want hash
// history to work in IE6/7, not only must this property be set, but you must
// also set document.domain BEFORE jQuery is loaded into the page. This
// property is only applicable if you are supporting IE6/7 (or IE8 operating
// in "IE7 compatibility" mode).
//
// In addition, the <jQuery.fn.hashchange.src> property must be set to the
// path of the included "document-domain.html" file, which can be renamed or
// modified if necessary (note that the document.domain specified must be the
// same in both your main JavaScript as well as in this file).
//
// Usage:
//
// jQuery.fn.hashchange.domain = document.domain;
// Property: jQuery.fn.hashchange.src
//
// If, for some reason, you need to specify an Iframe src file (for example,
// when setting document.domain as in <jQuery.fn.hashchange.domain>), you can
// do so using this property. Note that when using this property, history
// won't be recorded in IE6/7 until the Iframe src file loads. This property
// is only applicable if you are supporting IE6/7 (or IE8 operating in "IE7
// compatibility" mode).
//
// Usage:
//
// jQuery.fn.hashchange.src = 'path/to/file.html';
$.fn[ str_hashchange ].delay = 50;
/*
$.fn[ str_hashchange ].domain = null;
$.fn[ str_hashchange ].src = null;
*/
// Event: hashchange event
//
// Fired when location.hash changes. In browsers that support it, the native
// HTML5 window.onhashchange event is used, otherwise a polling loop is
// initialized, running every <jQuery.fn.hashchange.delay> milliseconds to
// see if the hash has changed. In IE6/7 (and IE8 operating in "IE7
// compatibility" mode), a hidden Iframe is created to allow the back button
// and hash-based history to work.
//
// Usage as described in <jQuery.fn.hashchange>:
//
// > // Bind an event handler.
// > jQuery(window).hashchange( function(e) {
// > var hash = location.hash;
// > ...
// > });
// >
// > // Manually trigger the event handler.
// > jQuery(window).hashchange();
//
// A more verbose usage that allows for event namespacing:
//
// > // Bind an event handler.
// > jQuery(window).on( 'hashchange', function(e) {
// > var hash = location.hash;
// > ...
// > });
// >
// > // Manually trigger the event handler.
// > jQuery(window).trigger( 'hashchange' );
//
// Additional Notes:
//
// * The polling loop and Iframe are not created until at least one handler
// is actually bound to the 'hashchange' event.
// * If you need the bound handler(s) to execute immediately, in cases where
// a location.hash exists on page load, via bookmark or page refresh for
// example, use jQuery(window).hashchange() or the more verbose
// jQuery(window).trigger( 'hashchange' ).
// * The event can be bound before DOM ready, but since it won't be usable
// before then in IE6/7 (due to the necessary Iframe), recommended usage is
// to bind it inside a DOM ready handler.
// Override existing $.event.special.hashchange methods (allowing this plugin
// to be defined after jQuery BBQ in BBQ's source code).
special[ str_hashchange ] = $.extend( special[ str_hashchange ], {
// Called only when the first 'hashchange' event is bound to window.
setup: function() {
// If window.onhashchange is supported natively, there's nothing to do..
if ( supports_onhashchange ) { return false; }
// Otherwise, we need to create our own. And we don't want to call this
// until the user binds to the event, just in case they never do, since it
// will create a polling loop and possibly even a hidden Iframe.
$( fake_onhashchange.start );
},
// Called only when the last 'hashchange' event is unbound from window.
teardown: function() {
// If window.onhashchange is supported natively, there's nothing to do..
if ( supports_onhashchange ) { return false; }
// Otherwise, we need to stop ours (if possible).
$( fake_onhashchange.stop );
}
});
// fake_onhashchange does all the work of triggering the window.onhashchange
// event for browsers that don't natively support it, including creating a
// polling loop to watch for hash changes and in IE 6/7 creating a hidden
// Iframe to enable back and forward.
fake_onhashchange = (function(){
var self = {},
timeout_id,
// Remember the initial hash so it doesn't get triggered immediately.
last_hash = get_fragment(),
fn_retval = function(val){ return val; },
history_set = fn_retval,
history_get = fn_retval;
// Start the polling loop.
self.start = function() {
timeout_id || poll();
};
// Stop the polling loop.
self.stop = function() {
timeout_id && clearTimeout( timeout_id );
timeout_id = undefined;
};
// This polling loop checks every $.fn.hashchange.delay milliseconds to see
// if location.hash has changed, and triggers the 'hashchange' event on
// window when necessary.
function poll() {
var hash = get_fragment(),
history_hash = history_get( last_hash );
if ( hash !== last_hash ) {
history_set( last_hash = hash, history_hash );
$(window).trigger( str_hashchange );
} else if ( history_hash !== last_hash ) {
location.href = location.href.replace( /#.*/, '' ) + history_hash;
}
timeout_id = setTimeout( poll, $.fn[ str_hashchange ].delay );
};
// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
// vvvvvvvvvvvvvvvvvvv REMOVE IF NOT SUPPORTING IE6/7/8 vvvvvvvvvvvvvvvvvvv
// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
typeof $.browser !== 'undefined' && $.browser.msie && !supports_onhashchange && (function(){
// Not only do IE6/7 need the "magical" Iframe treatment, but so does IE8
// when running in "IE7 compatibility" mode.
var iframe,
iframe_src;
// When the event is bound and polling starts in IE 6/7, create a hidden
// Iframe for history handling.
self.start = function(){
if ( !iframe ) {
iframe_src = $.fn[ str_hashchange ].src;
iframe_src = iframe_src && iframe_src + get_fragment();
// Create hidden Iframe. Attempt to make Iframe as hidden as possible
// by using techniques from http://www.paciellogroup.com/blog/?p=604.
iframe = $('<iframe tabindex="-1" title="empty"/>').hide()
// When Iframe has completely loaded, initialize the history and
// start polling.
.one( 'load', function(){
iframe_src || history_set( get_fragment() );
poll();
})
// Load Iframe src if specified, otherwise nothing.
.attr( 'src', iframe_src || 'javascript:0' )
// Append Iframe after the end of the body to prevent unnecessary
// initial page scrolling (yes, this works).
.insertAfter( 'body' )[0].contentWindow;
// Whenever `document.title` changes, update the Iframe's title to
// prettify the back/next history menu entries. Since IE sometimes
// errors with "Unspecified error" the very first time this is set
// (yes, very useful) wrap this with a try/catch block.
doc.onpropertychange = function(){
try {
if ( event.propertyName === 'title' ) {
iframe.document.title = doc.title;
}
} catch(e) {}
};
}
};
// Override the "stop" method since an IE6/7 Iframe was created. Even
// if there are no longer any bound event handlers, the polling loop
// is still necessary for back/next to work at all!
self.stop = fn_retval;
// Get history by looking at the hidden Iframe's location.hash.
history_get = function() {
return get_fragment( iframe.location.href );
};
// Set a new history item by opening and then closing the Iframe
// document, *then* setting its location.hash. If document.domain has
// been set, update that as well.
history_set = function( hash, history_hash ) {
var iframe_doc = iframe.document,
domain = $.fn[ str_hashchange ].domain;
if ( hash !== history_hash ) {
// Update Iframe with any initial `document.title` that might be set.
iframe_doc.title = doc.title;
// Opening the Iframe's document after it has been closed is what
// actually adds a history entry.
iframe_doc.open();
// Set document.domain for the Iframe document as well, if necessary.
domain && iframe_doc.write( '<script>document.domain="' + domain + '"</script>' );
iframe_doc.close();
// Update the Iframe's hash, for great justice.
iframe.location.hash = hash;
}
};
})();
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// ^^^^^^^^^^^^^^^^^^^ REMOVE IF NOT SUPPORTING IE6/7/8 ^^^^^^^^^^^^^^^^^^^
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
return self;
})();
})(jQuery,this);
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
@@ -1,23 +0,0 @@
/*
Copyright (c) 2012 Digital Fusion, http://teamdf.com/
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
!function(t){var i=t(window);t.fn.visible=function(t,e,o){if(!(this.length<1)){var r=this.length>1?this.eq(0):this,n=r.get(0),f=i.width(),h=i.height(),o=o?o:"both",l=e===!0?n.offsetWidth*n.offsetHeight:!0;if("function"==typeof n.getBoundingClientRect){var g=n.getBoundingClientRect(),u=g.top>=0&&g.top<h,s=g.bottom>0&&g.bottom<=h,c=g.left>=0&&g.left<f,a=g.right>0&&g.right<=f,v=t?u||s:u&&s,b=t?c||a:c&&a;if("both"===o)return l&&v&&b;if("vertical"===o)return l&&v;if("horizontal"===o)return l&&b}else{var d=i.scrollTop(),p=d+h,w=i.scrollLeft(),m=w+f,y=r.offset(),z=y.top,B=z+r.height(),C=y.left,R=C+r.width(),j=t===!0?B:z,q=t===!0?z:B,H=t===!0?R:C,L=t===!0?C:R;if("both"===o)return!!l&&p>=q&&j>=d&&m>=L&&H>=w;if("vertical"===o)return!!l&&p>=q&&j>=d;if("horizontal"===o)return!!l&&m>=L&&H>=w}}}}(jQuery);
@@ -1,12 +0,0 @@
/*!
* Copyright (c) 2013 Pieroxy <pieroxy@pieroxy.net>
* This work is free. You can redistribute it and/or modify it
* under the terms of the WTFPL, Version 2
* For more information see LICENSE.txt or http://www.wtfpl.net/
*
* For more information, the home page:
* http://pieroxy.net/blog/pages/lz-string/testing.html
*
* LZ-based compression algorithm, version 1.4.4
*/
var LZString=function(){function o(o,r){if(!t[o]){t[o]={};for(var n=0;n<o.length;n++)t[o][o.charAt(n)]=n}return t[o][r]}var r=String.fromCharCode,n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$",t={},i={compressToBase64:function(o){if(null==o)return"";var r=i._compress(o,6,function(o){return n.charAt(o)});switch(r.length%4){default:case 0:return r;case 1:return r+"===";case 2:return r+"==";case 3:return r+"="}},decompressFromBase64:function(r){return null==r?"":""==r?null:i._decompress(r.length,32,function(e){return o(n,r.charAt(e))})},compressToUTF16:function(o){return null==o?"":i._compress(o,15,function(o){return r(o+32)})+" "},decompressFromUTF16:function(o){return null==o?"":""==o?null:i._decompress(o.length,16384,function(r){return o.charCodeAt(r)-32})},compressToUint8Array:function(o){for(var r=i.compress(o),n=new Uint8Array(2*r.length),e=0,t=r.length;t>e;e++){var s=r.charCodeAt(e);n[2*e]=s>>>8,n[2*e+1]=s%256}return n},decompressFromUint8Array:function(o){if(null===o||void 0===o)return i.decompress(o);for(var n=new Array(o.length/2),e=0,t=n.length;t>e;e++)n[e]=256*o[2*e]+o[2*e+1];var s=[];return n.forEach(function(o){s.push(r(o))}),i.decompress(s.join(""))},compressToEncodedURIComponent:function(o){return null==o?"":i._compress(o,6,function(o){return e.charAt(o)})},decompressFromEncodedURIComponent:function(r){return null==r?"":""==r?null:(r=r.replace(/ /g,"+"),i._decompress(r.length,32,function(n){return o(e,r.charAt(n))}))},compress:function(o){return i._compress(o,16,function(o){return r(o)})},_compress:function(o,r,n){if(null==o)return"";var e,t,i,s={},p={},u="",c="",a="",l=2,f=3,h=2,d=[],m=0,v=0;for(i=0;i<o.length;i+=1)if(u=o.charAt(i),Object.prototype.hasOwnProperty.call(s,u)||(s[u]=f++,p[u]=!0),c=a+u,Object.prototype.hasOwnProperty.call(s,c))a=c;else{if(Object.prototype.hasOwnProperty.call(p,a)){if(a.charCodeAt(0)<256){for(e=0;h>e;e++)m<<=1,v==r-1?(v=0,d.push(n(m)),m=0):v++;for(t=a.charCodeAt(0),e=0;8>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}else{for(t=1,e=0;h>e;e++)m=m<<1|t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t=0;for(t=a.charCodeAt(0),e=0;16>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}l--,0==l&&(l=Math.pow(2,h),h++),delete p[a]}else for(t=s[a],e=0;h>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;l--,0==l&&(l=Math.pow(2,h),h++),s[c]=f++,a=String(u)}if(""!==a){if(Object.prototype.hasOwnProperty.call(p,a)){if(a.charCodeAt(0)<256){for(e=0;h>e;e++)m<<=1,v==r-1?(v=0,d.push(n(m)),m=0):v++;for(t=a.charCodeAt(0),e=0;8>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}else{for(t=1,e=0;h>e;e++)m=m<<1|t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t=0;for(t=a.charCodeAt(0),e=0;16>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}l--,0==l&&(l=Math.pow(2,h),h++),delete p[a]}else for(t=s[a],e=0;h>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;l--,0==l&&(l=Math.pow(2,h),h++)}for(t=2,e=0;h>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;for(;;){if(m<<=1,v==r-1){d.push(n(m));break}v++}return d.join("")},decompress:function(o){return null==o?"":""==o?null:i._decompress(o.length,32768,function(r){return o.charCodeAt(r)})},_decompress:function(o,n,e){var t,i,s,p,u,c,a,l,f=[],h=4,d=4,m=3,v="",w=[],A={val:e(0),position:n,index:1};for(i=0;3>i;i+=1)f[i]=i;for(p=0,c=Math.pow(2,2),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;switch(t=p){case 0:for(p=0,c=Math.pow(2,8),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;l=r(p);break;case 1:for(p=0,c=Math.pow(2,16),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;l=r(p);break;case 2:return""}for(f[3]=l,s=l,w.push(l);;){if(A.index>o)return"";for(p=0,c=Math.pow(2,m),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;switch(l=p){case 0:for(p=0,c=Math.pow(2,8),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;f[d++]=r(p),l=d-1,h--;break;case 1:for(p=0,c=Math.pow(2,16),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;f[d++]=r(p),l=d-1,h--;break;case 2:return w.join("")}if(0==h&&(h=Math.pow(2,m),m++),f[l])v=f[l];else{if(l!==d)return null;v=s+s.charAt(0)}w.push(v),f[d++]=s+v.charAt(0),h--,s=v,0==h&&(h=Math.pow(2,m),m++)}}};return i}();"function"==typeof define&&define.amd?define(function(){return LZString}):"undefined"!=typeof module&&null!=module&&(module.exports=LZString);
@@ -1,157 +0,0 @@
/* global wp */
/**
* media-library.js
*
* Adapted from WordPress
*
* @copyright 2017 by the WordPress contributors.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* This program incorporates work covered by the following copyright and
* permission notices:
*
* b2 is (c) 2001, 2002 Michel Valdrighi - m@tidakada.com - http://tidakada.com
*
* b2 is released under the GPL
*
* WordPress - Web publishing software
*
* Copyright 2003-2010 by the contributors
*
* WordPress is released under the GPL
*/
var Select = wp.media.view.MediaFrame.Select,
Library = wp.media.controller.Library,
l10n = wp.media.view.l10n;
wp.media.view.MediaFrame.ETSelect = wp.media.view.MediaFrame.Select.extend({
initialize: function() {
_.defaults( this.options, {
multiple: true,
editing: false,
embed: true,
state: 'insert',
metadata: {},
title: l10n.insertMediaTitle,
button: {
text: l10n.insertIntoPost
},
});
// Call 'initialize' directly on the parent class.
Select.prototype.initialize.apply( this, arguments );
this.createIframeStates();
},
/**
* Create the default states.
*/
createStates: function() {
var options = this.options;
var states = [
// Main states.
new Library({
id: 'insert',
title: options.title,
priority: 20,
toolbar: 'main-insert',
filterable: 'all',
library: wp.media.query( options.library ),
multiple: options.multiple ? 'reset' : false,
editable: true,
allowLocalEdits: true,
displaySettings: true,
displayUserSettings: true
}),
];
if (options.embed) {
// Embed states.
states.push(new wp.media.controller.Embed( { metadata: options.metadata } ))
}
this.states.add(states);
},
bindHandlers: function() {
var handlers;
Select.prototype.bindHandlers.apply( this, arguments );
this.on( 'toolbar:create:main-insert', this.createToolbar, this );
this.on( 'toolbar:create:main-embed', this.mainEmbedToolbar, this );
handlers = {
content: {
'embed': 'embedContent',
},
toolbar: {
'main-insert': 'mainInsertToolbar',
}
};
_.each( handlers, function( regionHandlers, region ) {
_.each( regionHandlers, function( callback, handler ) {
this.on( region + ':render:' + handler, this[ callback ], this );
}, this );
}, this );
},
// Content
embedContent: function() {
var view = new wp.media.view.Embed({
controller: this,
model: this.state()
}).render();
this.content.set( view );
if ( ! wp.media.isTouchDevice ) {
view.url.input.focus();
}
},
// Toolbars
mainInsertToolbar: function( view ) {
var options = this.options;
var controller = this;
view.set( 'insert', {
style: 'primary',
priority: 80,
text: options.button.text,
requires: { selection: true },
/**
* @fires wp.media.controller.State#insert
*/
click: function() {
var state = controller.state(),
selection = state.get('selection');
controller.close();
state.trigger( 'insert', selection ).reset();
}
});
},
mainEmbedToolbar: function( toolbar ) {
toolbar.view = new wp.media.view.Toolbar.Embed({
controller: this
});
}
});
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,92 +0,0 @@
( function($) {
$(function() {
// WP 5.8 above - Widget Block Editor.
var is_widgets_block_editor = $('.edit-widgets-block-editor').length > 0;
// 1.a Appends widget area creator panel.
var widget_writing_area = is_widgets_block_editor ? '.block-editor-writing-flow > div' : '.widget-liquid-right';
$(widget_writing_area).append(et_pb_options.widget_info);
var $create_box = $( '#et_pb_widget_area_create' ),
$widget_name_input = $create_box.find( '#et_pb_new_widget_area_name' ),
$et_pb_sidebars = $( 'div[id^=et_pb_widget_area_]' );
// 1.b. Handles create widget area action.
$create_box.find('.et_pb_create_widget_area').on('click', function(event) {
var $this_el = $(this);
event.preventDefault();
if ( $widget_name_input.val() === '' ) return;
$.ajax( {
type: "POST",
url: et_pb_options.ajaxurl,
data:
{
action : 'et_pb_add_widget_area',
et_admin_load_nonce : et_pb_options.et_admin_load_nonce,
et_widget_area_name : $widget_name_input.val()
},
success: function( data ){
$this_el.closest( '#et_pb_widget_area_create' ).find( '.et_pb_widget_area_result' ).hide().html( data ).slideToggle();
}
} );
});
// 2.a. Append custom widget area remove button and handles remove action.
var et_pb_sidebars_append_delete_button = function() {
// 2.a.1. Append custom widget area remove button.
var widget_area_id = is_widgets_block_editor ? $(this).data('widget-area-id') : $(this).attr('id');
var widget_wrapper = is_widgets_block_editor ? '.block-editor-block-list__block' : '.widgets-holder-wrap';
var widget_title = is_widgets_block_editor ? '.components-panel__body-toggle' : '.sidebar-name h2, .sidebar-name h3';
$(this).closest(widget_wrapper).find(widget_title).before('<a href="#" class="et_pb_widget_area_remove" data-et-widget-area-id="' + widget_area_id + '">' + et_pb_options.delete_string + '</a>');
// 2.a.1. andles remove widget area action.
$('.et_pb_widget_area_remove').on('click', function(event) {
var $this_el = $(this);
event.preventDefault();
$.ajax( {
type: "POST",
url: et_pb_options.ajaxurl,
data:
{
action : 'et_pb_remove_widget_area',
et_admin_load_nonce : et_pb_options.et_admin_load_nonce,
et_widget_area_name : $this_el.data('et-widget-area-id'),
},
success: function( data ){
$('a[data-et-widget-area-id="' + data + '"]').closest(widget_wrapper).remove();
}
} );
return false;
});
};
// 2.b. Appends custom widget area remove button on each custom sidebar.
if (is_widgets_block_editor) {
var widgetBlockListMutation = _.debounce(function(mutations, observer) {
$('div[data-widget-area-id^=et_pb_widget_area_]').each(et_pb_sidebars_append_delete_button);
// Disconnect once we know the delete buttons are added.
if ($('.et_pb_widget_area_remove').length > 0) {
observer.disconnect();
}
}, 1000);
// Watch for widget block editor to load Widget Area blocks. There is no event to
// know when those blocks are added on the editor, hence we use mutation observer.
var widgetBlockListObserver = new MutationObserver(widgetBlockListMutation);
widgetBlockListObserver.observe(document.querySelector('.block-editor-block-list__layout'), {childList: true});
} else {
$et_pb_sidebars.each(et_pb_sidebars_append_delete_button);
}
} );
} )(jQuery);
@@ -1,424 +0,0 @@
/**
* wp-color-picker-alpha
*
* Version 1.0
* Copyright (c) 2017 Elegant Themes.
* Licensed under the GPLv2 license.
*
* Overwrite Automattic Iris for enabled Alpha Channel in wpColorPicker
* Only run in input and is defined data alpha in true
* Add custom colorpicker UI
*
* This is modified version made by Elegant Themes based on the work covered by
* the following copyright:
*
* wp-color-picker-alpha Version: 1.1
* https://github.com/23r9i0/wp-color-picker-alpha
* Copyright (c) 2015 Sergio P.A. (23r9i0).
* Licensed under the GPLv2 license.
*/
( function( $ ) {
// Variable for some backgrounds
var image = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAAHnlligAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAHJJREFUeNpi+P///4EDBxiAGMgCCCAGFB5AADGCRBgYDh48CCRZIJS9vT2QBAggFBkmBiSAogxFBiCAoHogAKIKAlBUYTELAiAmEtABEECk20G6BOmuIl0CIMBQ/IEMkO0myiSSraaaBhZcbkUOs0HuBwDplz5uFJ3Z4gAAAABJRU5ErkJggg==';
// html stuff for wpColorPicker copy of the original color-picker.js
var _before = '<a tabindex="0" class="wp-color-result" />',
_after = '<div class="wp-picker-holder" />',
_wrap = '<div class="wp-picker-container" />',
_button = '<input type="button" class="button button-small button-clear hidden" />',
_close_button = '<button type="button" class="button button-confirm" />',
_close_button_icon = '<div style="fill: #3EF400; width: 25px; height: 25px; margin-top: -1px;"><svg viewBox="0 0 28 28" preserveAspectRatio="xMidYMid meet" shapeRendering="geometricPrecision"><g><path d="M19.203 9.21a.677.677 0 0 0-.98 0l-5.71 5.9-2.85-2.95a.675.675 0 0 0-.98 0l-1.48 1.523a.737.737 0 0 0 0 1.015l4.82 4.979a.677.677 0 0 0 .98 0l7.68-7.927a.737.737 0 0 0 0-1.015l-1.48-1.525z" fillRule="evenodd" /></g></svg></div>';
/**
* Overwrite Color
* for enable support rbga
*/
Color.fn.toString = function() {
if ( this._alpha < 1 )
return this.toCSS( 'rgba', this._alpha ).replace( /\s+/g, '' );
var hex = parseInt( this._color, 10 ).toString( 16 );
if ( this.error )
return '';
if ( hex.length < 6 ) {
for ( var i = 6 - hex.length - 1; i >= 0; i-- ) {
hex = '0' + hex;
}
}
return '#' + hex;
};
/**
* Overwrite wpColorPicker
*/
$.widget( 'wp.wpColorPicker', $.wp.wpColorPicker, {
_create: function() {
// bail early for unsupported Iris.
if ( ! $.support.iris ) {
return;
}
var self = this,
el = self.element;
$.extend( self.options, el.data() );
// keep close bound so it can be attached to a body listener
self.close = $.proxy( self.close, self );
self.initialValue = el.val();
// Set up HTML structure, hide things
el.addClass( 'wp-color-picker' ).hide().wrap( _wrap );
self.wrap = el.parent();
self.toggler = $( _before ).insertBefore( el ).css( { backgroundColor: self.initialValue } ).attr( 'title', wpColorPickerL10n.pick ).attr( 'data-current', wpColorPickerL10n.current );
self.pickerContainer = $( _after ).insertAfter( el );
self.button = $( _button );
self.close_button = $( _close_button );
if ( self.options.defaultColor ) {
self.button.addClass( 'wp-picker-default' ).val( wpColorPickerL10n.defaultString );
} else {
self.button.addClass( 'wp-picker-clear' ).val( wpColorPickerL10n.clear );
}
el.wrap( '<span class="wp-picker-input-wrap" />' ).after(self.button);
if ( self.options.diviColorpicker ) {
self.close_button.html( _close_button_icon );
el.after( self.close_button );
}
el.iris( {
target: self.pickerContainer,
hide: self.options.hide,
width: self.options.width,
height: self.options.height,
diviColorpicker: self.options.diviColorpicker,
mode: self.options.mode,
palettes: self.options.palettes,
change: function( event, ui ) {
if ( self.options.alpha ) {
self.toggler.css( { 'background-image': 'url(' + image + ')' } ).html('<span />');
self.toggler.find('span').css({
'width': '100%',
'height': '100%',
'position': 'absolute',
'top': 0,
'left': 0,
'border-top-left-radius': '3px',
'border-bottom-left-radius': '3px',
'background': ui.color.toString()
});
} else {
self.toggler.css( { backgroundColor: ui.color.toString() } );
}
// check for a custom cb
if ( $.isFunction( self.options.change ) ) {
self.options.change.call( this, event, ui );
}
}
} );
el.val( self.initialValue );
self._addListeners();
if ( ! self.options.hide ) {
self.toggler.click();
}
},
_addListeners: function() {
var self = this;
// prevent any clicks inside this widget from leaking to the top and closing it
self.wrap.on( 'click.wpcolorpicker', function( event ) {
event.stopPropagation();
});
self.toggler.click( function(){
if ( self.toggler.hasClass( 'wp-picker-open' ) ) {
self.close();
} else {
self.open();
}
});
self.element.change( function( event ) {
var me = $( this ),
val = me.val();
// Empty or Error = clear
if ( val === '' || self.element.hasClass('iris-error') ) {
if ( self.options.alpha ) {
self.toggler.css( 'backgroundColor', '' );
self.toggler.find('span').css( 'backgroundColor', '' );
} else {
self.toggler.css( 'backgroundColor', '' );
}
// fire clear callback if we have one
if ( $.isFunction( self.options.clear ) ) {
self.options.clear.call( this, event );
}
}
});
// open a keyboard-focused closed picker with space or enter
self.toggler.on( 'keyup', function( event ) {
if ( event.keyCode === 13 || event.keyCode === 32 ) {
event.preventDefault();
self.toggler.trigger( 'click' ).next().focus();
}
});
self.button.click( function( event ) {
var me = $( this );
if ( me.hasClass( 'wp-picker-clear' ) ) {
self.element.val( '' );
if ( self.options.alpha ) {
self.toggler.css( 'backgroundColor', '' );
self.toggler.find('span').css( 'backgroundColor', '' );
} else {
self.toggler.css( 'backgroundColor', '' );
}
if ( $.isFunction( self.options.clear ) ) {
self.options.clear.call( this, event );
}
} else if ( me.hasClass( 'wp-picker-default' ) ) {
self.element.val( self.options.defaultColor ).change();
}
});
self.close_button.click( function( event ) {
event.preventDefault();
self.close();
});
},
close: function() {
this._super();
var self = this;
if ($.isFunction(self.options.onClose)) {
self.options.onClose.call(this);
}
},
});
/**
* Overwrite iris
*/
$.widget( 'a8c.iris', $.a8c.iris, {
_create: function() {
this._super();
// Global option for check is mode rbga is enabled
this.options.alpha = this.element.data( 'alpha' ) || false;
// Is not input disabled
if ( ! this.element.is( ':input' ) ) {
this.options.alpha = false;
}
if ( typeof this.options.alpha !== 'undefined' && this.options.alpha ) {
var self = this,
el = self.element,
_html = '<div class="iris-strip iris-slider iris-alpha-slider"><div class="iris-slider-offset iris-slider-offset-alpha"></div></div>',
aContainer = $( _html ).appendTo( self.picker.find( '.iris-picker-inner' ) ),
aSlider = aContainer.find( '.iris-slider-offset-alpha' ),
controls = {
aContainer: aContainer,
aSlider: aSlider
};
// Set default width for input reset
self.options.defaultWidth = el.width();
// Update width for input
if ( self._color._alpha < 1 || self._color.toString().indexOf('rgb') != 1 ) {
el.width( parseInt( self.options.defaultWidth+100 ) );
}
// Push new controls
$.each( controls, function( k, v ){
self.controls[k] = v;
});
// Change size strip and add margin for sliders
self.controls.square.css({'margin-right': '0'});
var emptyWidth = ( self.picker.width() - self.controls.square.width() - 20 ),
stripsMargin = emptyWidth/6,
stripsWidth = (emptyWidth/2) - stripsMargin;
$.each( [ 'aContainer', 'strip' ], function( k, v ) {
self.controls[v].width( stripsWidth ).css({ 'margin-left': stripsMargin + 'px' });
});
// Add new slider
self._initControls();
// For updated widget
self._change();
}
},
_initControls: function() {
this._super();
if ( this.options.alpha ) {
var self = this,
controls = self.controls;
controls.aSlider.slider({
orientation: 'vertical',
min: 0,
max: 100,
step: 1,
value: parseInt( self._color._alpha*100 ),
slide: function( event, ui ) {
// Update alpha value
self._color._alpha = parseFloat( ui.value/100 );
self._change.apply( self, arguments );
}
});
}
},
_change: function() {
this._super();
var self = this,
el = self.element;
if ( this.options.alpha ) {
var controls = self.controls,
alpha = parseInt( self._color._alpha*100 ),
color = self._color.toRgb(),
gradient = [
'rgb(' + color.r + ',' + color.g + ',' + color.b + ') 0%',
'rgba(' + color.r + ',' + color.g + ',' + color.b + ', 0) 100%'
],
defaultWidth = self.options.defaultWidth,
target = self.picker.closest('.wp-picker-container').find( '.wp-color-result' );
// Generate background slider alpha, only for CSS3 old browser fuck!! :)
controls.aContainer.css({ 'background': 'linear-gradient(to bottom, ' + gradient.join( ', ' ) + '), url(' + image + ')' });
if ( target.hasClass('wp-picker-open') ) {
// Update alpha value
controls.aSlider.slider( 'value', alpha );
/**
* Disabled change opacity in default slider Saturation ( only is alpha enabled )
* and change input width for view all value
*/
if ( self._color._alpha < 1 ) {
var style = controls.strip.attr( 'style' ).replace( /rgba\(([0-9]+,)(\s+)?([0-9]+,)(\s+)?([0-9]+)(,(\s+)?[0-9\.]+)\)/g, 'rgb($1$3$5)' );
controls.strip.attr( 'style', style );
el.width( parseInt( defaultWidth+100 ) );
} else {
el.width( defaultWidth );
}
}
}
var reset = el.data('reset-alpha') || false;
if ( reset ) {
self.picker.find( '.iris-palette-container' ).on( 'click.palette', '.iris-palette', function() {
self._color._alpha = 1;
self.active = 'external';
self._change();
});
}
},
_addInputListeners: function( input ) {
var self = this,
debounceTimeout = 700, // originally set to 100, but some user perceive it as "jumps to random colors at third digit"
callback = function( event ){
var color = new Color( input.val() ),
val = input.val();
input.removeClass( 'iris-error' );
// we gave a bad color
if ( color.error ) {
// don't error on an empty input
if ( val !== '' ) {
input.addClass( 'iris-error' );
}
} else {
if ( color.toString() !== self._color.toString() ) {
// let's not do this on keyup for hex shortcodes
if ( ! ( event.type === 'keyup' && val.match( /^[0-9a-fA-F]{3}$/ ) ) ) {
self._setOption( 'color', color.toString() );
}
}
}
};
input.on( 'change', callback ).on( 'keyup', self._debounce( callback, debounceTimeout ) );
// If we initialized hidden, show on first focus. The rest is up to you.
if ( self.options.hide ) {
input.one( 'focus', function() {
self.show();
});
}
},
_dimensions: function( reset ) {
// whatever size
var self = this,
opts = self.options,
controls = self.controls,
square = controls.square,
strip = self.picker.find( '.iris-strip' ),
squareWidth = '77.5%',
stripWidth = '12%',
totalPadding = 20,
innerWidth = opts.border ? opts.width - totalPadding : opts.width,
controlsHeight,
paletteCount = $.isArray( opts.palettes ) ? opts.palettes.length : self._palettes.length,
paletteMargin, paletteWidth, paletteContainerWidth;
if ( reset ) {
square.css( 'width', '' );
strip.css( 'width', '' );
self.picker.css( {width: '', height: ''} );
}
squareWidth = innerWidth * ( parseFloat( squareWidth ) / 100 );
stripWidth = innerWidth * ( parseFloat( stripWidth ) / 100 );
controlsHeight = opts.border ? squareWidth + totalPadding : squareWidth;
if (opts.diviColorpicker ) {
square.width( opts.width ).height( opts.height );
controlsHeight = opts.height;
} else {
square.width( squareWidth ).height( squareWidth );
}
strip.height( squareWidth ).width( stripWidth );
self.picker.css( { width: opts.width, height: controlsHeight } );
if ( ! opts.palettes ) {
return self.picker.css( 'paddingBottom', '' );
}
// single margin at 2%
paletteMargin = squareWidth * 2 / 100;
paletteContainerWidth = squareWidth - ( ( paletteCount - 1 ) * paletteMargin );
paletteWidth = paletteContainerWidth / paletteCount;
self.picker.find('.iris-palette').each( function( i ) {
var margin = i === 0 ? 0 : paletteMargin;
$( this ).css({
width: paletteWidth,
height: paletteWidth,
marginLeft: margin
});
});
self.picker.css( 'paddingBottom', paletteWidth + paletteMargin );
strip.height( paletteWidth + paletteMargin + squareWidth );
}
} );
}( jQuery ) );
// Auto Call plugin is class is color-picker
jQuery( document ).ready( function( $ ) {
$( '.color-picker' ).wpColorPicker();
} );
File diff suppressed because one or more lines are too long
@@ -1,529 +0,0 @@
/**
* wp-color-picker-alpha
*
* Version 1.0
* Copyright (c) 2017 Elegant Themes.
* Licensed under the GPLv2 license.
*
* Overwrite Automattic Iris for enabled Alpha Channel in wpColorPicker
* Only run in input and is defined data alpha in true
* Add custom colorpicker UI
*
* This is modified version made by Elegant Themes based on the work covered by
* the following copyright:
*
* wp-color-picker-alpha Version: 1.1
* https://github.com/23r9i0/wp-color-picker-alpha
* Copyright (c) 2015 Sergio P.A. (23r9i0).
* Licensed under the GPLv2 license.
*/
( function( $ ) {
// Variable for some backgrounds
var image = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAAHnlligAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAHJJREFUeNpi+P///4EDBxiAGMgCCCAGFB5AADGCRBgYDh48CCRZIJS9vT2QBAggFBkmBiSAogxFBiCAoHogAKIKAlBUYTELAiAmEtABEECk20G6BOmuIl0CIMBQ/IEMkO0myiSSraaaBhZcbkUOs0HuBwDplz5uFJ3Z4gAAAABJRU5ErkJggg==';
// html stuff for wpColorPicker copy of the original color-picker.js
var _before = '<button type="button" class="button wp-color-result" aria-expanded="false"><span class="wp-color-result-text"></span></button>',
_after = '<div class="wp-picker-holder" />',
_wrap = '<div class="wp-picker-container" />',
_button = '<input type="button" class="button button-small button-clear hidden" />',
_wrappingLabel = '<label></label>',
_wrappingLabelText = '<span class="screen-reader-text"></span>',
_close_button = '<button type="button" class="button button-confirm" />',
_close_button_icon = '<div style="fill: #3EF400; width: 25px; height: 25px; margin-top: -1px;"><svg viewBox="0 0 28 28" preserveAspectRatio="xMidYMid meet" shapeRendering="geometricPrecision"><g><path d="M19.203 9.21a.677.677 0 0 0-.98 0l-5.71 5.9-2.85-2.95a.675.675 0 0 0-.98 0l-1.48 1.523a.737.737 0 0 0 0 1.015l4.82 4.979a.677.677 0 0 0 .98 0l7.68-7.927a.737.737 0 0 0 0-1.015l-1.48-1.525z" fillRule="evenodd" /></g></svg></div>';
// Color picker label translation. By default, set label manually without translation.
var _defaultString = 'Default';
var _defaultAriaLabel = 'Select default color';
var _clearString = 'Clear';
var _clearAriaLabel = 'Clear color';
var _colorValue = 'Color value';
var _selectColor = 'Select Color';
if ('undefined' !== typeof wp && 'undefined' !== typeof wp.i18n && 'undefined' !== typeof wp.i18n.__) {
// Directly use wp.i18n if it exists. wp.i18n is added on 5.0.
var __ = wp.i18n.__;
_defaultString = __( 'Default' );
_defaultAriaLabel = __( 'Select default color' );
_clearString = __( 'Clear' );
_clearAriaLabel = __( 'Clear color' );
_colorValue = __( 'Color value' );
_selectColor = __( 'Select Color' );
} else if ('undefined' !== typeof wpColorPickerL10n && 'undefined' !== typeof wpColorPickerL10n.current) {
// Or use wpColorPickerL10n if it's still supported. wpColorPickerL10n is deprecated
// since 5.5.
_defaultString = wpColorPickerL10n.defaultString;
_defaultAriaLabel = wpColorPickerL10n.defaultAriaLabel;
_clearString = wpColorPickerL10n.clear,
_clearAriaLabel = wpColorPickerL10n.clearAriaLabel;
_colorValue = wpColorPickerL10n.defaultLabel;
_selectColor = wpColorPickerL10n.pick;
}
/**
* Overwrite Color
* for enable support rbga
*/
Color.fn.toString = function() {
if ( this._alpha < 1 )
return this.toCSS( 'rgba', this._alpha ).replace( /\s+/g, '' );
var hex = parseInt( this._color, 10 ).toString( 16 );
if ( this.error )
return '';
if ( hex.length < 6 ) {
for ( var i = 6 - hex.length - 1; i >= 0; i-- ) {
hex = '0' + hex;
}
}
return '#' + hex;
};
/**
* Overwrite wpColorPicker
*/
$.widget( 'wp.wpColorPicker', $.wp.wpColorPicker, {
_create: function() {
// Return early if Iris support is missing.
if ( ! $.support.iris ) {
return;
}
var self = this,
el = self.element;
// Override default options with options bound to the element.
$.extend( self.options, el.data() );
// Create a color picker which only allows adjustments to the hue.
if ( self.options.type === 'hue' ) {
return self._createHueOnly();
}
// Bind the close event.
self.close = self.close.bind(self);
self.initialValue = el.val();
// Add a CSS class to the input field.
el.addClass( 'wp-color-picker' );
/*
* Check if there's already a wrapping label, e.g. in the Customizer.
* If there's no label, add a default one to match the Customizer template.
*/
if ( ! el.parent( 'label' ).length ) {
// Wrap the input field in the default label.
el.wrap( _wrappingLabel );
// Insert the default label text.
self.wrappingLabelText = $( _wrappingLabelText )
.insertBefore( el )
.text( _colorValue );
}
/*
* At this point, either it's the standalone version or the Customizer
* one, we have a wrapping label to use as hook in the DOM, let's store it.
*/
self.wrappingLabel = el.parent();
// Wrap the label in the main wrapper.
self.wrappingLabel.wrap( _wrap );
// Store a reference to the main wrapper.
self.wrap = self.wrappingLabel.parent();
// Set up the toggle button and insert it before the wrapping label.
self.toggler = $( _before )
.insertBefore( self.wrappingLabel )
.css( { backgroundColor: self.initialValue } )
.attr( 'title', _selectColor )
.addClass( 'et-wp-color-result-updated');
// some strings were changed in recent colorpicker update, but we still need to use legacy strings in some places
if ( typeof et_pb_color_picker_strings !== 'undefined' ) {
self.toggler.attr( 'data-legacy_title', et_pb_color_picker_strings.legacy_pick ).attr( 'data-current', et_pb_color_picker_strings.legacy_current );
}
// Set the toggle button span element text.
self.toggler.find( '.wp-color-result-text' ).text( _selectColor );
// Set up the Iris container and insert it after the wrapping label.
self.pickerContainer = $( _after ).insertAfter( self.wrappingLabel );
// Store a reference to the Clear/Default button.
self.button = $( _button );
self.close_button = $( _close_button ).html( _close_button_icon );
if ( self.options.diviColorpicker ) {
el.after( self.close_button );
}
// Set up the Clear/Default button.
if ( self.options.defaultColor ) {
self.button
.addClass( 'wp-picker-default' )
.val( _defaultString )
.attr( 'aria-label', _defaultAriaLabel );
} else {
self.button
.addClass( 'wp-picker-clear' )
.val( _clearString )
.attr( 'aria-label', _clearAriaLabel );
}
// Wrap the wrapping label in its wrapper and append the Clear/Default button.
self.wrappingLabel
.wrap( '<span class="wp-picker-input-wrap hidden" />' )
.after( self.button );
/*
* The input wrapper now contains the label+input+Clear/Default button.
* Store a reference to the input wrapper: we'll use this to toggle
* the controls visibility.
*/
self.inputWrapper = el.closest( '.wp-picker-input-wrap' );
/*
* CSS for support < 4.9
*/
self.toggler.css({
'height': '24px',
'margin': '0 6px 6px 0',
'padding': '0 0 0 30px',
'font-size': '11px'
});
el.iris( {
target: self.pickerContainer,
hide: self.options.hide,
width: self.options.width,
height: self.options.height,
mode: self.options.mode,
palettes: self.options.palettes,
diviColorpicker: self.options.diviColorpicker,
change: function( event, ui ) {
if ( self.options.alpha ) {
self.toggler.css( {
'background-image' : 'url(' + image + ')',
'position' : 'relative'
} );
if ( self.toggler.find('span.color-alpha').length == 0 ) {
self.toggler.append('<span class="color-alpha" />');
}
self.toggler.find( 'span.color-alpha' ).css( {
'width' : '100%',
'height' : '100%',
'position' : 'absolute',
'top' : '0px',
'left' : '0px',
'border-top-left-radius' : '3px',
'border-bottom-left-radius' : '3px',
'background' : ui.color.toString()
} );
} else {
self.toggler.css( { backgroundColor: ui.color.toString() } );
}
// check for a custom cb
if ( 'function' === typeof self.options.change ) {
self.options.change.call( this, event, ui );
}
}
} );
el.val( self.initialValue );
self._addListeners();
// Force the color picker to always be closed on initial load.
if ( ! self.options.hide ) {
self.toggler.trigger('click');
}
},
_addListeners: function() {
var self = this;
// Prevent any clicks inside this widget from leaking to the top and closing it.
self.wrap.on( 'click.wpcolorpicker', function( event ) {
event.stopPropagation();
return false;
});
self.toggler.on('click', function() {
if ( self.toggler.hasClass( 'wp-picker-open' ) ) {
self.close();
} else {
self.open();
}
});
self.element.on( 'change', function( event ) {
// Empty or Error = clear
if ( $( this ).val() === '' || self.element.hasClass( 'iris-error' ) ) {
if ( self.options.alpha ) {
self.toggler.find( 'span.color-alpha' ).css( 'backgroundColor', '' );
} else {
self.toggler.css( 'backgroundColor', '' );
}
// fire clear callback if we have one
if ( 'function' === typeof self.options.clear )
self.options.clear.call( this, event );
}
} );
self.button.on( 'click', function( event ) {
if ( $( this ).hasClass( 'wp-picker-clear' ) ) {
self.element.val( '' );
if ( self.options.alpha ) {
self.toggler.find( 'span.color-alpha' ).css( 'backgroundColor', '' );
} else {
self.toggler.css( 'backgroundColor', '' );
}
if ( 'function' === typeof self.options.clear )
self.options.clear.call( this, event );
} else if ( $( this ).hasClass( 'wp-picker-default' ) ) {
self.element.val( self.options.defaultColor ).trigger('change');
}
});
self.close_button.on('click', function(event) {
event.preventDefault();
self.close();
});
},
close: function() {
this._super();
var self = this;
if ('function' === typeof self.options.onClose) {
self.options.onClose.call(this);
}
},
});
/**
* Overwrite iris
*/
$.widget( 'a8c.iris', $.a8c.iris, {
_create: function() {
this._super();
// Global option for check is mode rbga is enabled
this.options.alpha = this.element.data( 'alpha' ) || false;
// Is not input disabled
if ( ! this.element.is( ':input' ) ) {
this.options.alpha = false;
}
if ( typeof this.options.alpha !== 'undefined' && this.options.alpha ) {
var self = this,
el = self.element,
_html = '<div class="iris-strip iris-slider iris-alpha-slider"><div class="iris-slider-offset iris-slider-offset-alpha"></div></div>',
aContainer = $( _html ).appendTo( self.picker.find( '.iris-picker-inner' ) ),
aSlider = aContainer.find( '.iris-slider-offset-alpha' ),
controls = {
aContainer: aContainer,
aSlider: aSlider
};
// Set default width for input reset
self.options.defaultWidth = el.width();
// Update width for input
if ( self._color._alpha < 1 || self._color.toString().indexOf('rgb') != 1 ) {
el.width( parseInt( self.options.defaultWidth+100 ) );
}
// Push new controls
$.each( controls, function( k, v ){
self.controls[k] = v;
});
// Change size strip and add margin for sliders
self.controls.square.css({'margin-right': '0px'});
var emptyWidth = ( self.picker.width() - self.controls.square.width() - 20 ),
stripsMargin = emptyWidth/6,
stripsWidth = (emptyWidth/2) - stripsMargin;
$.each( [ 'aContainer', 'strip' ], function( k, v ) {
self.controls[v].width( stripsWidth ).css({ 'margin-left': stripsMargin + 'px' });
});
// Add new slider
self._initControls();
// For updated widget
self._change();
}
},
_initControls: function() {
this._super();
if ( this.options.alpha ) {
var self = this,
controls = self.controls;
controls.aSlider.slider({
orientation: 'vertical',
min: 0,
max: 100,
step: 1,
value: parseInt( self._color._alpha*100 ),
slide: function( event, ui ) {
// Update alpha value
self._color._alpha = parseFloat( ui.value/100 );
self._change.apply( self, arguments );
}
});
}
},
_change: function() {
this._super();
var self = this,
el = self.element;
if ( this.options.alpha ) {
var controls = self.controls,
alpha = parseInt( self._color._alpha*100 ),
color = self._color.toRgb(),
gradient = [
'rgb(' + color.r + ',' + color.g + ',' + color.b + ') 0%',
'rgba(' + color.r + ',' + color.g + ',' + color.b + ', 0) 100%'
],
defaultWidth = self.options.defaultWidth,
target = self.picker.closest('.wp-picker-container').find( '.wp-color-result' );
// Generate background slider alpha, only for CSS3 old browser fuck!! :)
controls.aContainer.css({ 'background': 'linear-gradient(to bottom, ' + gradient.join( ', ' ) + '), url(' + image + ')' });
if ( target.hasClass('wp-picker-open') ) {
// Update alpha value
controls.aSlider.slider( 'value', alpha );
/**
* Disabled change opacity in default slider Saturation ( only is alpha enabled )
* and change input width for view all value
*/
if ( self._color._alpha < 1 ) {
var style = controls.strip.attr( 'style' ).replace( /rgba\(([0-9]+,)(\s+)?([0-9]+,)(\s+)?([0-9]+)(,(\s+)?[0-9\.]+)\)/g, 'rgb($1$3$5)' );
controls.strip.attr( 'style', style );
el.width( parseInt( defaultWidth+100 ) );
} else {
el.width( defaultWidth );
}
}
}
var reset = el.data('reset-alpha') || false;
if ( reset ) {
self.picker.find( '.iris-palette-container' ).on( 'click.palette', '.iris-palette', function() {
self._color._alpha = 1;
self.active = 'external';
self._change();
});
}
},
_addInputListeners: function( input ) {
var self = this,
debounceTimeout = 700, // originally set to 100, but some user perceive it as "jumps to random colors at third digit"
callback = function( event ){
var color = new Color( input.val() ),
val = input.val();
input.removeClass( 'iris-error' );
// we gave a bad color
if ( color.error ) {
// don't error on an empty input
if ( val !== '' ) {
input.addClass( 'iris-error' );
}
} else {
if ( color.toString() !== self._color.toString() ) {
// let's not do this on keyup for hex shortcodes
if ( ! ( event.type === 'keyup' && val.match( /^[0-9a-fA-F]{3}$/ ) ) ) {
self._setOption( 'color', color.toString() );
}
}
}
};
input.on( 'change', callback ).on( 'keyup', self._debounce( callback, debounceTimeout ) );
// If we initialized hidden, show on first focus. The rest is up to you.
if ( self.options.hide ) {
input.one( 'focus', function() {
self.show();
});
}
},
_dimensions: function( reset ) {
// whatever size
var self = this,
opts = self.options,
controls = self.controls,
square = controls.square,
strip = self.picker.find( '.iris-strip' ),
squareWidth = '77.5%',
stripWidth = '12%',
totalPadding = 20,
innerWidth = opts.border ? opts.width - totalPadding : opts.width,
controlsHeight,
paletteCount = Array.isArray( opts.palettes ) ? opts.palettes.length : self._palettes.length,
paletteMargin, paletteWidth, paletteContainerWidth;
if ( reset ) {
square.css( 'width', '' );
strip.css( 'width', '' );
self.picker.css( {width: '', height: ''} );
}
squareWidth = innerWidth * ( parseFloat( squareWidth ) / 100 );
stripWidth = innerWidth * ( parseFloat( stripWidth ) / 100 );
controlsHeight = opts.border ? squareWidth + totalPadding : squareWidth;
if (opts.diviColorpicker ) {
square.width( opts.width ).height( opts.height );
controlsHeight = opts.height;
} else {
square.width( squareWidth ).height( squareWidth );
}
strip.height( squareWidth ).width( stripWidth );
self.picker.css({
width: 'number' === typeof opts.width ? opts.width + 'px' : opts.width,
height: 'number' === typeof controlsHeight ? controlsHeight + 'px' : controlsHeight,
});
if ( ! opts.palettes ) {
return self.picker.css( 'paddingBottom', '' );
}
// single margin at 2%
paletteMargin = squareWidth * 2 / 100;
paletteContainerWidth = squareWidth - ( ( paletteCount - 1 ) * paletteMargin );
paletteWidth = paletteContainerWidth / paletteCount;
self.picker.find('.iris-palette').each( function( i ) {
var margin = i === 0 ? 0 : paletteMargin;
$( this ).css({
width: paletteWidth + 'px',
height: paletteWidth + 'px',
marginLeft: margin + 'px',
});
});
self.picker.css( 'paddingBottom', paletteWidth + paletteMargin + 'px' );
strip.height( paletteWidth + paletteMargin + squareWidth );
}
} );
}( jQuery ) );
// Auto Call plugin is class is color-picker.
jQuery(function($) {
$('.color-picker').wpColorPicker();
});
File diff suppressed because one or more lines are too long
@@ -1,2 +0,0 @@
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=299)}({299:function(e,t,n){"use strict";(function(e){e((function(){e("body").on("click",".et_pb_prompt_dont_proceed",(function(){var t=e(this).closest(".et_pb_modal_overlay");return e("body").removeClass("et_pb_stop_scroll"),t.addClass("et_pb_modal_closing"),setTimeout((function(){t.remove()}),600),!1}))}))}).call(this,n(5))},5:function(e,t){e.exports=jQuery}});
//# sourceMappingURL=failure_notice.js.map
@@ -1,48 +0,0 @@
// External dependencies
import $ from 'jquery';
/**
* Toggle background-layout classname of current module and/or its child modules.
*
* @since 4.6.0
*
* @param {object} $module
* @param {bool} status
*/
export const toggleAllBackgroundLayoutClassnameOnSticky = ($module, status) => {
// Toggle background-layout classname if it is on current $module
if ($module.is($('[data-background-layout-sticky]'))) {
toggleBackgroundLayoutClassnameOnSticky($module, status);
}
// Toggle background-layout classname if it is child module of current module
if ($module.find('[data-background-layout-sticky]').length > 0) {
$module.find('[data-background-layout-sticky]').each(function() {
toggleBackgroundLayoutClassnameOnSticky($(this), status);
});
}
};
/**
* Toggle background-layout classname of current module.
*
* @since 4.6.0
*
* @param {object} $module
* @param {bool} status
*/
export const toggleBackgroundLayoutClassnameOnSticky = ($module, status) => {
const attrPrefix = status ? '-sticky' : '';
const allClassnames = 'et_pb_bg_layout_dark et_pb_bg_layout_light';
const layoutColor = $module.attr(`data-background-layout${attrPrefix}`);
const layoutClassname = `et_pb_bg_layout_${layoutColor}`;
let $target = $module;
// Switch the target element for some modules.
if ($module.hasClass('et_pb_slide')) {
$target = $module.closest('.et_pb_slider');
}
$target.removeClass(allClassnames).addClass(layoutClassname);
};
@@ -1,648 +0,0 @@
// Internal Dependencies
import { top_window } from '@core/admin/js/frame-helpers';
import { isBuilder } from '../utils/utils';
import { getClosestStickyModuleOffsetTop, isTargetStickyState } from '../utils/sticky';
(function($) {
const isBlockLayoutPreview = $('body').hasClass('et-block-layout-preview');
const $tbHeader = $('.et-l--header').first();
let tbHeaderMostLengthyFixedSectionHeight = 0;
// Modification of underscore's _.debounce()
// Underscore.js 1.8.3
// http://underscorejs.org
// (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
// Underscore may be freely distributed under the MIT license.
window.et_pb_debounce = function(func, wait, immediate) {
let timeout; let args; let context; let timestamp; let
result;
const now = Date.now || new Date().getTime();
var later = function() {
const last = now - timestamp;
if (last < wait && last >= 0) {
timeout = setTimeout(later, wait - last);
} else {
timeout = null;
if (! immediate) {
result = func.apply(context, args);
if (! timeout) context = args = null;
}
}
};
return function() {
context = this;
args = arguments;
timestamp = now;
const callNow = immediate && ! timeout;
if (! timeout) timeout = setTimeout(later, wait);
if (callNow) {
result = func.apply(context, args);
context = args = null;
}
return result;
};
};
if ($tbHeader.length) {
const $tbHeaderSections = $tbHeader.find('.et_builder_inner_content').children('.et_pb_section--fixed');
// Get the most tall header fixed section height
const et_pb_header_most_lengthy_fixed_section_height = et_pb_debounce(e => {
tbHeaderMostLengthyFixedSectionHeight = 0;
$.each($tbHeaderSections, function(index, section) {
let $sectionHeight = $(section).outerHeight(true);
if ($sectionHeight > tbHeaderMostLengthyFixedSectionHeight) {
tbHeaderMostLengthyFixedSectionHeight = $sectionHeight;
}
});
}, 300);
$(window).on('resize', et_pb_header_most_lengthy_fixed_section_height);
}
window.et_pb_smooth_scroll = function($target, $top_section, speed, easing) {
const targetOffsetTop = $target.offset().top;
const $window_width = $(window).width();
let $menu_offset = 0;
let $scroll_position = 0;
let $menuLeft = '';
let $menuRight = '';
let $fixedHeaderSection = $tbHeader.find('.et_pb_section');
// If the target is in sticky state there should be no scroll so we can bail early.
if (isTargetStickyState($target)) {
return;
}
if ($('body').hasClass('et_fixed_nav') && $window_width > 980) {
const topHeaderHeight = $('#top-header').outerHeight() || 0;
const mainHeaderHeight = $('#main-header').outerHeight() || 0;
$menu_offset = topHeaderHeight + mainHeaderHeight - 1;
} else {
$menu_offset = 0;
}
if ($('#wpadminbar').length && $window_width > 600) {
const wpAdminBarHeight = $('#wpadminbar').outerHeight() || 0;
$menu_offset += wpAdminBarHeight;
}
if ($tbHeader.length) {
// attach targeted section just under header (if) fixed section
if ($fixedHeaderSection.hasClass('et_pb_section--fixed')) {
$menuLeft = Math.ceil(parseFloat($fixedHeaderSection.css('left')));
$menuRight = Math.ceil(parseFloat($fixedHeaderSection.css('right')));
if ($window_width < 980) {
$menu_offset += 90;
}
}
if (0 === $menuLeft + $menuRight) {
$menu_offset += tbHeaderMostLengthyFixedSectionHeight;
}
}
// Calculate offset that needs to be added due to the existence of sticky module(s).
// This avoids smooth scroll to stop beneath sticky module.
const closestStickyOffsetTop = getClosestStickyModuleOffsetTop($target);
if (closestStickyOffsetTop) {
// if automatic sticky offset exist, add additional 40px offset for UX reason
$menu_offset += (closestStickyOffsetTop + 40);
}
// fix sidenav scroll to top
if ($top_section) {
$scroll_position = 0;
} else {
$scroll_position = targetOffsetTop - $menu_offset;
}
// set swing (animate's scrollTop default) as default value
if ('undefined' === typeof easing) {
easing = 'swing';
}
$('html, body').animate({ scrollTop: $scroll_position }, speed, easing);
};
window.et_pb_form_placeholders_init = function($form) {
$form.find('input:text, input[type="email"], input[type="url"], textarea').each((index, domEle) => {
const $et_current_input = jQuery(domEle);
const $et_comment_label = $et_current_input.siblings('label');
let et_comment_label_value = $et_current_input.siblings('label').text();
if ($et_comment_label.length) {
$et_comment_label.hide();
if ($et_current_input.siblings('span.required')) {
et_comment_label_value += $et_current_input.siblings('span.required').text();
$et_current_input.siblings('span.required').hide();
}
$et_current_input.val(et_comment_label_value);
}
}).on('focus', function() {
let et_label_text = jQuery(this).siblings('label').text();
if (jQuery(this).siblings('span.required').length) et_label_text += jQuery(this).siblings('span.required').text();
if (jQuery(this).val() === et_label_text) jQuery(this).val('');
}).on('blur', function() {
let et_label_text = jQuery(this).siblings('label').text();
if (jQuery(this).siblings('span.required').length) et_label_text += jQuery(this).siblings('span.required').text();
if ('' === jQuery(this).val()) jQuery(this).val(et_label_text);
});
};
window.et_duplicate_menu = function(menu, append_to, menu_id, menu_class, menu_click_event) {
append_to.each(function() {
const $this_menu = $(this);
let $cloned_nav;
// Bail early if menu has already been duplicated.
if ($this_menu.find(`#${menu_id}`).length) {
return;
}
// make this function work with existing menus, without cloning
if ('' !== menu) {
menu.clone().attr('id', menu_id).removeClass().attr('class', menu_class)
.appendTo($this_menu);
}
$cloned_nav = $this_menu.find('> ul');
$cloned_nav.find('.menu_slide').remove();
$cloned_nav.find('.et_pb_menu__logo-slot').remove();
$cloned_nav.find('li').first().addClass('et_first_mobile_item');
$cloned_nav.find('a').on('click', function() {
$(this).parents('.et_mobile_menu').siblings('.mobile_menu_bar').trigger('click');
});
if ('no_click_event' !== menu_click_event) {
if (isBuilder) {
$this_menu.off('click');
}
$this_menu.on('click', '.mobile_menu_bar', function() {
// Close all other open menus.
$('.mobile_nav.opened .mobile_menu_bar').not($(this)).trigger('click');
if ($this_menu.hasClass('closed')) {
$this_menu.removeClass('closed').addClass('opened');
$cloned_nav.stop().slideDown(500);
} else {
$this_menu.removeClass('opened').addClass('closed');
$cloned_nav.stop().slideUp(500);
}
return false;
});
}
});
$('#mobile_menu .centered-inline-logo-wrap').remove();
};
// remove placeholder text before form submission
window.et_pb_remove_placeholder_text = function($form) {
$form.find('input:text, textarea').each((index, domEle) => {
const $et_current_input = jQuery(domEle);
const $et_label = $et_current_input.siblings('label');
const et_label_value = $et_current_input.siblings('label').text();
if ($et_label.length && $et_label.is(':hidden')) {
if ($et_label.text() == $et_current_input.val()) $et_current_input.val('');
}
});
};
window.et_fix_fullscreen_section = function() {
const $et_window = isBlockLayoutPreview ? $(top_window) : $(window);
$('section.et_pb_fullscreen').each(function() {
const $this_section = $(this);
et_calc_fullscreen_section.bind($this_section);
$et_window.on('resize', et_calc_fullscreen_section.bind($this_section));
});
};
window.et_bar_counters_init = function($bar_item) {
if (! $bar_item.length) {
return;
}
$bar_item.css({
width: `${parseFloat($bar_item.attr('data-width'))}%`,
});
};
window.et_fix_pricing_currency_position = function($pricing_table) {
setTimeout(() => {
const $all_pricing_tables = typeof $pricing_table !== 'undefined' ? $pricing_table : $('.et_pb_pricing_table');
if (! $all_pricing_tables.length) {
return;
}
$all_pricing_tables.each(function() {
const $this_table = $(this);
const $price_container = $this_table.find('.et_pb_et_price');
const $currency = $price_container.length ? $price_container.find('.et_pb_dollar_sign') : false;
const $price = $price_container.length ? $price_container.find('.et_pb_sum') : false;
if (! $currency || ! $price) {
return;
}
// adjust the margin of currency sign to make sure it doesn't overflow the price
$currency.css({ marginLeft: `${- $currency.width()}px` });
});
}, 1);
};
window.et_pb_set_responsive_grid = function($grid_items_container, single_item_selector) {
setTimeout(() => {
const container_width = $grid_items_container.innerWidth();
const $grid_items = $grid_items_container.find(single_item_selector);
const item_width = $grid_items.outerWidth(true);
const last_item_margin = item_width - $grid_items.outerWidth();
const columns_count = Math.round((container_width + last_item_margin) / item_width);
let counter = 1;
let first_in_row = 1;
let $first_in_last_row = $();
$grid_items.removeClass('last_in_row first_in_row on_last_row');
$grid_items.filter(':visible').each(function() {
const $this_element = $(this);
if (! $this_element.hasClass('inactive')) {
if (first_in_row === counter) {
$this_element.addClass('first_in_row');
$first_in_last_row = $this_element;
} else if (0 === counter % columns_count) {
$this_element.addClass('last_in_row');
first_in_row = counter + 1;
}
counter++;
}
});
if ($first_in_last_row.length) {
const $module = $first_in_last_row.parents('.et_pb_module');
// set margin bottom to 0 if the gallery is the last module on the column
if ($module.is(':last-child')) {
const column = $first_in_last_row.parents('.et_pb_column')[0];
$(column).find('.et_pb_grid_item').removeClass('on_last_row');
// keep gutter margin if gallery has pagination
let pagination = $module.find('.et_pb_gallery_pagination');
if (0 === pagination.length) {
pagination = $module.find('.et_pb_portofolio_pagination');
}
if (0 === pagination.length || (pagination.length > 0 && ! pagination.is(':visible'))) {
if (columns_count > 1) {
$first_in_last_row.addClass('on_last_row');
}
$first_in_last_row.nextAll().addClass('on_last_row');
}
}
}
}, 1); // need this timeout to make sure all the css applied before calculating sizes
};
window.et_pb_set_tabs_height = function($tabs_module) {
if ('undefined' === typeof $tabs_module) {
$tabs_module = $('.et_pb_tabs');
}
if (! $tabs_module.length) {
return;
}
$tabs_module.each(function() {
const $tab_controls = $(this).find('.et_pb_tabs_controls');
const $all_tabs = $tab_controls.find('li');
let max_height = 0;
const small_columns = '.et_pb_column_1_3, .et_pb_column_1_4, .et_pb_column_3_8';
const in_small_column = $(this).parents(small_columns).length > 0;
const on_small_screen = parseFloat($(window).width()) < 768;
const vertically_stacked = in_small_column || on_small_screen;
if (vertically_stacked) {
$(this).addClass('et_pb_tabs_vertically_stacked');
}
// determine the height of the tallest tab
if ($all_tabs.length) {
// remove the height attribute if it was added to calculate the height correctly
$tab_controls.children('li').removeAttr('style');
$all_tabs.each(function() {
const tab_height = $(this).outerHeight();
if (vertically_stacked) {
return;
}
if (tab_height > max_height) {
max_height = tab_height;
}
});
}
if (0 !== max_height) {
// set the height of tabs container based on the height of the tallest tab
$tab_controls.children('li').css('height', `${max_height}px`);
}
});
};
window.et_pb_box_shadow_apply_overlay = function(el) {
const pointerEventsSupport = document.body.style.pointerEvents !== undefined
// For some reasons IE 10 tells that supports pointer-events, but it doesn't
&& (document.documentMode === undefined || document.documentMode >= 11);
if (pointerEventsSupport) {
$(el).each(function() {
if (! $(this).children('.box-shadow-overlay').length) {
$(this)
.addClass('has-box-shadow-overlay')
.prepend('<div class="box-shadow-overlay"></div>');
}
});
} else {
$(el).addClass('.et-box-shadow-no-overlay');
}
};
window.et_pb_init_nav_menu = function($et_menus) {
$et_menus.each(function() {
const $et_menu = $(this);
// don't attach event handlers several times to the same menu
if ($et_menu.data('et-is-menu-ready')) {
return;
}
$et_menu.find('li').on('mouseenter', function() {
window.et_pb_toggle_nav_menu($(this), 'open');
}).on('mouseleave', function() {
window.et_pb_toggle_nav_menu($(this), 'close');
});
// close all opened menus on touch outside the menu
$('body').on('touchend', event => {
if ($(event.target).closest('ul.nav, ul.menu').length < 1 && $('.et-hover').length > 0) {
window.et_pb_toggle_nav_menu($('.et-hover'), 'close');
}
});
// Dropdown menu adjustment for touch screen
$et_menu.find('li.menu-item-has-children').on('touchend', function(event) {
const $closest_li = $(event.target).closest('.menu-item');
// no need special processing if parent li doesn't have hidden child elements
if (! $closest_li.hasClass('menu-item-has-children')) {
return;
}
const $this_el = $(this);
const is_mega_menu_opened = $closest_li.closest('.mega-menu-parent.et-touch-hover').length > 0;
// open submenu on 1st tap
// open link on second tap
if ($this_el.hasClass('et-touch-hover') || is_mega_menu_opened) {
const href = $this_el.find('>a').attr('href');
if (typeof href !== 'undefined') { // if parent link is not empty then open the link
window.location = $this_el.find('>a').attr('href');
}
} else {
const $opened_menu = $(event.target);
const $already_opened_menus = $opened_menu.closest('.menu-item').siblings('.et-touch-hover');
// close the menu before opening new one
if ($opened_menu.closest('.et-touch-hover').length < 1) {
window.et_pb_toggle_nav_menu($('.et-hover'), 'close', 0);
}
$this_el.addClass('et-touch-hover');
if ($already_opened_menus.length > 0) {
const $submenus_in_already_opened = $already_opened_menus.find('.et-touch-hover');
// close already opened submenus to avoid overlaps
window.et_pb_toggle_nav_menu($already_opened_menus, 'close');
window.et_pb_toggle_nav_menu($submenus_in_already_opened, 'close');
}
// open new submenu
window.et_pb_toggle_nav_menu($this_el, 'open');
}
event.preventDefault();
event.stopPropagation();
});
$et_menu.find('li.mega-menu').each(function() {
const $li_mega_menu = $(this);
const $li_mega_menu_item = $li_mega_menu.children('ul').children('li');
const li_mega_menu_item_count = $li_mega_menu_item.length;
if (li_mega_menu_item_count < 4) {
$li_mega_menu.addClass(`mega-menu-parent mega-menu-parent-${li_mega_menu_item_count}`);
}
});
// mark the menu as ready
$et_menu.data('et-is-menu-ready', 'ready');
});
};
window.et_pb_toggle_nav_menu = function($element, state, delay) {
if ('open' === state) {
if (! $element.closest('li.mega-menu').length || $element.hasClass('mega-menu')) {
$element.addClass('et-show-dropdown');
$element.removeClass('et-hover').addClass('et-hover');
}
} else {
const closeDelay = typeof delay !== 'undefined' ? delay : 200;
$element.removeClass('et-show-dropdown');
$element.removeClass('et-touch-hover');
setTimeout(() => {
if (! $element.hasClass('et-show-dropdown')) {
$element.removeClass('et-hover');
}
}, closeDelay);
}
};
window.et_pb_apply_sticky_image_effect = function($sticky_image_el) {
const $row = $sticky_image_el.closest('.et_pb_row');
const $section = $row.closest('.et_pb_section');
const $column = $sticky_image_el.closest('.et_pb_column');
const sticky_class = 'et_pb_section_sticky';
const sticky_mobile_class = 'et_pb_section_sticky_mobile';
const $lastRowInSection = $section.children('.et_pb_row').last();
const $lastColumnInRow = $row.children('.et_pb_column').last();
const $lastModuleInColumn = $column.children('.et_pb_module').last();
// If it is not in the last row, continue
if (! $row.is($lastRowInSection)) {
return true;
}
$lastRowInSection.addClass('et-last-child');
// Make sure sticky image is the last element in the column
if (! $sticky_image_el.is($lastModuleInColumn)) {
return true;
}
// If it is in the last row, find the parent section and attach new class to it
if (! $section.hasClass(sticky_class)) {
$section.addClass(sticky_class);
}
$column.addClass('et_pb_row_sticky');
if (! $section.hasClass(sticky_mobile_class) && $column.is($lastColumnInRow)) {
$section.addClass(sticky_mobile_class);
}
};
/**
* Inject a <li> element in the middle of a menu for the purposes of the menu module's
* inline centered logo style.
*
* @since 4.0
*
* @param {object} menu
*
* @returns {object|null}
*/
window.et_pb_menu_inject_inline_centered_logo = function(menu) {
const $listItems = $(menu).find('nav > ul > li');
const index = Math.round($listItems.length / 2);
const li = window.et_pb_menu_inject_item(menu, index, true);
if (li) {
$(li).addClass('et_pb_menu__logo-slot');
}
return li;
};
/**
* Inject a <li> element at the start of a menu for the purposes of the menu module's
* additional icons.
*
* @since 4.0
*
* @param {object} menu
* @param {number} index
* @param {boolean} fromTheBeginning
*
* @returns {object|null}
*/
window.et_pb_menu_inject_item = function(menu, index, fromTheBeginning) {
fromTheBeginning = undefined === fromTheBeginning ? true : fromTheBeginning;
index = Math.max(index, 0);
const $list = $(menu).find('nav > ul').first();
if (0 === $list.length) {
return null;
}
const $listItems = $list.find('> li');
const $li = $('<li></li>');
if (0 === $listItems.length) {
$list.append($li);
} else {
let action = fromTheBeginning ? 'before' : 'after';
let $sibling = fromTheBeginning
? $listItems.eq(index)
: $listItems.eq(($listItems.length - 1) - index);
if (0 === $sibling.length) {
action = fromTheBeginning ? 'after' : 'before';
$sibling = fromTheBeginning ? $listItems.last() : $listItems.first();
}
$sibling[action]($li);
}
return $li.get(0);
};
/**
* Reposition menu module dropdowns.
* This is necessary due to mega menus relying on an upper wrapper's width but
* still needing to be position relative to their parent li.
*
* @since 4.0
*
* @returns {void}
*/
window.et_pb_reposition_menu_module_dropdowns = et_pb_debounce(menus => {
const $menus = menus ? $(menus) : $('.et_pb_menu, .et_pb_fullwidth_menu');
$menus.each(function() {
const $row = $(this).find('.et_pb_row').first();
if (0 === $row.length) {
return true; // = continue.
}
const offset = $row.offset().top;
const moduleClass = $(this).attr('class').replace(/^.*?(et_pb(?:_fullwidth)?_menu_\d+[^\s]*).*$/i, '$1');
const isUpwards = $(this).find('.et_pb_menu__menu ul').first().hasClass('upwards');
const selector = '.et_pb_menu__menu > nav > ul > li.mega-menu.menu-item-has-children';
let css = '';
$(this).find(selector).each(function() {
const $li = $(this);
const liId = $li.attr('class').replace(/^.*?(menu-item-\d+).*$/i, '$1');
const selector = `.${moduleClass} li.${liId} > .sub-menu`;
if (isUpwards) {
// Offset by 1px to ensure smooth mouse hover.
var linkOffset = Math.floor(offset + $row.outerHeight() - $li.offset().top) - 1;
css += `${selector}{ bottom: ${linkOffset.toString()}px !important; }`;
} else {
// Offset by 1px to ensure smooth mouse hover.
var linkOffset = Math.floor($li.offset().top + $li.outerHeight() - offset) - 1;
css += `${selector}{ top: ${linkOffset.toString()}px !important; }`;
}
});
let $style = $(`style.et-menu-style-${moduleClass}`).first();
if (0 === $style.length) {
$style = $('<style></style>');
$style.addClass('et-menu-style');
$style.addClass(`et-menu-style-${moduleClass}`);
$style.appendTo($('head'));
}
const oldCss = $style.html();
if (css !== oldCss) {
$style.html(css);
}
});
}, 200);
})(jQuery);
@@ -1,168 +0,0 @@
// External dependencies
import debounce from 'lodash/debounce';
import endsWith from 'lodash/endsWith';
import filter from 'lodash/filter';
import forEach from 'lodash/forEach';
import get from 'lodash/get';
import groupBy from 'lodash/groupBy';
import isArray from 'lodash/isArray';
import isEmpty from 'lodash/isEmpty';
import isObject from 'lodash/isObject';
import map from 'lodash/map';
import size from 'lodash/size';
// Internal dependencies
import * as DOM from '@frontend-builder/features/scroll-effects/fe/io/dom';
import { ETBuilderScrollEffects } from '@frontend-builder/features/scroll-effects';
import { convertTransforms } from '@frontend-builder/features/scroll-effects/vb/helpers';
import { fromObject } from '@frontend-builder/features/scroll-effects/entities/scroll-effect';
import ETBuilderOffsetsConst from '@frontend-builder/constants/et-builder-offsets-const';
import { Window } from '@frontend-builder/features/scroll-effects/stores/window';
import { top_window } from '@core/admin/js/frame-helpers';
import { getContentAreaSelector } from 'gutenberg/utils/selectors';
const isBlockEditor = $(top_window.document).find(getContentAreaSelector(top_window, true)).length > 0;
const isBuilder = isObject(window.ET_Builder) && size(window.ET_Builder) > 1 && ! isBlockEditor;
const getViewportWidth = () => jQuery(window).width();
const toItem = (effects, id) => ({ id, effects: (effects || []).map(fromObject) });
const getSelector = (step, id) => `body[data-scroll-step="${step}"] ${id}`;
const scrollEffects = new ETBuilderScrollEffects(DOM, getSelector);
let motionEffectsLoaded = false;
const getMotionElementsFE = () => {
const allMotionElements = window.et_pb_motion_elements || [];
// We are on the real FE, so load all the motion elements.
if (! isBuilder || isEmpty(allMotionElements)) {
return allMotionElements;
}
/**
* We're inside the Builder, but still need to render motion effects from the TB
* Get all the motion elements for TB parts of the layout.
*/
const breakpoints = ['desktop', 'tablet', 'phone'];
const tb_motion_elements = {};
forEach(breakpoints, breakpoint => {
tb_motion_elements[breakpoint] = filter(window.et_pb_motion_elements[breakpoint], el => (endsWith(el.id, '_tb_header') || endsWith(el.id, '_tb_body') || endsWith(el.id, '_tb_footer')));
});
return tb_motion_elements;
};
const toggleMotionElements = (state = 'hide') => {
const activeMotionElements = getMotionElementsFE();
const elementsList = get(activeMotionElements, 'desktop', []);
if (isEmpty(elementsList)) {
return;
}
forEach(elementsList, element => {
const $element = jQuery(element.id);
if ('hide' === state) {
$element.addClass('et-pb-before-scroll-animation');
} else {
$element.removeClass('et-pb-before-scroll-animation et_animated et-waypoint');
$element.addClass('et_had_animation');
}
});
};
/**
* @param {number} width
* @returns {string}
*/
const getDevice = width => {
if (width <= ETBuilderOffsetsConst.responsiveLandscape.phone) {
return 'phone';
}
if (width <= ETBuilderOffsetsConst.responsiveLandscape.tablet) {
return 'tablet';
}
return 'desktop';
};
const getChildren = (element, effects) => {
const childrenCount = parseInt(element.children_count);
const children = {};
if (childrenCount > 0) {
for (let i = 0; i < childrenCount; i++) {
const key = `.${element.module_type}_item_${element.module_index}_${i}`;
children[key] = effects;
}
}
return children;
};
/**
* @param {[object]} elements
* @param {string} device
*/
const updateItems = (elements, device) => {
const groupedElements = groupBy(elements[device] || [], 'id');
map(groupedElements, toItem)
.forEach(({ id, effects }) => {
if (! isEmpty(effects) && isArray(effects)) {
const element = get(groupedElements, [id, '0'], {});
const start = get(element, 'trigger_start', 'middle');
const end = start; // Use only one offset point right now. Update the value here if/when we add second point.
const motionTriggers = { start, end };
if ('on' === element.grid_motion) {
if (! element.child_slug) {
const children = getChildren(element, effects);
forEach(children, (childModule, id) => {
scrollEffects.add(id, childModule, motionTriggers);
});
}
} else {
const transforms = isEmpty(element.transforms) ? [] : convertTransforms(element.transforms);
scrollEffects.add(id, [...transforms, ...effects], motionTriggers);
}
} else {
scrollEffects.remove(id);
}
});
if (! motionEffectsLoaded) {
motionEffectsLoaded = true;
setTimeout(() => toggleMotionElements('show'), 200);
}
};
const activeMotionElements = getMotionElementsFE();
if (! isEmpty(activeMotionElements)) {
const $window = $(window);
const windowStore = new Window($window.width(), $window.height());
const elements = activeMotionElements;
let device = getDevice(getViewportWidth());
// Hide all the elements on page load so scroll effects applied smoothly
toggleMotionElements();
jQuery(window).on('load', debounce(() => updateItems(elements, device), 500));
jQuery(window).on('resize', debounce(() => windowStore.setWidth($window.width()).setHeight($window.height()), 500));
windowStore.addSizeChangeListener(() => {
const newDevice = getDevice(getViewportWidth());
if (newDevice !== device) {
device = newDevice;
updateItems(elements, device);
} else {
scrollEffects.refresh();
}
});
}
@@ -1,96 +0,0 @@
(function($) {
// Turn of all hrefs which point to another page
$('body').on('click', 'a', function(event) {
const href = $(this).attr('href');
const start = typeof href !== 'undefined' ? href.substr(0, 1) : '';
// Stop the link if it points to another URL
if (start !== '#' && start !== '') {
event.preventDefault();
// Display notification
$('.link-disabled').addClass('active');
}
});
// Prompt closing mechanism
$('body').on('click', '.et_pb_prompt_proceed', () => {
$('.link-disabled').removeClass('active');
});
// Build preview screen
const ET_PageBuilder_Preview = function(e) {
// Create form on the fly
const $form = $('<form id="preview-data-submission" method="POST" style="display: none;"></form>');
let value;
let { data } = e;
const msie = document.documentMode;
// Origins should be matched
if (e.origin !== et_preview_params.preview_origin) {
$('.et-pb-preview-loading').replaceWith($('<h4 />', { style: 'text-align: center;' }).html(et_preview_params.alert_origin_not_matched));
return;
}
// IE9 below fix. They have postMessage, but it has to be in string
if (typeof msie !== 'undefined' && msie < 10) {
data = JSON.parse(data);
}
// Ignore messages not coming from the builder.
if (! data || ! data.et_pb_preview_nonce) {
return;
}
// Loop postMessage data and append it to $form
for (const name in data) {
const $textarea = $('<textarea />', { name, style: 'display: none; ' }).val(data[name]);
$textarea.appendTo($form);
}
$form.append('<input type="submit" value="submit" style="display: none;" />');
$form.appendTo('.container');
// Submit the form
$('#preview-data-submission').trigger('submit');
};
// listen to data passed from builder
window.addEventListener('message', ET_PageBuilder_Preview, false);
/**
* Notify parent of parsed shortcode.
*/
const previewLoaded = $('#content > .content .et-pb-preview-loading').length !== 1;
if (previewLoaded && typeof parent !== 'undefined') {
/**
* There's no way to determine when the shortcode's JS has done parsing, so
* assume a safe fixed timeout before contacting parent's window.
*/
setTimeout(() => {
const output = {
html: $('#content > .content').html(),
stylesheets: [],
};
jQuery.each(window.location.search.substr(1).split('&'), (index, param) => {
const paramArray = param.split('=');
if (typeof paramArray[0] !== 'undefined' && typeof paramArray[1] !== 'undefined' && 'iframe_id' === paramArray[0]) {
output.iframe_id = paramArray[1];
}
});
/**
* Pass parsed shortcode's style hrefs to parent.
*/
$('link[rel="stylesheet"]').each((index, style) => {
output.stylesheets.push($(style).attr('href'));
});
parent.postMessage(output, window.location.origin);
}, 2000);
}
})(jQuery);
File diff suppressed because it is too large Load Diff
@@ -1,114 +0,0 @@
// External Dependencies
import difference from 'lodash/difference';
import forEach from 'lodash/forEach';
import get from 'lodash/get';
import isEqual from 'lodash/isEqual';
import keys from 'lodash/keys';
import pick from 'lodash/pick';
import $ from 'jquery';
// Internal dependencies
import ETScriptStickyElement from './sticky-element';
import ETScriptStickyStore from '../stores/sticky';
import {
isBFB,
isLBB,
isTB,
isVB,
} from '../utils/utils';
// Modules that use sticky element feature
const stickyInstances = {};
/**
* Initialize Sticky Elements;
* Front-end: loads settings from store (which is loaded from global variable passed
* via wp_localize_script())
* Builder: adds store listener which will listen to Sticky Element settings change
* pushed by builder's ETBuilderCustomCSSOutput component.
*
* @since 4.6.0
*/
if (isVB || isBFB || isTB || isLBB) {
/**
* Get Sticky Elements instances that need to be removed and unset from currently initialized
* stickyInstances list by incoming settings from store and stickyInstances.
*
* @since 4.6.0
*
* @returns {Array}
*/
function getUnsetStickyElements() {
// Get id of currently initialized ETScriptStickyElement
const currentInstanceIds = keys(stickyInstances);
// Get sticky settings from store
const stickyModules = ETScriptStickyStore.modules;
// Get id of settings from store
const stickyModuleIds = keys(stickyModules);
// If currently initialized ETScriptStickyElement id doesn't exist on store's settings id, it
// means the ETScriptStickyElement is either removed or has its sticky status removed
// (sticky_position attribute is set to `none`)
return difference(currentInstanceIds, stickyModuleIds);
}
/**
* Store's setting change listener callback.
*
* @since 4.6.0
*/
function onStickySettingsChange() {
// Loop over unset sticky elements then remove their instances
forEach(getUnsetStickyElements(), id => {
// End sticky state, and removed isSticky prop
stickyInstances[id].endSticky();
stickyInstances[id].setProp('isSticky', false);
// Remove ETScriptStickyElement listener
stickyInstances[id].removeListeners();
// Remove instance
delete stickyInstances[id];
});
// Loop over incoming sticky element settings from store
forEach(ETScriptStickyStore.modules, (settings, id) => {
// Check whether current setting has been initialized; if true, it means the sticky element
// is being updated
const currentStickyInstance = get(stickyInstances, id);
// Update sticky element
if (currentStickyInstance) {
// Check if current instance is equal to incoming settings from store. Current instance
// has less attribute than store's because some attribute are generated on the fly at store.
// Thus, omit attribute differences during comparison
const instanceSettingsKeys = keys(currentStickyInstance.getSettings());
const instanceInSettings = pick(settings, instanceSettingsKeys);
// If incoming settings are equal with current instance's settings, bail
if (isEqual(currentStickyInstance.getSettings(), instanceInSettings)) {
return;
}
// Update settings, then set initial props
stickyInstances[id].setSettings(settings, true);
} else {
// Create new ETScriptStickyElement instance
stickyInstances[id] = new ETScriptStickyElement(settings);
}
});
}
// Attach callback to store's settings change event
ETScriptStickyStore.addSettingsChangeListener(onStickySettingsChange);
} else {
// Need to wait until document is ready to get correct offset values
$(() => {
forEach(ETScriptStickyStore.modules, (settings, id) => {
// Create sticky element instance
stickyInstances[id] = new ETScriptStickyElement(settings);
});
});
}
@@ -1,2 +0,0 @@
!function(e){var n={};function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:r})},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,n){if(1&n&&(e=t(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(t.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var o in e)t.d(r,o,function(n){return e[n]}.bind(null,o));return r},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="",t(t.s=300)}({300:function(e,n,t){"use strict";(function(e){e((function(){var n=e(".wp-list-table"),t=e("li.wp-menu-open");n.find(".row-actions .edit, .row-actions .view").css("display","none"),t.find("a.wp-menu-open").removeClass("wp-menu-open wp-has-current-submenu"),t.find(".wp-submenu").addClass("wp-not-current-submenu"),t.removeClass("wp-menu-open wp-has-current-submenu"),n.on("click",".row-title",(function(){return e(this).closest("td").find(".row-actions .inline a").trigger("click"),!1})),n.on("click","td.column-posts a",(function(){return!1}))}))}).call(this,t(5))},5:function(e,n){e.exports=jQuery}});
//# sourceMappingURL=library_category.js.map
File diff suppressed because one or more lines are too long
@@ -1,2 +0,0 @@
!function(t){var e={};function n(i){if(e[i])return e[i].exports;var _=e[i]={i:i,l:!1,exports:{}};return t[i].call(_.exports,_,_.exports,n),_.l=!0,_.exports}n.m=t,n.c=e,n.d=function(t,e,i){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:i})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var _ in t)n.d(i,_,function(e){return t[e]}.bind(null,_));return i},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=302)}({302:function(t,e,n){"use strict";(function(t){var e=t("#et_settings_meta_box"),n=e.find(".et_pb_page_settings_container").first(),i=t(".et_pb_toggle_builder_wrapper"),_=t(".et_pb_page_setting"),s=t(".et_pb_page_layout_settings"),o=t("#formatdiv"),r=window.et_pb_options;i.hasClass("et_pb_builder_is_used")&&function(){var e=s.closest("#et_settings_meta_box").find(".et_pb_page_layout_settings");if(_.filter(":visible").length>1?(e.hide(),s.find(".et_pb_side_nav_settings").show()):("post"!==r.post_type&&"no"===r.is_third_party_post_type&&e.hide(),s.closest("#et_settings_meta_box").find(".et_pb_side_nav_settings").show(),s.closest("#et_settings_meta_box").find(".et_pb_single_title").show()),e.length>0){var n=e.find('option[value="et_full_width_page"]');n.length>0&&n.show()}if(o.length){var i=o.find('input[type="radio"]:checked').val();o.hide(),t(".et_divi_format_setting.et_divi_".concat(i,"_settings")).hide()}"project"===r.post_type&&s.closest("#et_settings_meta_box").find(".et_pb_project_nav").show()}(),n.hasClass("et_pb_page_settings_container--tb-has-header")&&e.find(".et_pb_nav_settings").hide(),n.hasClass("et_pb_page_settings_container--tb-has-body")&&e.find(".et_pb_page_layout_settings, .et_pb_single_title").hide(),0===n.height()&&e.hide()}).call(this,n(5))},5:function(t,e){t.exports=jQuery}});
//# sourceMappingURL=page-settings-metabox.js.map
@@ -1,2 +0,0 @@
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=303)}({303:function(e,t,n){"use strict";(function(e){e((function(){var t=e("#epanel-ajax-saving");e(".et_disable_memory_limit_increase").on("click",(function(n){n.preventDefault(),e.ajax({type:"POST",url:ajaxurl,data:{action:"et_reset_memory_limit_increase",et_builder_reset_memory_limit_nonce:et_reset_memory_limit_increase.et_builder_reset_memory_limit_nonce},beforeSend:function(e){t.addClass("et_loading").removeClass("success-animation"),t.fadeIn("fast")},success:function(n){t.removeClass("et_loading").removeClass("success-animation"),setTimeout((function(){t.fadeOut("slow")}),500),"success"===n&&(e(".et_disable_memory_limit_increase").closest(".epanel-box").hide(),t.addClass("success-animation"))}})}))}))}).call(this,n(5))},5:function(e,t){e.exports=jQuery}});
//# sourceMappingURL=reset_memory_limit_increase_setting.js.map
File diff suppressed because one or more lines are too long
@@ -1,238 +0,0 @@
// External dependencies
import { EventEmitter } from 'events';
import debounce from 'lodash/debounce';
import get from 'lodash/get';
// Internal dependencies
import {
maybeDecreaseEmitterMaxListeners,
maybeIncreaseEmitterMaxListeners,
registerFrontendComponent,
} from '../utils/utils';
const HEIGHT_CHANGE = 'height_change';
const WIDTH_CHANGE = 'width_change';
const DIMENSION_CHANGE = 'dimension_change';
// States
const states = {
height: 0,
width: 0,
};
/**
* Document store; track document height (at the moment) and its changes. Builder elements
* should listen and get this store's value instead of directly getting it from document.
* ETScriptDocumentStore is not exported; intentionally export its instance so there'll only be one
* ETScriptDocumentStore instance.
*
* @since 4.6.0
*/
class ETScriptDocumentStore extends EventEmitter {
/**
* ETScriptDocumentStore constructor.
*
* @since 4.6.0
*/
constructor() {
super();
this.setHeight(get(document, 'documentElement.offsetHeight'));
this.setWidth(get(document, 'documentElement.offsetWidth'));
}
/**
* Record document height.
*
* @since 4.6.0
*
* @param {number} height
*
* @returns {Window}
*/
setHeight = height => {
if (height === states.height) {
return this;
}
states.height = height;
this.emit(HEIGHT_CHANGE);
this.emit(DIMENSION_CHANGE);
return this;
};
/**
* Record document width.
*
* @since 4.6.0
*
* @param {number} width
*
* @returns {Window}
*/
setWidth = width => {
if (width === states.width) {
return this;
}
states.width = width;
this.emit(WIDTH_CHANGE);
this.emit(DIMENSION_CHANGE);
return this;
};
/**
* Get recorded document height.
*
* @since 4.6.0
*
* @returns {number}
*/
get height() {
return states.height;
}
/**
* Get recorded document width.
*
* @since 4.6.0
*
* @returns {number}
*/
get width() {
return states.width;
}
/**
* Add document dimension change event listener.
*
* @since 4.6.0
*
* @param {Function} callback
*
* @returns {Window}
*/
addDimensionChangeListener = callback => {
maybeIncreaseEmitterMaxListeners(this, DIMENSION_CHANGE);
this.on(DIMENSION_CHANGE, callback);
return this;
};
/**
* Remove document dimension change event listener.
*
* @since 4.6.0
*
* @param {Function} callback
*
* @returns {Window}
*/
removeDimensionChangeListener = callback => {
this.removeListener(DIMENSION_CHANGE, callback);
maybeDecreaseEmitterMaxListeners(this, DIMENSION_CHANGE);
return this;
};
/**
* Add document height change event listener.
*
* @since 4.6.0
*
* @param {Function} callback
*
* @returns {Window}
*/
addHeightChangeListener = callback => {
maybeIncreaseEmitterMaxListeners(this, HEIGHT_CHANGE);
this.on(HEIGHT_CHANGE, callback);
return this;
};
/**
* Remove document height change event listener.
*
* @since 4.6.0
*
* @param {Function} callback
*
* @returns {Window}
*/
removeHeightChangeListener = callback => {
this.removeListener(HEIGHT_CHANGE, callback);
maybeDecreaseEmitterMaxListeners(this, HEIGHT_CHANGE);
return this;
};
/**
* Add document width change event listener.
*
* @since 4.6.0
*
* @param {Function} callback
*
* @returns {Window}
*/
addWidthChangeListener = callback => {
maybeIncreaseEmitterMaxListeners(this, WIDTH_CHANGE);
this.on(WIDTH_CHANGE, callback);
return this;
};
/**
* Remove document width change event listener.
*
* @since 4.6.0
*
* @param {Function} callback
*
* @returns {Window}
*/
removeWidthChangeListener = callback => {
this.removeListener(WIDTH_CHANGE, callback);
maybeDecreaseEmitterMaxListeners(this, WIDTH_CHANGE);
return this;
};
}
// Create document store instance
const documentStoreInstance = new ETScriptDocumentStore();
/**
* Event's function callback to update document store's props
*
* @since 4.6.2
*/
function updateDocumentStoreProps() {
const documentHeight = get(document, 'documentElement.offsetHeight');
const documentWidth = get(document, 'documentElement.offsetWidth');
// Store automatically ignore if given height value is equal to the current one; so this is fine
documentStoreInstance.setHeight(documentHeight).setWidth(documentWidth);
}
// Listen to document's DOM change, debounce its callback, and update store's props
const documentObserver = new MutationObserver(debounce(updateDocumentStoreProps, 50));
// Observe document change
// @todo probably plug this on only when necessary
// @todo also enable to plug this off
documentObserver.observe(document, {
attributes: true,
childList: true,
subtree: true,
});
// Update document store properties when Divi's fixed header transition is completed
window.addEventListener('ETDiviFixedHeaderTransitionEnd', updateDocumentStoreProps);
// Register store instance as component to be exposed via global object
registerFrontendComponent('stores', 'document', documentStoreInstance);
// Export store instance.
// IMPORTANT: For uniformity, import this as ETScriptDocumentStore
export default documentStoreInstance;
@@ -1,946 +0,0 @@
// External dependencies
import { EventEmitter } from 'events';
import assign from 'lodash/assign';
import cloneDeep from 'lodash/cloneDeep';
import compact from 'lodash/compact';
import filter from 'lodash/filter';
import forEach from 'lodash/forEach';
import get from 'lodash/get';
import has from 'lodash/has';
import head from 'lodash/head';
import includes from 'lodash/includes';
import isEqual from 'lodash/isEqual';
import isFunction from 'lodash/isFunction';
import isObject from 'lodash/isObject';
import isUndefined from 'lodash/isUndefined';
import keys from 'lodash/keys';
import last from 'lodash/last';
import map from 'lodash/map';
import mapKeys from 'lodash/mapKeys';
import set from 'lodash/set';
import size from 'lodash/size';
import slice from 'lodash/slice';
import sortBy from 'lodash/sortBy';
import $ from 'jquery';
// Internal dependencies
import {
isOrHasValue,
} from '@frontend-builder/utils/responsive-options-pure';
import {
top_window,
} from '@core-ui/utils/frame-helpers';
import ETScriptDocumentStore from './document';
import ETScriptWindowStore from './window';
import {
getOffsets,
isBFB,
isBuilder,
isDiviTheme,
isExtraTheme,
isLBB,
isTB,
isVB,
maybeDecreaseEmitterMaxListeners,
maybeIncreaseEmitterMaxListeners,
registerFrontendComponent,
} from '../utils/utils';
import {
filterInvalidModules,
getLimit,
} from '../utils/sticky';
// Event Constants
const SETTINGS_CHANGE = 'settings_change';
// Variables
const $body = $('body');
const hasFixedNav = $body.hasClass('et_fixed_nav');
/**
* Saved sticky elements. In FE, this means all the sticky settings that exist on current page.
* In VB (and other builder context) this means sticky settings that exist on current page but
* is rendered outside current builder type. Removed nested sticky module (sticky inside another
* sticky module) from the module list.
*
* @since 4.6.0
*
* @type {object}
*/
const savedStickyElements = filterInvalidModules(cloneDeep(window.et_pb_sticky_elements));
/**
* Defaults of known non module elements which its stickiness needs to be considered.
*
* @since 4.6.0
*
* @type {object}
*/
const elementsDefaults = {
wpAdminBar: {
id: 'wpAdminBar',
selector: '#wpadminbar',
exist: false,
height: 0,
window: 'top',
condition: () => {
// Admin bar doesn't have fixed position in smaller breakpoint
const isPositionFixed = 'fixed' === top_window.jQuery(elements.wpAdminBar.selector).css('position');
// When Responsive View's control is visible, admin bar offset becomes irrelevant. Note:
// At this point the `height` value might not be updated yet, so manually get the height
// value via `getHeight()` method.
const hasVbAppFramePaddingTop = elements.builderAppFramePaddingTop.getHeight() > 0;
return ! hasVbAppFramePaddingTop && ! isTB && ! isLBB && isPositionFixed;
},
},
diviFixedPrimaryNav: {
id: 'diviPrimaryNav',
selector: '#main-header',
exist: false,
height: 0,
window: 'app',
condition: () => {
// Divi Theme has fixed nav. Note: vertical header automatically removes .et_fixed_nav
// classname so it is fine just to test fixed nav state against .et_fixed_nav classname only
const hasFixedNavBodyClass = isDiviTheme && hasFixedNav;
// Check for element's existence
const isNavExist = $(elements.diviFixedPrimaryNav.selector).length > 0;
// Primary nav is doesn't have fixed position in smaller breakpoint
const isPositionFixed = 'fixed' === $(elements.diviFixedPrimaryNav.selector).css('position');
return hasFixedNavBodyClass && isNavExist && isPositionFixed;
},
getHeight: () => {
const $mainHeader = $(elementsDefaults.diviFixedPrimaryNav.selector);
// Bail if this isn't Divi
if (! isDiviTheme && 1 > $mainHeader.length) {
return 0;
}
// Clone header
const $clone = $mainHeader.clone();
// Emulate fixed header state. Fixed header state is emulated as soon as the window is
// scrolled so it is safe to assume that any sticky module on its sticky state will "meet"
// header on its fixed state; this will avoid unwanted "jump" effect that happens because
// fixed header has 400ms transition which could be slower than scroll speed; The fixed header
// state also adds negative margin top state to #page-container which triggers document
// dimension change event. Also add classname which will ensure that this clone won't
// be visible to end user even if we only render it for a split second to avoid issues
$clone.addClass('et-fixed-header et-script-temporary-measurement');
// Add it to layout so its dimension can be measured
$mainHeader.parent().append($clone);
// Measure the fixed header height
const height = $clone.outerHeight();
// Immediately remove the cloned DOM from layout
$clone.remove();
return parseFloat(height);
},
},
diviFixedSecondaryNav: {
id: 'diviPrimaryNav',
selector: '#top-header',
exist: false,
height: 0,
window: 'app',
condition: () => {
// Divi Theme has fixed nav. Note: vertical header automatically removes .et_fixed_nav
// classname so it is fine just to test fixed nav state against .et_fixed_nav classname only
const hasFixedNavBodyClass = isDiviTheme && hasFixedNav;
// Check for element's existence
const isNavExist = $(elements.diviFixedSecondaryNav.selector).length > 0;
// Primary nav is doesn't have fixed position in smaller breakpoint
const isPositionFixed = 'fixed' === $(elements.diviFixedSecondaryNav.selector).css('position');
return hasFixedNavBodyClass && isNavExist && isPositionFixed;
},
},
extraFixedPrimaryNav: {
id: 'extraFixedPrimaryNav',
selector: '#main-header',
exist: false,
height: 0,
window: 'app',
condition: () => {
if (! isObject(ETScriptWindowStore) || ! isExtraTheme) {
return false;
}
// Extra Theme has fixed nav.
const hasFixedNavBodyClass = isExtraTheme && hasFixedNav;
// Check for element's existence.
const isNavExist = $(elements.extraFixedPrimaryNav.selector).length > 0;
// Extra has its own breakpoint for fixed nav. Detecting computed style is most likely fail
// because retrieved value is always one step behind before the computed style result is retrieved
const isPositionFixed = 1024 <= (ETScriptWindowStore.width + ETScriptWindowStore.verticalScrollBar);
return hasFixedNavBodyClass && isNavExist && isPositionFixed;
},
getHeight: () => {
const $mainHeader = $(elementsDefaults.extraFixedPrimaryNav.selector);
// Bail if this isn't Extra
if (! isExtraTheme && 1 > $mainHeader.length) {
return 0;
}
// Clone header
const $clone = $mainHeader.clone();
// Emulate fixed header state. Fixed header state is emulated as soon as the window is
// scrolled so it is safe to assume that any sticky module on its sticky state will "meet"
// header on its fixed state; this will avoid unwanted "jump" effect that happens because
// fixed header has 500ms transition which could be slower than scroll speed; The fixed header
// state also adds negative margin top state to #page-container which triggers document
// dimension change event. Also add classname which will ensure that this clone won't
// be visible to end user even if we only render it for a split second to avoid issues
$clone.addClass('et-fixed-header et-script-temporary-measurement');
// Add it to layout so its dimension can be measured
$mainHeader.parent().append($clone);
// Measure the fixed header height
const height = $clone.outerHeight();
// Immediately remove the cloned DOM from layout
$clone.remove();
return parseFloat(height);
},
},
builderAppFramePaddingTop: {
id: 'builderAppFramePaddingTop',
selector: isBFB ? '#et-bfb-app-frame' : '#et-fb-app-frame',
exist: false,
height: 0,
window: 'top',
getHeight: () => {
const selector = elements.builderAppFramePaddingTop.selector;
const cssProperty = isBFB ? 'marginTop' : 'paddingTop';
const paddingTop = top_window.jQuery(selector).css(cssProperty);
return parseFloat(paddingTop);
}
},
tbHeader: {
id: 'et-tb-branded-modal__header',
selector: '.et-tb-branded-modal__header',
exist: false,
height: 0,
window: 'top',
},
lbbHeader: {
id: 'et-block-builder-modal--header',
selector: '.et-block-builder-modal--header',
exist: false,
height: 0,
window: 'top',
},
gbHeader: {
id: 'edit-post-header',
// This selector exist on WP 5.4 and below; hence these are used instead of `.block-editor-editor-skeleton__header`
selector: '.edit-post-header',
exist: false,
height: 0,
window: 'top',
},
gbFooter: {
id: 'block-editor-editor-skeleton__footer',
selector: '.block-editor-editor-skeleton__footer',
exist: false,
height: 0,
window: 'top',
},
gbComponentsNoticeList: {
id: 'components-notice-list',
selector: '.components-notice-list',
exist: false,
height: 0,
window: 'top',
multiple: true,
},
};
/**
* Known non module elements which its stickiness needs to be considered.
*
* @since 4.6.0
*
* @type {object}
*/
const elements = cloneDeep(elementsDefaults);
// States
/**
* Hold all sticky elements modules' properties.
*
* @since 4.6.0
*
* @type {object}
*/
let modules = {};
/**
* Sticky Elements store.
*
* This store stores selected properties of all sticky elements on the page so a sticky element
* can use other sticky element's calculated value quickly.
*
* @since 4.6.0
*/
class ETScriptStickyStore extends EventEmitter {
/**
* ETScriptStickyStore constructor.
*
* @since 4.6.0
*/
constructor() {
super();
// Load modules passed via global variable from server via wp_localize_script()
assign(modules, savedStickyElements);
// Caculate top/bottom offsetModules which are basically list of sticky elements that need
// to be considered for additional offset calculation when `Offset From Surrounding Sticky Elements`
// option is toggled `on`
this.generateOffsetModules();
// Calculate known elements' properties. This needs to be done after DOM is ready
if (isVB) {
$(window).on('et_fb_init_app_after', () => {
this.setElementsProps();
});
} else {
$(() => {
this.setElementsProps();
});
}
// Some props need to be updated when document height is changed (eg. fixed nav's height)
ETScriptDocumentStore.addHeightChangeListener(this.onDocumentHeightChange);
// Builder specific event callback
if (isBuilder) {
// Event callback once the builder has been mounted
$(window).on('et_fb_root_did_mount', this.onBuilderDidMount);
// Listen to builder change if current window is builder window
window.addEventListener('ETBuilderStickySettingsSyncs', this.onBuilderSettingsChange);
}
}
/**
* Get registered modules.
*
* @since 4.6.0
*
* @type {object}
*/
get modules() {
return modules;
}
/**
* List of builder options (that is used by sticky elements) that has responsive mode.
*
* @since 4.6.0
*
* @returns {Array}
*/
get responsiveOptions() {
const options = [
'position',
'topOffset',
'bottomOffset',
'topLimit',
'bottomLimit',
'offsetSurrounding',
'transition',
'topOffsetModules',
'bottomOffsetModules',
];
return options;
}
/**
* Update selected module / elements prop on document height change.
*
* @since 4.6.0
*/
onDocumentHeightChange = () => {
// Update Divi fixed nav height property. Divi fixed nav height change when it enters its sticky state
// thus making it having different height when sits on top of viewport and during window scroll
if (this.getElementProp('diviFixedPrimaryNav', 'exist', false)) {
const getHeight = this.getElementProp('diviFixedPrimaryNav', 'getHeight');
this.setElementProp('diviFixedPrimaryNav', 'height', getHeight());
}
// Update Extra's fixed height property. Extra fixed nav height changes as the window is scrolled
if (this.getElementProp('extraFixedPrimaryNav', 'exist', false)) {
const getExtraFixedMainHeaderHeight = this.getElementProp('extraFixedPrimaryNav', 'getHeight');
this.setElementProp('extraFixedPrimaryNav', 'height', getExtraFixedMainHeaderHeight());
}
if (this.getElementProp('builderAppFramePaddingTop', 'exist', false)) {
this.setElementHeight('builderAppFramePaddingTop');
}
}
/**
* Builder did mount listener callback.
*
* @since 4.6.0
*/
onBuilderDidMount = () => {
const stickyOnloadModuleKeys = keys(window.et_pb_sticky_elements);
const stickyMountedModuleKeys = keys(this.modules);
// Has sticky elements but builder has no saved sticky module; sticky element on current
// page is outside current builder (eg. page builder has with no sticky element saved but
// TB header of current page has sticky element). Need to emit change to kickstart the stick
// element initialization and generating offset modules
if (stickyOnloadModuleKeys.length > 0 && isEqual(stickyOnloadModuleKeys, stickyMountedModuleKeys)) {
this.onBuilderSettingsChange(undefined, true);
}
}
/**
* Builder settings change listener callback.
*
* @since 4.6.0
*
* @param {object} event
* @param {bool} forceUpdate
*/
onBuilderSettingsChange = (event, forceUpdate = false) => {
const settings = get(event, 'detail.settings');
if (isEqual(settings, this.modules) && ! forceUpdate) {
return;
}
// Update sticky settings. Removed nested sticky module (sticky inside another
// sticky module) from the module list.
modules = filterInvalidModules(cloneDeep(settings), modules);
// Append saved sticky elements settings which is rendered outside of current builder
// type because it won't be generated by current builder's components
assign(modules, savedStickyElements);
// Generate offset modules
this.generateOffsetModules();
this.emit(SETTINGS_CHANGE);
}
/**
* Get id of all modules.
*
* @since 4.6.0
*
* @type {object} modules
*
* @returns {Array}
*/
getModulesId = modules => map(modules, module => module.id)
/**
* Get modules based on its rendering position; also consider its offset surrounding setting if needed.
*
* @since 4.6.0
* @param {string} top|bottom
* @param position
* @param offsetSurrounding
* @param {string|bool} on|off|false When false, ignore offset surrounding value.
* @returns {bool}
*/
getModulesByPosition = (position, offsetSurrounding = false) => filter(modules, (module, id) => {
// Check offset surrounding value; if param set to `false`, ignore it. If `on`|`off`, only
// pass module that has matching value
const isOffsetSurrounding = ! offsetSurrounding ? true : isOrHasValue(module.offsetSurrounding, offsetSurrounding);
return includes(['top_bottom', position], this.getProp(id, 'position')) && isOffsetSurrounding;
})
/**
* Sort modules from top to down based on offset prop. Passed module has no id or index prop so
* offset which visually indicate module's position in the page will do.
*
* @since 4.6.0
*/
sortModules = () => {
const storeModules = this.modules;
const modulesSize = size(storeModules);
// Return modules as-is if it is less than two modules; no need to sort it
if (modulesSize < 2) {
return storeModules;
}
// There's no index whatsoever, but offset's top and left indicates module's position
const sortedModules = sortBy(storeModules, [
module => module.offsets.top,
module => module.offsets.left,
]);
// sortBy returns array type value; remap id as object key
const remappedModules = mapKeys(sortedModules, module => module.id);
modules = cloneDeep(remappedModules);
}
/**
* Set prop value.
*
* @since 4.6.0
*
* @param {string} id Need to be unique.
* @param {string} name
* @param {string} value
*/
setProp = (id, name, value) => {
// Skip updating if the id isn't exist
if (! has(modules, id) || isUndefined(id)) {
return;
}
const currentValue = this.getProp(id, name);
// Skip updating prop if the value is the same
if (currentValue === value) {
return;
}
set(modules, `${id}.${name}`, value);
}
/**
* Get prop.
*
* @since 4.6.0
* @param {string} id
* @param {string} name
* @param {mixed} defaultValue
* @param returnCurrentBreakpoint
* @param {bool} return
* @returns {mixed}
*/
getProp = (id, name, defaultValue, returnCurrentBreakpoint = true) => {
const value = get(modules, `${id}.${name}`, defaultValue);
const isResponsive = returnCurrentBreakpoint
&& isObject(value)
&& has(value, 'desktop')
&& includes(this.responsiveOptions, name);
return isResponsive ? get(value, get(ETScriptWindowStore, 'breakpoint', 'desktop'), defaultValue) : value;
}
/**
* Set known elements' props.
*
* @since 4.6.0
*/
setElementsProps = () => {
forEach(elements, (settings, name) => {
if (! has(settings, 'window')) {
return;
}
if (has(settings, 'condition') && isFunction(settings.condition) && ! settings.condition()) {
// Reset props if it fails on condition check
this.setElementProp(name, 'exist', get(elementsDefaults, `${name}.exist`, false));
this.setElementProp(name, 'height', get(elementsDefaults, `${name}.height`, 0));
return;
}
const currentWindow = 'top' === this.getElementProp(name, 'window') ? top_window : window;
const $element = currentWindow.jQuery(settings.selector);
const hasElement = $element.length > 0 && $element.is(':visible');
if (hasElement) {
this.setElementProp(name, 'exist', hasElement);
this.setElementHeight(name);
}
});
}
/**
* Set known element prop value.
*
* @since 4.6.0
*
* @param {string} id Need to be unique.
* @param {string} name
* @param {string} value
*/
setElementProp = (id, name, value) => {
const currentValue = this.getElementProp(id, name);
// Skip updating prop if the value is the same
if (currentValue === value) {
return;
}
set(elements, `${id}.${name}`, value);
}
/**
* Get known element prop.
*
* @since 4.6.0
*
* @param {string} id
* @param {string} name
* @param {mixed} defaultValue
*
* @returns {mixed}
*/
getElementProp = (id, name, defaultValue) => get(elements, `${id}.${name}`, defaultValue)
/**
* Set element height.
*
* @since 4.6.0
*
* @param {string} name
*/
setElementHeight = name => {
const selector = this.getElementProp(name, 'selector');
const currentWindow = 'top' === this.getElementProp(name, 'window', 'app') ? top_window : window;
const $selector = currentWindow.jQuery(selector);
let height = 0;
forEach($selector, item => {
const getHeight = this.getElementProp(name, 'getHeight', false);
if (isFunction(getHeight)) {
height += getHeight();
} else {
height += currentWindow.jQuery(item).outerHeight();
}
});
this.setElementProp(name, 'height', parseInt(height));
}
/**
* Generate offset modules for offset surrounding option.
*
* @since 4.6.0
*/
generateOffsetModules = () => {
// Get module's width, height, and offsets. These are needed to calculate offset module's
// adjacent column adjustment. stickyElement will update this later on its initialization
// This needs to be on earlier and different loop than the one below for generating offset
// modules because in builder the modules need to be sorted from top to down first
forEach(this.modules, (module, id) => {
const $module = $(this.getProp(id, 'selector'));
const moduleWidth = parseInt($module.outerWidth());
const moduleHeight = parseInt($module.outerHeight());
const moduleOffsets = getOffsets($module, moduleWidth, moduleHeight);
// Only update dimension props if module isn't on sticky state
if (! this.isSticky(id)) {
this.setProp(id, 'width', moduleWidth);
this.setProp(id, 'height', moduleHeight);
this.setProp(id, 'offsets', moduleOffsets);
}
// Set limits
const position = this.getProp(id, 'position', 'none');
const isStickyBottom = includes(['bottom', 'top_bottom'], position);
const isStickyTop = includes(['top', 'top_bottom'], position);
if (isStickyBottom) {
const topLimit = this.getProp(id, 'topLimit');
const topLimitSettings = getLimit($module, topLimit);
this.setProp(id, 'topLimitSettings', topLimitSettings);
}
if (isStickyTop) {
const bottomLimit = this.getProp(id, 'bottomLimit');
const bottomLimitSettings = getLimit($module, bottomLimit);
this.setProp(id, 'bottomLimitSettings', bottomLimitSettings);
}
});
// Sort modules in builder to ensure top to bottom module order for generating offset modules
if (isBuilder) {
this.sortModules();
}
const { modules } = this;
const modulesSize = size(modules);
const topPositionModules = this.getModulesByPosition('top', 'on');
const topPositionModulesId = this.getModulesId(topPositionModules);
const bottomPositionModules = this.getModulesByPosition('bottom', 'on');
const bottomPositionModulesId = this.getModulesId(bottomPositionModules);
// Capture top/bottom offsetModules updates for later loop
const offsetModulesUpdates = [];
forEach(modules, (module, id) => {
if (isOrHasValue(module.offsetSurrounding, 'on')) {
// Top position sticky: get all module id that uses top / top_bottom position +
// has its offset surrounding turn on, that are rendered BEFORE THIS sticky element
if (includes(['top', 'top_bottom'], this.getProp(id, 'position'))) {
const topOffsetModuleIndex = topPositionModulesId.indexOf(id);
const topOffsetModule = slice(topPositionModulesId, 0, topOffsetModuleIndex);
// Saves all top offset modules for reference. This still needs to be processed to
// filter adjacent column later
this.setProp(id, 'topOffsetModulesAll', topOffsetModule);
// Mark for adjacent column filtering
offsetModulesUpdates.push({
prop: 'topOffsetModules',
id,
});
}
// Bottom position sticky: get all module id that uses bottom / top_bottom position +
// has its offset surrounding turn on, that are rendered AFTER THIS sticky element
if (includes(['bottom', 'top_bottom'], this.getProp(id, 'position'))) {
const bottomOffsetModuleIndex = bottomPositionModulesId.indexOf(id);
const bottomOffsetModules = slice(bottomPositionModulesId, (bottomOffsetModuleIndex + 1), modulesSize);
// Saves all bottom offset modules for reference. This still needs to be processed to
// filter adjacent column later
this.setProp(id, 'bottomOffsetModulesAll', bottomOffsetModules);
// Mark for adjacent column filtering
offsetModulesUpdates.push({
prop: 'bottomOffsetModules',
id,
});
}
}
});
// Top / bottom offset modules adjacent column filtering
if (offsetModulesUpdates.length > 0) {
// Default offsets. Make sure all sides element is available
const defaultOffsets = {
top: 0,
right: 0,
bottom: 0,
left: 0,
};
// Proper limit settings based on current offset modules position
const offsetLimitPropMaps = {
topOffsetModules: 'bottomLimitSettings',
bottomOffsetModules: 'topLimitSettings',
};
forEach(offsetModulesUpdates, update => {
// module's id
const moduleId = update.id;
// Need to be defined inside offsetModulesUpdates loop so each surrounding loop starts new
// Will be updated on every loop so next loop has reference of what is prev modules has
const prevSurroundingOffsets = {
...defaultOffsets,
};
// Loop over module's top/bottom offset module ids
const offsetModules = filter(this.getProp(moduleId, `${update.prop}All`), id => {
// Modules that are defined at top/bottomOffsetModules prop which is positioned after
// current module is referred as surrounding (modules) offset
const surroundingOffsets = {
...defaultOffsets,
...this.getProp(id, 'offsets', {}),
};
// Current module's offset
const moduleOffsets = {
...defaultOffsets,
...this.getProp(moduleId, 'offsets'),
};
// Module limit's offset
const moduleLimitOffsets = this.getProp(moduleId, `${offsetLimitPropMaps[update.prop]}.offsets`);
const surroundingLimitOffsets = this.getProp(id, `${offsetLimitPropMaps[update.prop]}.offsets`);
// If current and surrounding modules both have limit offsets, their top and bottom needs
// to be put in consideration in case they will never offset each other
if (moduleLimitOffsets && surroundingLimitOffsets) {
if (surroundingLimitOffsets.top < moduleLimitOffsets.top || surroundingLimitOffsets.bottom > moduleLimitOffsets.bottom) {
return false;
}
}
// If module has no limits, offset from surrounding sticky elements most likely not a
// valid offset surrounding. There is a case where surrounding can be valid offset, which
// is when current module on sticky state between surrounding limit top and bottom.
// However this rarely happens and requires conditional offset based on current window
// scroll top which might be over-engineer. Thus this is kept this way until further
// confirmation with design team
// @todo probably add conditional offset surrounding; confirm to design team
if (! moduleLimitOffsets && surroundingLimitOffsets) {
return false;
}
// Top Offset modules (sticky position top): modules rendered before current module
// Bottom Offset module (sticky position bottom): modules rendered after current module
// caveat: offset modules that are not vertically aligned with current module should not
// be considered as offset modules and affecting current module's auto-added offset.
// Hence this filter. Initially, all offset module should affect module's auto offset
let shouldPass = true;
// Surrounding module is beyond current module's right side
// ***********
// * current *
// ***********
// ***************
// * surrounding *
// ***************
const isSurroundingBeyondCurrentRight = surroundingOffsets.left >= moduleOffsets.right;
// Surrounding module is beyond current module's left side
// ***********
// * current *
// ***********
// ***************
// * surrounding *
// ***************
const isSurroundingBeyondCurrentLeft = surroundingOffsets.right < moduleOffsets.left;
// Surrounding module overlaps with current module's right side
// *********** ************************
// * current * * current *
// *********** OR ************************
// *************** ***************
// * surrounding * * surrounding *
// *************** ***************
const isSurroundingOverlapsCurrent = surroundingOffsets.left > moduleOffsets.left && surroundingOffsets.right > moduleOffsets.left;
// Previous surrounding module overlaps with current module's left side.
// ************************
// * current *
// ************************
// ******************** ******************************
// * prev surrounding * * surrounding (on this loop) *
// ******************** ******************************
const isPrevSurroundingOverlapsWithCurrent = moduleOffsets.left <= prevSurroundingOffsets.right && surroundingOffsets.top < prevSurroundingOffsets.bottom;
// Ignore surrounding height if previous surrounding height has affected current module's offset
// See isPrevSurroundingOverlapsWithCurrent's figure above
const isPrevSurroundingHasAffectCurrent = isSurroundingOverlapsCurrent && isPrevSurroundingOverlapsWithCurrent;
// Ignore the surrounding's height given the following scenarios
if (isSurroundingBeyondCurrentRight || isSurroundingBeyondCurrentLeft || isPrevSurroundingHasAffectCurrent) {
shouldPass = false;
}
// Save current surrounding offsets for next surrounding offsets comparison
assign(prevSurroundingOffsets, surroundingOffsets);
// true: surrounding's height is considered for current module's auto offset
// false: surrounding's height is ignored
return shouldPass;
});
// Set ${top/bottom}OffsetModules prop which will be synced to stickyElement
this.setProp(moduleId, `${update.prop}Align`, offsetModules);
});
}
// Perform secondary offset module calculation. The above works by getting the first surrounding
// sticky on the next row that affects current sticky. This works well when the row is filled
// like a grid, but fail if there is row in between which is not vertically overlap. Thus,
// get the closest surrounding offset sticky from last calculation, then fetch it. The idea is
// the last surrounding sticky might have offset which is not vertically align / overlap to
// current sticky element
forEach(this.modules, (module, moduleId) => {
if (module.topOffsetModulesAlign) {
const lastTopOffsetModule = last(module.topOffsetModulesAlign);
const pervTopOffsetModule = this.getProp(lastTopOffsetModule, 'topOffsetModules', this.getProp(lastTopOffsetModule, 'topOffsetModulesAlign', []));
this.setProp(moduleId, 'topOffsetModules', compact([
...pervTopOffsetModule,
...[lastTopOffsetModule],
]));
}
if (module.bottomOffsetModulesAlign) {
const firstBottomOffsetModule = head(module.bottomOffsetModulesAlign);
const pervBottomOffsetModule = this.getProp(firstBottomOffsetModule, 'bottomOffsetModules', this.getProp(firstBottomOffsetModule, 'bottomOffsetModulesAlign', []));
this.setProp(moduleId, 'bottomOffsetModules', compact([
...[firstBottomOffsetModule],
...pervBottomOffsetModule,
]));
}
});
}
/**
* Check if module with given id is on sticky state.
*
* @since 4.6.0
*
* @param {string} id
*
* @returns {bool}
*/
isSticky = id => get(this.modules, [id, 'isSticky'], false)
/**
* Add listener callback for settings change event.
*
* @since 4.6.0
* @param callback
* @param {Function}
*/
addSettingsChangeListener = callback => {
maybeIncreaseEmitterMaxListeners(this, SETTINGS_CHANGE);
this.on(SETTINGS_CHANGE, callback);
return this;
}
/**
* Remove listener callback for settings change event.
*
* @since 4.6.0
* @param callback
* @param {Function}
*/
removeSettingsChangeListener = callback => {
this.removeListener(SETTINGS_CHANGE, callback);
maybeDecreaseEmitterMaxListeners(this, SETTINGS_CHANGE);
return this;
}
}
const stickyStoreInstance = new ETScriptStickyStore;
// Register store instance as component to be exposed via global object
registerFrontendComponent('stores', 'sticky', stickyStoreInstance);
// Export store instance
// IMPORTANT: For uniformity, import this as ETScriptStickyStore
export default stickyStoreInstance;
@@ -1,754 +0,0 @@
// External dependencies
import { EventEmitter } from 'events';
import forEach from 'lodash/forEach';
import get from 'lodash/get';
import includes from 'lodash/includes';
import isEqual from 'lodash/isEqual';
import $ from 'jquery';
// Internal dependencies
import { top_window } from '@core-ui/utils/frame-helpers';
import ETScriptStickyStore from './sticky';
import {
getContentAreaSelector,
getTemplateEditorIframe,
} from '../../frontend-builder/gutenberg/utils/selectors';
import { isTemplateEditor } from '../../frontend-builder/gutenberg/utils/conditionals';
import {
isBFB,
isExtraTheme,
isFE,
isLBB,
isLBP,
isTB,
isVB,
maybeDecreaseEmitterMaxListeners,
maybeIncreaseEmitterMaxListeners,
registerFrontendComponent,
} from '../utils/utils';
// Builder window
const $window = $(window);
const $topWindow = top_window.jQuery(top_window);
const hasTopWindow = ! isEqual(window, top_window);
const windowLocations = hasTopWindow ? ['app', 'top'] : ['app'];
// Event Constants
const HEIGHT_CHANGE = 'height_change';
const WIDTH_CHANGE = 'width_change';
const SCROLL_TOP_CHANGE = 'scroll_top_change';
const BREAKPOINT_CHANGE = 'breakpoint_change';
const SCROLL_LOCATION_CHANGE = 'scroll_location_change';
const VERTICAL_SCROLL_BAR_CHANGE = 'vertical_scroll_bar_change';
// States.
// Private, limited to this module (ETScriptWindowStore class) only
const states = {
breakpoint: 'desktop',
extraMobileBreakpoint: false,
isBuilderZoomed: false,
scrollLocation: et_builder_utils_params.onloadScrollLocation, // app|top
scrollTop: {
app: 0,
top: 0,
},
height: {
app: 0,
top: 0,
},
width: {
app: 0,
top: 0,
},
bfbIframeOffset: {
top: 0,
left: 0,
},
lbpIframeOffset: {
top: 0,
left: 0,
},
verticalScrollBar: {
app: 0,
top: 0,
},
};
// Valid values.
// Retrieved from server, used for validating values
const validValues = {
scrollLocation: [...et_builder_utils_params.scrollLocations],
};
// Variables
const builderScrollLocations = {
...et_builder_utils_params.builderScrollLocations,
};
// @todo need to change how this works since builder already have et_screen_sizes(), unless
// we prefer to add another breakpoint functions
const deviceMinimumBreakpoints = {
desktop: 980,
tablet: 767,
phone: 0,
};
const bfbFrameId = '#et-bfb-app-frame';
/**
* Window store.
*
* This store listen to direct window's events; builder callback listen to this store's events
* to avoid dom-based calculation whenever possible; use the property passed by this store.
*
* @since 4.6.0
*/
class ETScriptWindowStore extends EventEmitter {
/**
* ETScriptWindowStore constructor.
*
* @since 4.6.0
*/
constructor() {
super();
// Set app window onload values
const windowWidth = $window.innerWidth();
const windowHeight = $window.innerHeight();
const windowScrollTop = $window.scrollTop();
this.setWidth('app', windowWidth).setHeight('app', windowHeight);
this.setScrollTop('app', windowScrollTop);
this.setVerticalScrollBarWidth('app', (window.outerWidth - windowWidth));
// Set top window onload values (if top window exist)
if (hasTopWindow) {
const topWindowWidth = $topWindow.innerWidth();
const topWindowHeight = $topWindow.innerHeight();
const topWindowScrollTop = top_window.jQuery(top_window).scrollTop();
this.setWidth('top', topWindowWidth).setHeight('top', topWindowHeight);
this.setScrollTop('top', topWindowScrollTop);
this.setVerticalScrollBarWidth('top', (top_window.outerWidth - topWindowWidth));
}
// Set iframe offset
if (isBFB) {
this.setBfbIframeOffset();
}
// Set Layout Block iframe offset
if (isLBP) {
this.setLayoutBlockPreviewIframeOffset();
}
}
/**
* Set window height.
*
* @since 4.6.0
*
* @param {string} windowLocation App|top.
* @param {number} height
*
* @returns {Window}
*/
setHeight = (windowLocation = 'app', height) => {
if (height === states.height[windowLocation]) {
return this;
}
states.height[windowLocation] = height;
this.emit(HEIGHT_CHANGE);
return this;
};
/**
* Set window width.
*
* @since 4.6.0
*
* @param {string} windowLocation App|top.
* @param {number} width
*
* @returns {Window}
*/
setWidth = (windowLocation = 'app', width) => {
if (width === states.width[windowLocation]) {
return this;
}
// Only app window could set breakpoint
if ('app' === windowLocation) {
this.setBreakpoint(width);
// Extra theme has its own "mobile breakpoint" (below 1024px)
if (isExtraTheme) {
const outerWidth = this.width + this.verticalScrollBar;
const extraMobileBreakpoint = 1024;
const fixedNavActivation = ! states.extraMobileBreakpoint && outerWidth >= extraMobileBreakpoint;
const fixedNavDeactivation = states.extraMobileBreakpoint && outerWidth < extraMobileBreakpoint;
// Re-set element props when Extra mobile breakpoint change happens
if (fixedNavActivation || fixedNavDeactivation) {
states.extraMobileBreakpoint = (outerWidth >= extraMobileBreakpoint);
ETScriptStickyStore.setElementsProps();
}
}
}
states.width[windowLocation] = width;
this.emit(WIDTH_CHANGE);
return this;
};
/**
* Set scroll location value.
*
* @since 4.6.0
*
* @param {string} scrollLocation App|top.
*
* @returns {ETScriptWindowStore}
*/
setScrollLocation = scrollLocation => {
// Prevent incorrect scroll location value from being saved
if (! includes(validValues.scrollLocation, scrollLocation)) {
return false;
}
if (scrollLocation === states.scrollLocation) {
return this;
}
states.scrollLocation = scrollLocation;
this.emit(SCROLL_LOCATION_CHANGE);
return this;
}
/**
* Set scroll top value.
*
* @since 4.6.0
*
* @param {string} windowLocation App|top.
* @param {number} scrollTop
*
* @returns {ETScriptWindowStore}
*/
setScrollTop = (windowLocation, scrollTop) => {
if (scrollTop === states.scrollTop[windowLocation]) {
return this;
}
states.scrollTop[windowLocation] = scrollTop;
this.emit(SCROLL_TOP_CHANGE);
return this;
}
/**
* Set builder zoomed status (on builder only).
*
* @since 4.6.0
*
* @param {string} builderPreviewMode Desktop|tablet|phone|zoom|wireframe.
*/
setBuilderZoomedStatus = builderPreviewMode => {
const isBuilderZoomed = 'zoom' === builderPreviewMode;
states.isBuilderZoomed = isBuilderZoomed;
}
/**
* Set BFB iframe offset.
*
* @since 4.6.0
*/
setBfbIframeOffset = () => {
states.bfbIframeOffset = top_window.jQuery(bfbFrameId).offset();
}
/**
* Set Layout Block iframe offset.
*
* @since 4.6.0
*/
setLayoutBlockPreviewIframeOffset = () => {
const blockId = get(window.ETBlockLayoutModulesScript, 'blockId', '');
const previewIframeId = `#divi-layout-iframe-${blockId}`;
const $block = top_window.jQuery(previewIframeId).closest('.wp-block[data-type="divi/layout"]');
const blockPosition = $block.position();
const contentSelectors = [
// WordPress 5.4
'block-editor-editor-skeleton__content',
// WordPress 5.5
'interface-interface-skeleton__content',
];
let blockOffsetTop = parseInt(get(blockPosition, 'top', 0));
// Since WordPress 5.4, blocks list position to its parent somehow is not considered
// Previous inserted DOM are also gone + Block item now has collapsing margin top/bottom
// These needs to be manually calculated here since the result is no longer identical
if (includes(contentSelectors, getContentAreaSelector(top_window, false))) {
// Find Block List Layout. By default, it's located on editor of top window.
// When Template Editor is active, it's "moved" to editor of iframe window.
const $blockEditorLayout = isTemplateEditor() ? getTemplateEditorIframe(top_window).find('.block-editor-block-list__layout.is-root-container') : top_window.jQuery('.block-editor-block-list__layout');
// Blocks list position to its parent (title + content wrapper)
// WordPress 5.4 = 183px
// WordPress 5.5 = 161px
if ($blockEditorLayout.length) {
blockOffsetTop += $blockEditorLayout.position().top;
}
// Compensating collapsing block item margin top
blockOffsetTop += parseInt($block.css('marginTop')) || 0;
}
// Admin bar in less than 600 width window uses absolute positioning which stays on top of
// document and affecting iframe top offset
if (600 > this.width && ETScriptStickyStore.getElementProp('wpAdminBar', 'exist', false)) {
blockOffsetTop += ETScriptStickyStore.getElementProp('wpAdminBar', 'height', 0);
}
states.lbpIframeOffset.top = blockOffsetTop;
}
/**
* Set vertical scrollbar width.
*
* @since 4.6.0
*
* @param {string} windowLocation
* @param {number} width
*/
setVerticalScrollBarWidth = (windowLocation = 'app', width) => {
if (width === states.verticalScrollBar[windowLocation]) {
return this;
}
states.verticalScrollBar[windowLocation] = width;
this.emit(VERTICAL_SCROLL_BAR_CHANGE);
return this;
}
/**
* Get current window width.
*
* @since 4.6.0
*
* @returns {number}
*/
get width() {
return states.width[this.scrollLocation];
}
/**
* Get current window height.
*
* @since 4.6.0
*
* @returns {number}
*/
get height() {
return states.height[this.scrollLocation];
}
/**
* Get current window scroll location.
*
* @since 4.6.0
*
* @returns {string} App|top.
*/
get scrollLocation() {
return states.scrollLocation;
}
/**
* Get current window scroll top / distance to document.
*
* @since 4.6.0
*
* @returns {number}
*/
get scrollTop() {
const multiplier = this.isBuilderZoomed ? 2 : 1;
let appFrameOffset = 0;
// Add app iframe offset on scrollTop calculation in BFB
if (isBFB) {
appFrameOffset += states.bfbIframeOffset.top;
}
// Add Layout Block preview iframe on scrollTop calculation
if (isLBP) {
appFrameOffset += states.lbpIframeOffset.top;
}
return (states.scrollTop[this.scrollLocation] - appFrameOffset) * multiplier;
}
/**
* Get current app window breakpoint (by device).
*
* @since 4.6.0
*
* @returns {string}
*/
get breakpoint() {
return states.breakpoint;
}
/**
* Get builder zoomed status.
*
* @since 4.6.0
*
* @returns {bool}
*/
get isBuilderZoomed() {
return states.isBuilderZoomed;
}
/**
* Get current window vertical scrollbar width.
*
* @since 4.6.0
*
* @returns {number}
*/
get verticalScrollBar() {
return states.verticalScrollBar[this.scrollLocation];
}
/**
* Get builder scroll location of builder context + preview mode.
*
* @since 4.6.0
*
* @param {string} previewMode Desktop|tablet|phone|zoom|wireframe.
*
* @returns {string} App|top.
*/
getBuilderScrollLocation = previewMode => get(builderScrollLocations, previewMode, 'app')
/**
* Add width change event listener.
*
* @since 4.6.0
*
* @param {Function} callback
*
* @returns {Window}
*/
addWidthChangeListener = callback => {
maybeIncreaseEmitterMaxListeners(this, WIDTH_CHANGE);
this.on(WIDTH_CHANGE, callback);
return this;
};
/**
* Remove width change event listener.
*
* @since 4.6.0
*
* @param {Function} callback
*
* @returns {Window}
*/
removeWidthChangeListener = callback => {
this.removeListener(WIDTH_CHANGE, callback);
maybeDecreaseEmitterMaxListeners(this, WIDTH_CHANGE);
return this;
};
/**
* Add height change event listener.
*
* @since 4.6.0
*
* @param {Function} callback
*
* @returns {Window}
*/
addHeightChangeListener = callback => {
maybeIncreaseEmitterMaxListeners(this, HEIGHT_CHANGE);
this.on(HEIGHT_CHANGE, callback);
return this;
};
/**
* Remove height change event listener.
*
* @since 4.6.0
*
* @param {Function} callback
*
* @returns {Window}
*/
removeHeightChangeListener = callback => {
this.removeListener(HEIGHT_CHANGE, callback);
maybeDecreaseEmitterMaxListeners(this, HEIGHT_CHANGE);
return this;
};
/**
* Add scroll location change event listener.
*
* @param callback
* @since 4.6.0
* @returns {ETScriptWindowStore}
*/
addScrollLocationChangeListener = callback => {
maybeIncreaseEmitterMaxListeners(this, SCROLL_LOCATION_CHANGE);
this.on(SCROLL_LOCATION_CHANGE, callback);
return this;
}
/**
* Remove scroll location change event listener.
*
* @param callback
* @since 4.6.0
* @returns {ETScriptWindowStore}
*/
removeScrollLocationChangeListener = callback => {
this.removeListener(SCROLL_LOCATION_CHANGE, callback);
maybeDecreaseEmitterMaxListeners(this, SCROLL_LOCATION_CHANGE);
return this;
}
/**
* Add scroll top change event listener.
*
* @param callback
* @since 4.6.0
* @returns {ETScriptWindowStore}
*/
addScrollTopChangeListener = callback => {
maybeIncreaseEmitterMaxListeners(this, SCROLL_TOP_CHANGE);
this.on(SCROLL_TOP_CHANGE, callback);
return this;
}
/**
* Remove scroll top change event listener.
*
* @param callback
* @since 4.6.0
* @returns {ETScriptWindowStore}
*/
removeScrollTopChangeListener = callback => {
this.removeListener(SCROLL_TOP_CHANGE, callback);
maybeDecreaseEmitterMaxListeners(this, SCROLL_TOP_CHANGE);
return this;
}
/**
* Set breakpoint (by device) based on window width.
*
* @since 4.6.0
*
* @todo Update breakpoint setting mechanic so this won't need to define another screen size definition
* and able to reuse (et_screen_size()).
*
* @param {number} windowWidth
*
* @returns {ETScriptWindowStore}
*/
setBreakpoint = windowWidth => {
let newBreakpoint = '';
forEach(deviceMinimumBreakpoints, (minWidth, device) => {
if (windowWidth > minWidth) {
newBreakpoint = device;
// equals to "break"
return false;
}
});
// No need to update breakpoint property if it is unchanged
if (this.breakpoint === newBreakpoint) {
return;
}
states.breakpoint = newBreakpoint;
this.emit(BREAKPOINT_CHANGE);
return this;
}
/**
* Add breakpoint change event listener.
*
* @since 4.6.0
*
* @param {Function} callback
*/
addBreakpointChangeListener = callback => {
maybeIncreaseEmitterMaxListeners(this, BREAKPOINT_CHANGE);
this.on(BREAKPOINT_CHANGE, callback);
return this;
}
/**
* Remove breakpoint change event listener.
*
* @since 4.6.0
*
* @param {Function} callback
*/
removeBreakpointChangeListener = callback => {
this.removeListener(BREAKPOINT_CHANGE, callback);
maybeDecreaseEmitterMaxListeners(this, BREAKPOINT_CHANGE);
return this;
}
}
// initiate window store instance
const windowStoreInstance = new ETScriptWindowStore();
/**
* Listen for (app/top) window events, and update store's value
* store is listener free; it only hold / set / get values.
*/
forEach(windowLocations, windowLocation => {
const isTop = 'top' === windowLocation;
const isApp = 'app' === windowLocation;
const currentWindow = isApp ? window : top_window;
const $currentWindow = currentWindow.jQuery(currentWindow);
// Scroll in Theme Builder & Layout Block Builder happens on element; adjustment needed
// const scrollWindow = isTop && (isTB || isLBB) ? currentWindow.document.getElementById('et-fb-app') : currentWindow;
const scrollWindow = () => {
// Theme Builder & Layout Block Builder
if (isTop && (isTB || isLBB)) {
return currentWindow.document.getElementById('et-fb-app');
}
// Layout Block Preview / Gutenberg
if (isTop && isLBP) {
return currentWindow.document.getElementsByClassName(getContentAreaSelector(currentWindow, false))[0];
}
return currentWindow;
};
// listen to current (app/top) window resize event
currentWindow.addEventListener('resize', () => {
const width = currentWindow.jQuery(currentWindow).innerWidth();
const height = currentWindow.jQuery(currentWindow).innerHeight();
windowStoreInstance.setWidth(windowLocation, width).setHeight(windowLocation, height);
windowStoreInstance.setVerticalScrollBarWidth(windowLocation, (currentWindow.outerWidth - width));
if ((windowStoreInstance.width > 782 && height <= 782) || (windowStoreInstance.width <= 782 && height > 782)) {
// Wait until admin bar's viewport style kicks in
setTimeout(() => {
ETScriptStickyStore.setElementHeight('wpAdminBar');
windowStoreInstance.emit(SCROLL_TOP_CHANGE);
}, 300);
}
});
// listen to current (app/top) window scroll event
scrollWindow().addEventListener('scroll', () => {
const scrollTop = isTop && (isTB || isLBB || isLBP) ? scrollWindow().scrollTop : scrollWindow().pageYOffset;
windowStoreInstance.setScrollTop(windowLocation, scrollTop);
});
// Top window listener only
if (isTop) {
// Listen to builder's preview mode change that is passed via top window event
$currentWindow.on('et_fb_preview_mode_changed', (event, screenMode, builderMode) => {
const scrollLocation = windowStoreInstance.getBuilderScrollLocation(builderMode);
windowStoreInstance.setBuilderZoomedStatus(builderMode);
windowStoreInstance.setScrollLocation(scrollLocation);
});
// Update iframe offset if any metabox is moved
if (isBFB) {
currentWindow.addEventListener('ETBFBMetaboxSortStopped', () => {
windowStoreInstance.setBfbIframeOffset();
});
}
// Gutenberg moves the scroll back to window if window's width is less than 600px
if (isLBP) {
currentWindow.addEventListener('scroll', () => {
if (windowStoreInstance.width > 600) {
return;
}
const scrollTop = currentWindow.pageYOffset;
windowStoreInstance.setScrollTop(windowLocation, scrollTop);
});
}
// When scroll is located on top window, there is a chance that the top window actually scrolls
// before the builder is loaded which means initial scroll top value actually has changed
// to avoid issue caused by it, when app window that carries this script is loaded, trigger
// scroll event on the top window's scrolling element
scrollWindow().dispatchEvent(new CustomEvent('scroll'));
}
// App window listener only
if (isApp) {
// Update known element props when breakpoint changes. Breakpoint change is basically less
// aggressive resize event, happened between known window's width
if (isFE || isVB) {
windowStoreInstance.addBreakpointChangeListener(() => {
ETScriptStickyStore.setElementsProps();
});
}
// Update iframe offset if layout block is moved
if (isLBP) {
currentWindow.addEventListener('ETBlockGbBlockOrderChange', () => {
// Need to wait at least 300ms until GB animation is done
setTimeout(() => {
windowStoreInstance.setLayoutBlockPreviewIframeOffset();
windowStoreInstance.emit(SCROLL_TOP_CHANGE);
}, 300);
});
// Update iframe offset if notice size is changed
currentWindow.addEventListener('ETGBNoticeSizeChange', () => {
if (ETScriptStickyStore.getElementProp('gbComponentsNoticeList', 'exist', false)) {
ETScriptStickyStore.setElementHeight('gbComponentsNoticeList');
windowStoreInstance.emit(SCROLL_TOP_CHANGE);
}
});
}
}
});
// Register store instance as component to be exposed via global object
registerFrontendComponent('stores', 'window', windowStoreInstance);
// Export store instance
// IMPORTANT: For uniformity, import this as ETScriptWindowStore
export default windowStoreInstance;
@@ -1,345 +0,0 @@
// Sticky Elements specific utils, used accross files
// External dependencies
import filter from 'lodash/filter';
import forEach from 'lodash/forEach';
import get from 'lodash/get';
import head from 'lodash/head';
import includes from 'lodash/includes';
import isEmpty from 'lodash/isEmpty';
import isString from 'lodash/isString';
import $ from 'jquery';
// Internal dependencies
import {
getOffsets,
} from './utils';
/**
* Get top / bottom limit attributes.
*
* @since 4.6.0
* @param {object} $selector
* @param limit
* @param {string}
* @returns {object}
* @returns {string} Object.limit.
* @returns {number} Object.height.
* @returns {number} Object.width.
* @return {object} object.offsets
* @return {number} object.offsets.top
* @return {number} object.offsets.right
* @return {number} object.offsets.bottom
* @return {number} object.offsets.left
*/
export const getLimit = ($selector, limit) => {
// @todo update valid limits based on selector
const validLimits = ['body', 'section', 'row', 'column'];
if (! includes(validLimits, limit)) {
return false;
}
// Limit selector
const $limitSelector = getLimitSelector($selector, limit);
if (! $limitSelector) {
return false;
}
const height = $limitSelector.outerHeight();
const width = $limitSelector.outerWidth();
return {
limit,
height,
width,
offsets: getOffsets($limitSelector, width, height),
};
};
/**
* Get top / bottom limit selector based on given name.
*
* @since 4.6.0
*
* @param {object} $selector
* @param {string} limit
*
* @returns {bool|object}
*/
export const getLimitSelector = ($selector, limit) => {
let parentSelector = false;
switch (limit) {
case 'body':
parentSelector = '.et_builder_inner_content';
break;
case 'section':
parentSelector = '.et_pb_section';
break;
case 'row':
parentSelector = '.et_pb_row';
break;
case 'column':
parentSelector = '.et_pb_column';
break;
default:
break;
}
return parentSelector ? $selector.closest(parentSelector) : false;
};
/**
* Filter invalid sticky modules
* 1. Sticky module inside another sticky module.
*
* @param {object} modules
* @param {object} currentModules
*
* @since 4.6.0
*/
export const filterInvalidModules = (modules, currentModules = {}) => {
const filteredModules = {};
forEach(modules, (module, key) => {
// If current sticky module is inside another sticky module, ignore current module
if ($(module.selector).parents('.et_pb_sticky_module').length > 0) {
return;
}
// Repopulate the module list
if (! isEmpty(currentModules) && currentModules[key]) {
// Keep props that isn't available on incoming modules intact
filteredModules[key] = {
...currentModules[key],
...module,
};
} else {
filteredModules[key] = module;
}
});
return filteredModules;
};
/**
* Get sticky style of given module by cloning, adding sticky state classname, appending DOM,
* retrieving value, then immediately the cloned DOM. This is needed for property that is most
* likely to be affected by transition if the sticky value is retrieved on the fly, thus it needs
* to be retrieved ahead its time by this approach.
*
* @since 4.6.0
*
* @param {string} id
* @param {object} $module
* @param {object} $placeholder
*
* @returns {object}
*/
export const getStickyStyles = (id, $module, $placeholder) => {
// Sticky state classname to be added; these will make cloned module to have fixed position and
// make sticky style take effect
const stickyStyleClassname = 'et_pb_sticky et_pb_sticky_style_dom';
// Cloned the module add sticky state classname; set the opacity to 0 and remove the transition
// so the dimension can be immediately retrieved
const $stickyStyleDom = $module.clone().addClass(stickyStyleClassname).attr({
'data-sticky-style-dom-id': id,
// Remove inline styles so on-page styles works. Especially needed if module is in sticky state
style: '',
}).css({
opacity: 0,
transition: 'none',
animation: 'none',
});
// Cloned module might contain image. However the image might take more than a milisecond to be
// loaded on the cloned module after the module is appended to the layout EVEN IF the image on
// the $module has been loaded. This might load to inaccurate sticky style calculation. To avoid
// it, recreate the image by getting actual width and height then recreate the image using SVG
$stickyStyleDom.find('img').each(function(index) {
const $img = $(this);
const $measuredImg = $module.find('img').eq(index);
const measuredWidth = get($measuredImg, [0, 'naturalWidth'], $module.find('img').eq(index).outerWidth());
const measuredHeight = get($measuredImg, [0, 'naturalHeight'], $module.find('img').eq(index).outerHeight());
$img.attr({
// Remove scrse to force DOM to use src
scrset: '',
// Recreate svg to use image's actual width so the image reacts appropriately when sticky
// style modifies image dimension (eg image has 100% and padding in sticky style is larger;
// this will resulting in image being smaller because the wrapper dimension is smaller)
src: `data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="${measuredWidth}" height="${measuredHeight}"><rect width="${measuredWidth}" height="${measuredHeight}" /></svg>`,
});
});
// Append the cloned DOM
$module.after($stickyStyleDom);
// Get inline margin style value that is substraction of sticky style - style due to position
// relative to fixed change
const getMarginStyle = corner => {
const marginPropName = `margin${corner}`;
const $normalModule = $module.hasClass('et_pb_sticky') ? $placeholder : $module;
return parseFloat($stickyStyleDom.css(marginPropName)) - parseFloat($normalModule.css(marginPropName));
};
// Measure sticky style DOM properties
const styles = {
height: $stickyStyleDom.outerHeight(),
width: $stickyStyleDom.outerWidth(),
marginRight: getMarginStyle('Right'),
marginLeft: getMarginStyle('Left'),
padding: $stickyStyleDom.css('padding'),
};
// Immediately remove the cloned DOM
$(`.et_pb_sticky_style_dom[data-sticky-style-dom-id="${id}"]`).remove();
return styles;
};
/**
* Remove given property's transition from transition property's value. To make some properties
* (eg. Width, top, left) transition smoothly when entering / leaving sticky state, its property
* and transition need to be removed then re-added 50ms later. This is mostly happened because the
* module positioning changed from relative to fixed when entering/leaving sticky state.
*
* @since 4.6.0
*
* @param {string} transitionValue
* @param {Array} trimmedProperties
*
* @returns {string}
*/
export const trimTransitionValue = (transitionValue, trimmedProperties) => {
// Make sure that transitionValue is string. Otherwise split will throw error
if (! isString(transitionValue)) {
transitionValue = '';
}
const transitions = transitionValue.split(', ');
const trimmedValue = filter(transitions, transition => ! includes(trimmedProperties, head(transition.split(' '))));
return isEmpty(trimmedValue) ? 'none' : trimmedValue.join(', ');
};
/**
* Calculate automatic offset that should be given based on sum of heights of all sticky modules
* that are currently in sticky state when window reaches $target's offset.
*
* @since 4.6.0
*
* @param {object} $target
*
* @returns {number}
*/
export const getClosestStickyModuleOffsetTop = $target => {
const offset = $target.offset();
offset.right = offset.left + $target.outerWidth();
let closestStickyElement = null;
let closestStickyOffsetTop = 0;
// Get all sticky module data from store. NOTE: this util might be used on various output build
// so it needs to get sticky store value via global object instead of importing it
const stickyModules = get(window.ET_FE, 'stores.sticky.modules', {});
// Loop sticky module data to get the closest sticky module to given y offset. Sticky module
// already has map of valid modules it needs to consider as automatic offset due to
// adjacent-column situation.
// @see https://github.com/elegantthemes/Divi/issues/19432
forEach(stickyModules, stickyModule => {
// Ignore sticky module if it is stuck to bottom
if (! includes(['top_bottom', 'top'], stickyModule.position)) {
return;
}
// Ignore if $target is sticky module (that sticks to top; stuck to bottom check above has
// made sure of it) - otherwise the auto-generate offset will subtract the element's offset
// and causing the scroll never reaches $target location.
// @see https://github.com/elegantthemes/Divi/issues/23240
if ($target.is(get(stickyModule, 'selector'))) {
return;
}
// Ignore if sticky module's right edge doesn't collide with target's left edge
if (get(stickyModule, 'offsets.right', 0) < offset.left) {
return;
}
// Ignore if sticky module's left edge doesn't collide with target's right edge
if (get(stickyModule, 'offsets.left', 0) > offset.right) {
return;
}
// Ignore sticky module if it is located below given y offset
if (get(stickyModule, 'offsets.top', 0) > offset.top) {
return;
}
// Ignore sticky module if its bottom limit is higher than given y offset
const bottomLimitBottom = get(stickyModule, 'bottomLimitSettings.offsets.bottom');
if (bottomLimitBottom && bottomLimitBottom < offset.top) {
return;
}
closestStickyElement = stickyModule;
});
// Once closest sticky module to given y offset has been found, loop its topOffsetModules, get
// each module's heightSticky and return the sum of their heights
if (get(closestStickyElement, 'topOffsetModules', false)) {
forEach(get(closestStickyElement, 'topOffsetModules', []), stickyId => {
// Get sticky module's height on sticky state; fallback to height just to be safe
const stickyModuleHeight = get(stickyModules, [stickyId, 'heightSticky'], get(stickyModules, [stickyId, 'height'], 0));
// Sum up top offset module's height
closestStickyOffsetTop += stickyModuleHeight;
});
// Get closest-to-y-offset's sticky module's height on sticky state;
const closestStickyElementHeight = get(stickyModules, [closestStickyElement.id, 'heightSticky'], get(stickyModules, [closestStickyElement.id, 'height'], 0));
// Sum up top offset module's height
closestStickyOffsetTop += closestStickyElementHeight;
}
return closestStickyOffsetTop;
};
/**
* Determine if the target is in sticky state.
*
* @since 4.9.5
*
* @param {object} $target
*
* @returns {bool}
*/
export const isTargetStickyState = $target => {
const stickyModules = get(window.ET_FE, 'stores.sticky.modules', {});
let isStickyState = false;
forEach(stickyModules, stickyModule => {
const isTarget = $target.is(get(stickyModule, 'selector'));
const {isSticky, isPaused} = stickyModule;
// If the target is in sticky state and not paused, set isStickyState to true and exit iteration.
// Elements can have a sticky limit (ex: section) in which case they can be sticky but paused.
if (isTarget && isSticky && !isPaused) {
isStickyState = true;
return false; // Exit iteration.
}
});
return isStickyState;
};
@@ -1,292 +0,0 @@
/**
* IMPORTANT: Keep external dependencies as low as possible since this utils might be
* imported by various frontend scripts; need to keep frontend script size low.
*/
// External dependencies
import includes from 'lodash/includes';
import get from 'lodash/get';
import $ from 'jquery';
// Internal dependencies
import { top_window } from '@core/admin/js/frame-helpers';
/**
* Check current page's builder Type.
*
* @since 4.6.0
*
* @param {string} builderType Fe|vb|bfb|tb|lbb|lbp.
*
* @returns {bool}
*/
export const isBuilderType = builderType => builderType === window.et_builder_utils_params.builderType;
/**
* Return condition value.
*
* @since 4.6.0
*
* @param {string} conditionName
*
* @returns {bool}
*/
export const is = conditionName => window.et_builder_utils_params.condition[conditionName];
/**
* Is current page Frontend.
*
* @since 4.6.0
*
* @type {bool}
*/
export const isFE = isBuilderType('fe');
/**
* Is current page Visual Builder.
*
* @since 4.6.0
*
* @type {bool}
*/
export const isVB = isBuilderType('vb');
/**
* Is current page BFB / New Builder Experience.
*
* @since 4.6.0
*
* @type {bool}
*/
export const isBFB = isBuilderType('bfb');
/**
* Is current page Theme Builder.
*
* @since 4.6.0
*
* @type {bool}
*/
export const isTB = isBuilderType('tb');
/**
* Is current page Layout Block Builder.
*
* @type {bool}
*/
export const isLBB = isBuilderType('lbb');
/**
* Is current page uses Divi Theme.
*
* @since 4.6.0
*
* @type {bool}
*/
export const isDiviTheme = is('diviTheme');
/**
* Is current page uses Extra Theme.
*
* @since 4.6.0
*
* @type {bool}
*/
export const isExtraTheme = is('extraTheme');
/**
* Is current page Layout Block Preview.
*
* @since 4.6.0
*
* @type {bool}
*/
export const isLBP = isBuilderType('lbp');
/**
* Check if current window is block editor window (gutenberg editing page).
*
* @since 4.6.0
*
* @type {bool}
*/
export const isBlockEditor = 0 < $(top_window.document).find('.edit-post-layout__content').length;
/**
* Check if current window is builder window (VB, BFB, TB, LBB).
*
* @since 4.6.0
*
* @type {bool}
*/
export const isBuilder = includes(['vb', 'bfb', 'tb', 'lbb'], window.et_builder_utils_params.builderType);
/**
* Get offsets value of all sides.
*
* @since 4.6.0
*
* @param {object} $selector JQuery selector instance.
* @param {number} height
* @param {number} width
*
* @returns {object}
*/
export const getOffsets = ($selector, width = 0, height = 0) => {
// Return previously saved offset if sticky tab is active; retrieving actual offset contain risk
// of incorrect offsets if sticky horizontal / vertical offset of relative position is modified.
const isStickyTabActive = isBuilder && $selector.hasClass('et_pb_sticky') && 'fixed' !== $selector.css('position');
const cachedOffsets = $selector.data('et-offsets');
const cachedDevice = $selector.data('et-offsets-device');
const currentDevice = get(window.ET_FE, 'stores.window.breakpoint', '');
// Only return cachedOffsets if sticky tab is active and cachedOffsets is not undefined and
// cachedDevice equal to currentDevice.
if (isStickyTabActive && cachedOffsets !== undefined && cachedDevice === currentDevice) {
return cachedOffsets;
}
// Get top & left offsets
const offsets = $selector.offset();
// If no offsets found, return empty object
if ('undefined' === typeof offsets) {
return {};
}
// FE sets the flag for sticky module which uses transform as classname on module wrapper while
// VB, BFB, TB, and LB sets the flag on CSS output's <style> element because it can't modify
// its parent. This compromises avoids the needs to extract transform rendering logic
const hasTransform = isBuilder
? $selector.children('.et-fb-custom-css-output[data-sticky-has-transform="on"]').length > 0
: $selector.hasClass('et_pb_sticky--has-transform');
let top = 'undefined' === typeof offsets.top ? 0 : offsets.top;
let left = 'undefined' === typeof offsets.left ? 0 : offsets.left;
// If module is sticky module that uses transform, its offset calculation needs to be adjusted
// because transform tends to modify the positioning of the module
if (hasTransform) {
// Calculate offset (relative to selector's parent) AFTER it is affected by transform
// NOTE: Can't use jQuery's position() because it considers margin-left `auto` which causes issue
// on row thus this manually calculate the difference between element and its parent's offset
// @see https://github.com/jquery/jquery/blob/1.12-stable/src/offset.js#L149-L155
const parentOffsets = $selector.parent().offset();
const transformedPosition = {
top: offsets.top - parentOffsets.top,
left: offsets.left - parentOffsets.left,
};
// Calculate offset (relative to selector's parent) BEFORE it is affected by transform
const preTransformedPosition = {
top: $selector[0].offsetTop,
left: $selector[0].offsetLeft,
};
// Update offset's top value
top += (preTransformedPosition.top - transformedPosition.top);
offsets.top = top;
// Update offset's left value
left += (preTransformedPosition.left - transformedPosition.left);
offsets.left = left;
}
// Manually calculate right & bottom offsets
offsets.right = left + width;
offsets.bottom = top + height;
// Save copy of the offset on element's .data() in case of scenario where retrieving actual
// offset value will lead to incorrect offset value (eg. sticky tab active with position offset)
$selector.data('et-offsets', offsets);
// Add current device to cache
if ('' !== currentDevice) {
$selector.data('et-offsets-device', offsets);
}
return offsets;
};
/**
* Increase EventEmitter's max listeners if lister count is about to surpass the max listeners limit
* IMPORTANT: Need to be placed BEFORE `.on()`.
*
* @since 4.6.0
* @param {EventEmitter} emitter
* @param eventName
* @param {string} EventName
*/
export const maybeIncreaseEmitterMaxListeners = (emitter, eventName) => {
const currentCount = emitter.listenerCount(eventName);
const maxListeners = emitter.getMaxListeners();
if (currentCount === maxListeners) {
emitter.setMaxListeners(maxListeners + 1);
}
};
/**
* Decrease EventEmitter's max listeners if listener count is less than max listener limit and above
* 10 (default max listener limit). If listener count is less than 10, max listener limit will
* remain at 10
* IMPORTANT: Need to be placed AFTER `.removeListener()`.
*
* @since 4.6.0
*
* @param {EventEmitter} emitter
* @param {string} eventName
*/
export const maybeDecreaseEmitterMaxListeners = (emitter, eventName) => {
const currentCount = emitter.listenerCount(eventName);
const maxListeners = emitter.getMaxListeners();
if (maxListeners > 10) {
emitter.setMaxListeners(currentCount);
}
};
/**
* Expose frontend (FE) component via global object so it can be accessed and reused externally
* Note: window.ET_Builder is for builder app's component; window.ET_FE is for frontend component.
*
* @since 4.6.0
*
* @param {string} type
* @param {string} name
* @param {mixed} component
*/
export const registerFrontendComponent = (type, name, component) => {
// Make sure that ET_FE is available
if ('undefined' === typeof window.ET_FE) {
window.ET_FE = {};
}
if ('object' !== typeof window.ET_FE[type]) {
window.ET_FE[type] = {};
}
window.ET_FE[type][name] = component;
};
/**
* Set inline style with !important tag. JQuery's .css() can't set value with `!important` tag so
* here it is.
*
* @since 4.6.2
*
* @param {object} $element
* @param {string} cssProp
* @param {string} value
*/
export const setImportantInlineValue = ($element, cssProp, value) => {
// Remove prop from current inline style in case the prop is already exist
$element.css(cssProp, '');
// Get current inline style
const inlineStyle = $element.attr('style');
// Re-insert inline style + property with important tag
$element.attr('style', `${inlineStyle} ${cssProp}: ${value} !important;`);
};