version 4.13.0
This commit is contained in:
345
includes/builder/scripts/utils/sticky.js
Normal file
345
includes/builder/scripts/utils/sticky.js
Normal file
@ -0,0 +1,345 @@
|
||||
// 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;
|
||||
};
|
306
includes/builder/scripts/utils/utils.js
Normal file
306
includes/builder/scripts/utils/utils.js
Normal file
@ -0,0 +1,306 @@
|
||||
/**
|
||||
* 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';
|
||||
|
||||
export const getBuilderUtilsParams = () => {
|
||||
if (window.et_builder_utils_params) {
|
||||
return window.et_builder_utils_params;
|
||||
}
|
||||
|
||||
if (top_window.et_builder_utils_params) {
|
||||
return top_window.et_builder_utils_params;
|
||||
}
|
||||
|
||||
return {};
|
||||
};
|
||||
|
||||
export const getBuilderType = () => get(getBuilderUtilsParams(), 'builderType', '');
|
||||
|
||||
/**
|
||||
* 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 === getBuilderType();
|
||||
|
||||
/**
|
||||
* Return condition value.
|
||||
*
|
||||
* @since 4.6.0
|
||||
*
|
||||
* @param {string} conditionName
|
||||
*
|
||||
* @returns {bool}
|
||||
*/
|
||||
export const is = conditionName => get(getBuilderUtilsParams(), `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'], getBuilderType());
|
||||
|
||||
/**
|
||||
* 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;`);
|
||||
};
|
Reference in New Issue
Block a user