/**
* External dependencies
*/
import { setWith, clone } from 'lodash';
/**
* Utility for updating state and only cloning objects in the path that changed.
*
* @param {Object} state The state being updated
* @param {Array} path The path being updated
* @param {*} value The value to update for the path
*
* @return {Object} The new state
*/
export default function updateState( state, path, value ) {
return setWith( clone( state ), path, value, clone );
}
__( 'Save as default', 'elementor' );
__( 'Sure you want to change default settings?', 'elementor' );
__( 'Your changes will automatically be saved for future uses of this element. %1$sNote:%2$s This includes sensitive information like emails, API keys, etc.', 'elementor' );
__( 'Save', 'elementor' );
__( 'Cancel', 'elementor' );
__( 'Do not show this message again', 'elementor' );
__( 'Previous settings restored.', 'elementor' );
__( 'An error occurred.', 'elementor' );
__( 'Default settings has been reset.', 'elementor' );
__( 'An error occurred.', 'elementor' );
__( 'Default settings changed.', 'elementor' );
__( 'Undo', 'elementor' );
__( 'An error occurred.', 'elementor' );# Varela Round font
`VarelaRound-Regular.ttf` is the unmodified Varela Round Regular font from the
[Google Fonts repository](https://github.com/google/fonts/tree/main/ofl/varelaround).
It is included locally so FrontEdit does not make a request to Google Fonts.
The font is licensed under the SIL Open Font License, Version 1.1; the complete
license and required attribution are included in `OFL.txt`.
{"translation-revision-date":"2026-MO-DA HO:MI+ZONE","generator":"WP-CLI\/2.12.0","source":"src\/Components\/NavMenu.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"pl_PL","plural-forms":"nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);"},"Header & Footer":["Nag\u0142\u00f3wek i stopka"],"Dashboard":["Panel sterowania"],"Widgets":["Widgety"],"Settings":["Ustawienia"],"What's New?":["Co nowego?"],"Learn":["Naucz si\u0119"],"Free vs Pro":["Darmowe vs Pro"],"Get Full Control":["Uzyskaj pe\u0142n\u0105 kontrol\u0119"],"Free":["Darmowe"],"Version":["Wersja"],"Useful Resources":["Przydatne zasoby"],"Getting Started":["Jak zacz\u0105\u0107"],"How to use widgets":["Jak u\u017cywa\u0107 widget\u00f3w"],"How to use features":["Jak u\u017cywa\u0107 funkcji"],"How to use templates":["Jak u\u017cywa\u0107 szablon\u00f3w"],"Contact us":["Skontaktuj si\u0119 z nami"]}}}/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */
/**
* List block tracker for UUID-aware list editing and serialization.
*
* Dependencies: wp.blocks, SFE.ElementPrep
* Exposes: SFE.ListBlockTracker
*/
(function() {
'use strict';
window.MWP = window.MWP || {};
window.MWP.SFE = window.MWP.SFE || {};
const SFE = window.MWP.SFE;
SFE.ManagerData = SFE.ManagerData || {};
const { createBlock, serialize: serializeBlocks } = window.wp?.blocks || {};
const UUID_ATTR_KEYS = ['mwpSfeUuid', 'mwpSfeUuidShadow'];
const LIST_ITEM_TEXT_ATTR = 'data-mwp-sfe-list-item-text';
const LIST_ITEM_TEXT_CLASS = 'mwp-sfe-list-item-text';
const PLACEHOLDER_ATTR = 'data-rich-text-placeholder';
const LIST_ID_ATTR = 'data-list-id';
const LIST_ITEM_ID_ATTR = 'data-item-id';
const LIST_RUNTIME_UUID_ATTR = 'data-mwp-sfe-list-runtime-uuid';
const LIST_ITEM_RUNTIME_UUID_ATTR = 'data-mwp-sfe-list-item-runtime-uuid';
/**
* Return whether one node is a nested list element.
*
* @param {Node|null} node Candidate DOM node.
* @returns {boolean} True when the node is a nested list.
*/
function isNestedListNode(node) {
return !!(
node &&
node.nodeType === Node.ELEMENT_NODE &&
(node.tagName === 'UL' || node.tagName === 'OL')
);
}
/**
* Return whether one node is ignorable formatting whitespace between list
* structures.
*
* Pretty-printed block markup often leaves direct `\n` text nodes between a
* list item's own text and its nested child list. Those nodes should not be
* moved into the direct text surface because they become visible editing
* artifacts once wrapped.
*
* @param {Node|null} node Candidate DOM node.
* @returns {boolean} True when the node is ignorable whitespace.
*/
function isIgnorableListWhitespaceNode(node) {
return !!(
node &&
node.nodeType === Node.TEXT_NODE &&
String(node.textContent || '')
.replace(/\uFEFF/g, '')
.replace(/\u00A0/g, ' ')
.trim()
.length === 0
);
}
/**
* Return the direct inline text surface for one list item.
*
* @param {HTMLLIElement|null} liElement Candidate list item.
* @returns {HTMLElement|null} Existing direct text surface, if any.
*/
function getDirectItemTextSurface(liElement) {
if (!liElement || liElement.nodeType !== Node.ELEMENT_NODE || liElement.tagName !== 'LI') {
return null;
}
return Array.from(liElement.children || []).find(child => (
child &&
child.nodeType === Node.ELEMENT_NODE &&
child.getAttribute(LIST_ITEM_TEXT_ATTR) === '1'
)) || null;
}
/**
* Return the DOM attribute name that stores one session-scoped runtime UUID.
*
* Runtime UUIDs are distinct from the existing serialization/attr UUIDs. They
* exist only while the editor session is open so external callers can point at
* the current live list cursor/target without having to manage shifting paths.
*
* @param {string} type Supported runtime identity type.
* @returns {string} Attribute name, or an empty string for invalid types.
*/
function getRuntimeUuidAttributeName(type) {
if (type === 'list') {
return LIST_RUNTIME_UUID_ATTR;
}
if (type === 'item') {
return LIST_ITEM_RUNTIME_UUID_ATTR;
}
return '';
}
/**
* Normalize one runtime UUID candidate.
*
* @param {*} value Candidate runtime UUID.
* @returns {string} Trimmed runtime UUID, or an empty string.
*/
function normalizeRuntimeUuid(value) {
return String(value || '').trim();
}
/**
* Return whether one element matches the requested runtime-identity type.
*
* @param {Element|null} element Candidate DOM element.
* @param {string} type Supported runtime identity type.
* @returns {boolean} True when the element matches the type.
*/
function isRuntimeIdentityElement(element, type) {
if (!element || element.nodeType !== Node.ELEMENT_NODE) {
return false;
}
if (type === 'list') {
return element.tagName === 'UL' || element.tagName === 'OL';
}
if (type === 'item') {
return element.tagName === 'LI';
}
return false;
}
/**
* Return one tracked element by runtime UUID from the live DOM.
*
* This intentionally queries the current DOM first instead of trusting only a
* cached map so history restores and other structural replacements can keep
* runtime UUID resolution stable as long as the attributes remain present.
*
* @param {Object|null} tracker Active list tracker.
* @param {string} runtimeUuid Session-scoped runtime UUID.
* @param {string} type Supported runtime identity type.
* @returns {Element|null} Matching live DOM element.
*/
function findElementByRuntimeUuid(tracker, runtimeUuid, type) {
const normalizedRuntimeUuid = normalizeRuntimeUuid(runtimeUuid);
const attrName = getRuntimeUuidAttributeName(type);
if (
!tracker?.listElement ||
!normalizedRuntimeUuid ||
!attrName ||
!isRuntimeIdentityElement(tracker.listElement, 'list')
) {
return null;
}
if (
type === 'list' &&
tracker.listElement.getAttribute(attrName) === normalizedRuntimeUuid
) {
return tracker.listElement;
}
try {
const selector = `[${attrName}="${CSS.escape(normalizedRuntimeUuid)}"]`;
return tracker.listElement.querySelector(selector);
} catch (error) {
const escapedUuid = normalizedRuntimeUuid.replace(/"/g, '\\"');
return tracker.listElement.querySelector(`[${attrName}="${escapedUuid}"]`);
}
}
/**
* Return every direct text surface currently attached to one list item.
*
* Merge/delete flows can temporarily move multiple direct text surfaces into
* the same list item. The shared list normalizer must collapse them back to
* one canonical surface before placeholder syncing or serialization.
*
* @param {HTMLLIElement|null} liElement Candidate list item.
* @returns {HTMLElement[]} Direct text surfaces in DOM order.
*/
function getAllDirectItemTextSurfaces(liElement) {
if (!liElement || liElement.nodeType !== Node.ELEMENT_NODE || liElement.tagName !== 'LI') {
return [];
}
return Array.from(liElement.children || []).filter(child => (
child &&
child.nodeType === Node.ELEMENT_NODE &&
child.getAttribute(LIST_ITEM_TEXT_ATTR) === '1'
));
}
/**
* Return whether one node is only placeholder/caret scaffolding.
*
* Duplicate direct text surfaces may carry empty placeholder anchors or
* caret `
` nodes. Those artifacts should be dropped when collapsing
* duplicate surfaces instead of being concatenated into visible stacks.
*
* @param {Node|null} node Candidate DOM node.
* @returns {boolean} True when the node is redundant placeholder UI.
*/
function isRedundantSurfaceArtifact(node) {
if (!node) {
return true;
}
if (isIgnorableListWhitespaceNode(node)) {
return true;
}
if (node.nodeType === Node.TEXT_NODE) {
return String(node.textContent || '')
.replace(/\uFEFF/g, '')
.replace(/\u00A0/g, ' ')
.trim()
.length === 0;
}
if (node.nodeType !== Node.ELEMENT_NODE) {
return false;
}
if (node.tagName === 'BR') {
return true;
}
return !!node.hasAttribute?.(PLACEHOLDER_ATTR);
}
/**
* Ensure one list item owns one direct inline text surface.
*
* The root list remains the single live editor host, but this wrapper gives
* schema/ABE flows one stable DOM surface per list item's own text content.
*
* @param {HTMLLIElement|null} liElement Candidate list item.
* @returns {HTMLElement|null} Ensured direct text surface.
*/
function ensureDirectItemTextSurface(liElement) {
if (!liElement || liElement.nodeType !== Node.ELEMENT_NODE || liElement.tagName !== 'LI') {
return null;
}
let surface = getDirectItemTextSurface(liElement);
if (!surface) {
surface = document.createElement('span');
surface.setAttribute(LIST_ITEM_TEXT_ATTR, '1');
surface.classList.add(LIST_ITEM_TEXT_CLASS);
liElement.insertBefore(
surface,
Array.from(liElement.childNodes || []).find(isNestedListNode) || null
);
}
getAllDirectItemTextSurfaces(liElement)
.filter(candidate => candidate && candidate !== surface)
.forEach(duplicateSurface => {
Array.from(duplicateSurface.childNodes || []).forEach(node => {
if (isRedundantSurfaceArtifact(node)) {
node.remove();
return;
}
surface.appendChild(node);
});
duplicateSurface.remove();
});
const childNodes = Array.from(liElement.childNodes || []);
childNodes.forEach(node => {
if (
node &&
node !== surface &&
!isNestedListNode(node) &&
isIgnorableListWhitespaceNode(node)
) {
node.remove();
}
});
const movableNodes = childNodes.filter(node => {
if (!node || node === surface || isNestedListNode(node)) {
return false;
}
if (isIgnorableListWhitespaceNode(node)) {
return false;
}
return !(
node.nodeType === Node.ELEMENT_NODE &&
node.getAttribute?.(LIST_ITEM_TEXT_ATTR) === '1'
);
});
movableNodes.forEach(node => surface.appendChild(node));
return surface;
}
/**
* Clone list attrs while optionally stripping plugin UUID ownership.
*
* The outermost core/list is the only persisted UUID owner for an entire
* list tree. Nested core/list blocks are structural children of that root.
* If we preserve a nested list UUID here, one accidental assignment can be
* re-serialized forever and split a single logical list into multiple
* history/edit targets. Keep this guard unless the ownership model changes
* everywhere else in PHP and JS at the same time.
*
* @param {Object} attrs Parsed Gutenberg attrs.
* @param {boolean} allowUuidOwnership True for the root list only.
* @returns {Object} Safe cloned attrs.
*/
function cloneListAttrs(attrs, allowUuidOwnership = true) {
const clonedAttrs = JSON.parse(JSON.stringify(attrs || {}));
if (allowUuidOwnership) {
return clonedAttrs;
}
UUID_ATTR_KEYS.forEach(key => delete clonedAttrs[key]);
return clonedAttrs;
}
/**
* Return the direct list-item children for one list element.
*
* @param {HTMLElement|null} listElement Candidate list element.
* @returns {HTMLLIElement[]} Direct child list items.
*/
function getDirectListItems(listElement) {
if (!listElement || listElement.nodeType !== Node.ELEMENT_NODE) {
return [];
}
return Array.from(listElement.children || []).filter(child => child.tagName === 'LI');
}
/**
* Normalize one path-like value into zero-based list indexes.
*
* Supported inputs:
* - `0_1_2`
* - `1.2.3`
* - arrays of integers
*
* @param {string|Array|null} pathValue Candidate path value.
* @returns {number[]|null} Parsed zero-based indexes.
*/
function normalizePathIndexes(pathValue) {
if (Array.isArray(pathValue)) {
const indexes = pathValue.map(value => Number.parseInt(value, 10));
return indexes.every(Number.isInteger) && indexes.every(index => index >= 0)
? indexes
: null;
}
const raw = typeof pathValue === 'string' ? pathValue.trim() : '';
if (!raw) {
return [];
}
const separator = raw.includes('.') ? '.' : '_';
const parts = raw.split(separator).filter(Boolean);
if (!parts.length) {
return [];
}
const indexes = parts.map(part => Number.parseInt(part, 10));
if (!indexes.every(Number.isInteger)) {
return null;
}
if (separator === '.') {
return indexes.every(index => index > 0)
? indexes.map(index => index - 1)
: null;
}
return indexes.every(index => index >= 0) ? indexes : null;
}
/**
* Convert one zero-based path index list into public path metadata.
*
* @param {number[]} indexes Zero-based indexes.
* @returns {{path: string, pathLabel: string, depth: number}} Path metadata.
*/
function buildPathMeta(indexes) {
const safeIndexes = Array.isArray(indexes) ? indexes.filter(Number.isInteger) : [];
return {
path: safeIndexes.join('_'),
pathLabel: safeIndexes.map(index => index + 1).join('.'),
depth: Math.max(0, safeIndexes.length - 1),
};
}
/**
* Return the direct child list element for one list item.
*
* @param {HTMLLIElement|null} listItem Candidate list item.
* @returns {HTMLElement|null} Direct nested list, if present.
*/
function getDirectChildList(listItem) {
if (!listItem || listItem.nodeType !== Node.ELEMENT_NODE || listItem.tagName !== 'LI') {
return null;
}
return Array.from(listItem.children || []).find(child => (
child.tagName === 'UL' || child.tagName === 'OL'
)) || null;
}
/**
* Return the preferred nested list tag for one list item.
*
* @param {Object|null} tracker Active list tracker.
* @param {HTMLLIElement} listItem Parent list item.
* @returns {string} `UL` or `OL`.
*/
function getPreferredChildListTagName(tracker, listItem) {
const directChildList = getDirectChildList(listItem);
if (directChildList) {
return directChildList.tagName;
}
const parentList = listItem?.parentElement;
if (parentList && (parentList.tagName === 'UL' || parentList.tagName === 'OL')) {
return parentList.tagName;
}
return tracker?.listElement?.tagName === 'OL' ? 'OL' : 'UL';
}
/**
* Return one direct child list for a list item, creating it only when needed.
*
* Outdent can promote one item and then re-home its trailing siblings beneath
* that promoted item. When the promoted item already owns a child list, those
* siblings must be appended into the existing list so the DOM mirrors native
* editor behavior instead of creating duplicate sibling list wrappers.
*
* @param {Object|null} tracker Active list tracker.
* @param {HTMLLIElement} listItem Parent list item.
* @param {string} preferredTagName Fallback list tag name.
* @returns {HTMLElement|null} Direct child list element.
*/
function ensureDirectChildList(tracker, listItem, preferredTagName = '') {
if (!listItem || listItem.nodeType !== Node.ELEMENT_NODE || listItem.tagName !== 'LI') {
return null;
}
let childList = getDirectChildList(listItem);
if (childList) {
return childList;
}
childList = document.createElement(
preferredTagName || getPreferredChildListTagName(tracker, listItem)
);
childList.classList.add('wp-block-list');
listItem.appendChild(childList);
return childList;
}
/**
* Remove empty nested list wrappers up the ancestry chain.
*
* The root list element is never removed, even when it becomes empty.
*
* @param {Object|null} tracker Active list tracker.
* @param {HTMLElement|null} startList First candidate nested list.
* @returns {void}
*/
function cleanupEmptyAncestorLists(tracker, startList) {
let currentList = startList;
while (
currentList &&
currentList !== tracker?.listElement &&
currentList.nodeType === Node.ELEMENT_NODE &&
(currentList.tagName === 'UL' || currentList.tagName === 'OL') &&
!getDirectListItems(currentList).length
) {
const parentItem = currentList.parentElement?.tagName === 'LI'
? currentList.parentElement
: null;
currentList.remove();
currentList = parentItem ? parentItem.parentElement : null;
}
}
/**
* Build one new list item element from a structural operation payload.
*
* @param {Object|null} operation Candidate operation payload.
* @returns {HTMLLIElement} New list item element.
*/
function buildListItemFromOperation(operation) {
const li = document.createElement('li');
const directSurface = ensureDirectItemTextSurface(li);
const runtimeUuid = normalizeRuntimeUuid(
operation?.itemUuid
?? operation?.newItemUuid
);
const html = typeof operation?.contentHtml === 'string'
? operation.contentHtml
: (typeof operation?.html === 'string' ? operation.html : '');
const text = typeof operation?.contentText === 'string'
? operation.contentText
: (typeof operation?.text === 'string' ? operation.text : '');
if (html) {
directSurface.innerHTML = html;
} else if (text) {
directSurface.textContent = text;
}
if (runtimeUuid) {
li.setAttribute(LIST_ITEM_RUNTIME_UUID_ATTR, runtimeUuid);
}
return li;
}
/**
* Copy one donor item's structural/style attributes onto the destination list
* item while preserving the destination runtime UUID.
*
* Native Enter list splitting happens inside the browser's contenteditable
* engine, so the new sibling inherits the source `li` element's attributes
* such as class and style automatically. API-driven insert/move operations
* should mirror that behavior by cloning the donor item's `li` attributes,
* except for the session-scoped runtime UUID which must stay unique.
*
* @param {HTMLLIElement|null} listItem Destination list item.
* @param {HTMLLIElement|null} donorItem Style/structure donor item.
* @returns {void}
*/
function copyDonorItemAttributes(listItem, donorItem) {
if (
!listItem ||
listItem.nodeType !== Node.ELEMENT_NODE ||
listItem.tagName !== 'LI' ||
!donorItem ||
donorItem.nodeType !== Node.ELEMENT_NODE ||
donorItem.tagName !== 'LI'
) {
return;
}
const destinationRuntimeUuid = normalizeRuntimeUuid(
listItem.getAttribute(LIST_ITEM_RUNTIME_UUID_ATTR)
);
Array.from(listItem.attributes || []).forEach(attr => {
if (attr?.name === LIST_ITEM_RUNTIME_UUID_ATTR) {
return;
}
listItem.removeAttribute(attr.name);
});
Array.from(donorItem.attributes || []).forEach(attr => {
if (attr?.name === LIST_ITEM_RUNTIME_UUID_ATTR) {
return;
}
listItem.setAttribute(attr.name, attr.value);
});
if (destinationRuntimeUuid) {
listItem.setAttribute(LIST_ITEM_RUNTIME_UUID_ATTR, destinationRuntimeUuid);
}
}
/**
* Reassign one list item's structural ID from its destination styling
* context.
*
* When an explicit target item is known, its structural `data-item-id`
* becomes the style donor for insert-before, insert-after, move-before, and
* move-after commands. This keeps the inheritance rule simple and matches the
* public API's explicit `targetItemUuid` model.
*
* For internal list-path insert/move cases that do not resolve through one
* target item, fall back to the local destination neighbors. If there is no
* neighboring item at all, clear the structural ID so the next tracker rebuild
* seeds a fresh item identity instead of accidentally preserving source attrs.
*
* @param {HTMLLIElement|null} listItem Destination list item.
* @param {HTMLLIElement|null} targetItem Explicit style donor item.
* @returns {string} Applied structural ID or an empty string.
*/
function inheritDestinationItemId(listItem, targetItem = null) {
if (!listItem || listItem.nodeType !== Node.ELEMENT_NODE || listItem.tagName !== 'LI') {
return '';
}
const explicitTargetItem = targetItem && targetItem.nodeType === Node.ELEMENT_NODE && targetItem.tagName === 'LI'
? targetItem
: null;
const previousItem = listItem.previousElementSibling?.tagName === 'LI'
? listItem.previousElementSibling
: null;
const nextItem = listItem.nextElementSibling?.tagName === 'LI'
? listItem.nextElementSibling
: null;
const inheritedId = normalizeRuntimeUuid(
explicitTargetItem?.getAttribute(LIST_ITEM_ID_ATTR)
|| previousItem?.getAttribute(LIST_ITEM_ID_ATTR)
|| nextItem?.getAttribute(LIST_ITEM_ID_ATTR)
);
if (inheritedId) {
listItem.setAttribute(LIST_ITEM_ID_ATTR, inheritedId);
return inheritedId;
}
listItem.removeAttribute(LIST_ITEM_ID_ATTR);
return '';
}
/**
* Apply one remove-list-item operation.
*
* @param {Object|null} tracker Active list tracker.
* @param {HTMLLIElement} listItem Target list item.
* @returns {boolean} True when the mutation applied.
*/
function applyRemoveListItemOperation(tracker, listItem) {
if (!tracker?.listElement || !listItem) {
return false;
}
const oldParentList = listItem.parentElement;
listItem.remove();
cleanupEmptyAncestorLists(tracker, oldParentList);
return true;
}
/**
* Apply one indent-list-item operation.
*
* @param {Object|null} tracker Active list tracker.
* @param {HTMLLIElement} listItem Target list item.
* @returns {boolean} True when the mutation applied.
*/
function applyIndentListItemOperation(tracker, listItem) {
if (!tracker?.listElement || !listItem) {
return false;
}
const previousItem = listItem.previousElementSibling?.tagName === 'LI'
? listItem.previousElementSibling
: null;
if (!previousItem) {
return false;
}
const nestedList = ensureDirectChildList(tracker, previousItem);
nestedList.appendChild(listItem);
return true;
}
/**
* Apply one outdent-list-item operation.
*
* @param {Object|null} tracker Active list tracker.
* @param {HTMLLIElement} listItem Target list item.
* @returns {boolean} True when the mutation applied.
*/
function applyOutdentListItemOperation(tracker, listItem) {
if (!tracker?.listElement || !listItem) {
return false;
}
const parentList = listItem.parentElement;
const parentItem = parentList?.parentElement?.tagName === 'LI'
? parentList.parentElement
: null;
if (!parentList || !parentItem) {
return false;
}
const ancestorList = parentItem.parentElement;
const followingSiblings = [];
let next = listItem.nextElementSibling;
while (next) {
followingSiblings.push(next);
next = next.nextElementSibling;
}
ancestorList.insertBefore(listItem, parentItem.nextElementSibling);
if (followingSiblings.length) {
const nestedList = ensureDirectChildList(tracker, listItem, parentList.tagName);
followingSiblings.forEach(sibling => nestedList.appendChild(sibling));
}
cleanupEmptyAncestorLists(tracker, parentList);
return true;
}
/**
* Apply one toggle-list-type operation.
*
* @param {Object|null} tracker Active list tracker.
* @param {Object} rawOperation Structural operation payload.
* @param {Object} options Apply-operation options.
* @returns {boolean} True when the mutation applied.
*/
function applyToggleListTypeOperation(tracker, rawOperation, options = {}) {
if (!tracker?.listElement) {
return false;
}
const listPath = rawOperation.listPath ?? rawOperation.list_path ?? '';
const targetList = getListByPath(tracker, listPath);
const editorHost = options?.editorHost && typeof options.editorHost.changeListType === 'function'
? options.editorHost
: null;
const requestedType = targetList
? (
normalizeListTypeTagName(
rawOperation.value
?? rawOperation.listType
?? rawOperation.list_type
?? rawOperation.ordered
) || (targetList.tagName === 'OL' ? 'UL' : 'OL')
)
: '';
if (
!targetList ||
!requestedType ||
targetList.tagName === requestedType ||
!editorHost
) {
return false;
}
const nextList = editorHost.changeListType(targetList, requestedType.toLowerCase(), {
saveHistory: options.saveHistory !== false,
restoreCursor: options.restoreCursor !== false,
});
return !!nextList;
}
/**
* Apply one update-list-item-text operation.
*
* @param {HTMLLIElement} listItem Target list item.
* @param {Object} rawOperation Structural operation payload.
* @returns {boolean} True when the mutation applied.
*/
function applyUpdateListItemTextOperation(listItem, rawOperation) {
if (!listItem) {
return false;
}
const directSurface = ensureDirectItemTextSurface(listItem);
const html = typeof rawOperation?.contentHtml === 'string'
? rawOperation.contentHtml
: (typeof rawOperation?.html === 'string' ? rawOperation.html : '');
const text = typeof rawOperation?.contentText === 'string'
? rawOperation.contentText
: (typeof rawOperation?.text === 'string' ? rawOperation.text : '');
if (!directSurface) {
return false;
}
directSurface.innerHTML = '';
if (html) {
directSurface.innerHTML = html;
} else if (text) {
directSurface.textContent = text;
}
return true;
}
/**
* Insert one new list item relative to explicit before/after/list anchors.
*
* @param {Object|null} tracker Active list tracker.
* @param {Object} rawOperation Structural operation payload.
* @param {Object} trackerApi List tracker API surface.
* @returns {boolean} True when the mutation applied.
*/
function applyInsertListItemOperation(tracker, rawOperation, trackerApi) {
if (!tracker?.listElement || !trackerApi) {
return false;
}
const beforePath = rawOperation.beforePath ?? rawOperation.before_path ?? '';
const afterPath = rawOperation.afterPath ?? rawOperation.after_path ?? '';
const listPath = rawOperation.listPath ?? rawOperation.list_path ?? '';
const beforeItem = trackerApi.getItemByPath(tracker, beforePath);
const afterItem = trackerApi.getItemByPath(tracker, afterPath);
const newListItem = buildListItemFromOperation(rawOperation);
if (beforeItem?.parentElement) {
beforeItem.parentElement.insertBefore(newListItem, beforeItem);
copyDonorItemAttributes(newListItem, beforeItem);
inheritDestinationItemId(newListItem, beforeItem);
return true;
}
if (afterItem?.parentElement) {
afterItem.parentElement.insertBefore(newListItem, afterItem.nextElementSibling);
copyDonorItemAttributes(newListItem, afterItem);
inheritDestinationItemId(newListItem, afterItem);
return true;
}
const targetList = getListByPath(tracker, listPath);
if (!targetList) {
return false;
}
const position = typeof rawOperation.position === 'string'
? rawOperation.position.trim().toLowerCase()
: 'append';
if (position === 'prepend' && targetList.firstElementChild) {
targetList.insertBefore(newListItem, targetList.firstElementChild);
} else {
targetList.appendChild(newListItem);
}
inheritDestinationItemId(newListItem);
return true;
}
/**
* Move one existing list item relative to explicit before/after/list anchors.
*
* @param {Object|null} tracker Active list tracker.
* @param {HTMLLIElement} listItem Target list item.
* @param {Object} rawOperation Structural operation payload.
* @param {Object} trackerApi List tracker API surface.
* @returns {boolean} True when the mutation applied.
*/
function applyMoveListItemOperation(tracker, listItem, rawOperation, trackerApi) {
if (!tracker?.listElement || !listItem || !trackerApi) {
return false;
}
const beforePath = rawOperation.beforePath ?? rawOperation.before_path ?? '';
const afterPath = rawOperation.afterPath ?? rawOperation.after_path ?? '';
const listPath = rawOperation.listPath ?? rawOperation.list_path ?? '';
const beforeItem = trackerApi.getItemByPath(tracker, beforePath);
const afterItem = trackerApi.getItemByPath(tracker, afterPath);
const oldParentList = listItem.parentElement;
let didApply = false;
if (beforeItem && beforeItem !== listItem && !listItem.contains(beforeItem)) {
beforeItem.parentElement.insertBefore(listItem, beforeItem);
copyDonorItemAttributes(listItem, beforeItem);
inheritDestinationItemId(listItem, beforeItem);
didApply = true;
} else if (afterItem && afterItem !== listItem && !listItem.contains(afterItem)) {
afterItem.parentElement.insertBefore(listItem, afterItem.nextElementSibling);
copyDonorItemAttributes(listItem, afterItem);
inheritDestinationItemId(listItem, afterItem);
didApply = true;
} else if (typeof listPath === 'string') {
const targetList = getListByPath(tracker, listPath);
const ownerItem = targetList?.parentElement?.tagName === 'LI'
? targetList.parentElement
: null;
if (targetList && ownerItem !== listItem && !listItem.contains(ownerItem || null)) {
const position = typeof rawOperation.position === 'string'
? rawOperation.position.trim().toLowerCase()
: 'append';
if (position === 'prepend' && targetList.firstElementChild) {
targetList.insertBefore(listItem, targetList.firstElementChild);
} else {
targetList.appendChild(listItem);
}
inheritDestinationItemId(listItem);
didApply = true;
}
}
if (didApply) {
cleanupEmptyAncestorLists(tracker, oldParentList);
}
return didApply;
}
/**
* Resolve one tracked list element from a list-path payload.
*
* The root list lives at the empty path. Nested lists are addressed by the
* tree path of the parent item that owns that child list.
*
* @param {Object|null} tracker Active list tracker.
* @param {string|Array} pathValue Root-empty list path or parent-item path.
* @returns {HTMLElement|null} Matching list element.
*/
function getListByPath(tracker, pathValue) {
if (!tracker?.listElement) {
return null;
}
if (
pathValue === '' ||
pathValue === null ||
typeof pathValue === 'undefined' ||
(Array.isArray(pathValue) && !pathValue.length) ||
(typeof pathValue === 'string' && !pathValue.trim())
) {
return tracker.listElement;
}
const parentItem = ListBlockTracker.getItemByPath(tracker, pathValue);
return parentItem ? getDirectChildList(parentItem) : null;
}
/**
* Normalize one requested list-type value to a DOM tag name.
*
* @param {*} value Candidate list-type value.
* @returns {string} `OL`, `UL`, or an empty string.
*/
function normalizeListTypeTagName(value) {
if (value === true) {
return 'OL';
}
if (value === false) {
return 'UL';
}
const normalized = String(value || '').trim().toLowerCase();
if (normalized === 'ordered' || normalized === 'ol' || normalized === 'true') {
return 'OL';
}
if (normalized === 'unordered' || normalized === 'ul' || normalized === 'false') {
return 'UL';
}
return '';
}
const ListBlockTracker = {
active: null,
/**
* Initialize tracker for a list element
* @param {HTMLElement} listElement - The UL or OL element
* @param {Object} originalBlock - The complete WordPress block structure
*/
init(listElement, originalBlock = {}) {
if (!createBlock || !serializeBlocks) {
console.error('wp.blocks not available');
}
const tracker = {
listElement,
originalBlock: JSON.parse(JSON.stringify(originalBlock)),
uuidMap: new Map(), // uuid -> {type, attrs, element}
domMap: new WeakMap(), // element -> uuid
runtimeUuidMap: new Map(), // runtimeUuid -> {type, element}
runtimeDomMap: new WeakMap() // element -> runtimeUuid
};
// Attach tracker to element to avoid singleton issues
listElement._mwpListTracker = tracker;
// Build UUID tracking from DOM and original block structure
this.buildFromDOM(tracker, listElement, originalBlock);
this.active = tracker;
return tracker;
},
/**
* Build UUID mappings from DOM and original block structure
* Assigns UUIDs to all lists and list items, mapping to their original attrs
*/
buildFromDOM(tracker, listElement, originalBlock) {
const previousEntries = tracker.uuidMap instanceof Map
? new Map(tracker.uuidMap)
: new Map();
const previousRuntimeEntries = tracker.runtimeUuidMap instanceof Map
? new Map(tracker.runtimeUuidMap)
: new Map();
tracker.uuidMap.clear();
tracker.domMap = new WeakMap();
tracker.runtimeUuidMap.clear();
tracker.runtimeDomMap = new WeakMap();
tracker.listElement = listElement;
this.syncEditableTextSurfaces(listElement);
this.registerRuntimeIdentity(
tracker,
listElement,
'list',
previousRuntimeEntries
);
// Assign UUID to root list and map to original attrs
const rootUuid = this.getOrCreateUuid(listElement, 'list');
const previousRootEntry = previousEntries.get(rootUuid);
tracker.uuidMap.set(rootUuid, {
type: 'list',
attrs: previousRootEntry?.attrs
? cloneListAttrs(previousRootEntry.attrs, true)
: cloneListAttrs(originalBlock.attrs || {}, true),
element: listElement
});
tracker.domMap.set(listElement, rootUuid);
// Recursively process list structure
this.processListRecursive(
tracker,
listElement,
originalBlock.innerBlocks || [],
previousEntries,
previousRuntimeEntries
);
},
/**
* Recursively process list items and nested lists, assigning UUIDs
*/
processListRecursive(
tracker,
listElement,
originalItems,
previousEntries = new Map(),
previousRuntimeEntries = new Map()
) {
const items = getDirectListItems(listElement);
items.forEach((li, index) => {
this.syncEditableTextSurfaces(li);
const originalItem = originalItems[index] || {};
this.registerRuntimeIdentity(
tracker,
li,
'item',
previousRuntimeEntries
);
const itemUuid = this.getOrCreateUuid(li, 'item');
const previousItemEntry = previousEntries.get(itemUuid);
// Map UUID to original item attrs
tracker.uuidMap.set(itemUuid, {
type: 'item',
attrs: previousItemEntry?.attrs
? JSON.parse(JSON.stringify(previousItemEntry.attrs || {}))
: JSON.parse(JSON.stringify(originalItem.attrs || {})),
element: li
});
tracker.domMap.set(li, itemUuid);
// Handle nested lists
const nestedList = getDirectChildList(li);
if (nestedList) {
const originalNested = originalItem.innerBlocks?.[0] || {};
this.registerRuntimeIdentity(
tracker,
nestedList,
'list',
previousRuntimeEntries
);
const nestedUuid = this.getOrCreateUuid(nestedList, 'list');
const previousNestedEntry = previousEntries.get(nestedUuid);
// Map nested list attrs without plugin UUID ownership.
// The tracker still needs a temporary DOM identity for list
// editing, but persisting mwpSfeUuid* on nested lists would
// fracture one logical list into multiple save/history roots.
tracker.uuidMap.set(nestedUuid, {
type: 'list',
attrs: previousNestedEntry?.attrs
? cloneListAttrs(previousNestedEntry.attrs, false)
: cloneListAttrs(originalNested.attrs || {}, false),
element: nestedList
});
tracker.domMap.set(nestedList, nestedUuid);
// Recurse into nested list
this.processListRecursive(
tracker,
nestedList,
originalNested.innerBlocks || [],
previousEntries,
previousRuntimeEntries
);
}
});
},
/**
* Register one list or list-item runtime identity on the tracker.
*
* @param {Object} tracker Active list tracker.
* @param {Element} element Live list or list-item element.
* @param {string} type Supported runtime identity type.
* @param {Map} previousRuntimeEntries Previous runtime entry map.
* @returns {string} Resolved runtime UUID.
*/
registerRuntimeIdentity(
tracker,
element,
type,
previousRuntimeEntries = new Map()
) {
const runtimeUuid = this.getOrCreateRuntimeUuid(
tracker,
element,
type,
previousRuntimeEntries
);
if (!runtimeUuid) {
return '';
}
tracker.runtimeUuidMap.set(runtimeUuid, {
type,
element,
});
tracker.runtimeDomMap.set(element, runtimeUuid);
return runtimeUuid;
},
/**
* Return whether one runtime UUID is already owned by a different element.
*
* Native contenteditable list splitting can clone DOM attributes from the
* source item into the newly created sibling. When that happens, the new
* runtime UUID must be reseeded so each live cursor target stays unique.
*
* @param {Object} tracker Active list tracker.
* @param {string} runtimeUuid Candidate runtime UUID.
* @param {Element|null} element Element requesting that UUID.
* @returns {boolean} True when the UUID belongs elsewhere.
*/
isRuntimeUuidClaimedByDifferentElement(tracker, runtimeUuid, element) {
const normalizedRuntimeUuid = normalizeRuntimeUuid(runtimeUuid);
if (!tracker?.runtimeUuidMap || !normalizedRuntimeUuid) {
return false;
}
const existingEntry = tracker.runtimeUuidMap.get(normalizedRuntimeUuid);
return !!(existingEntry?.element && existingEntry.element !== element);
},
/**
* Get the inherited structural ID for an element or seed it from the
* runtime UUID when it does not exist yet.
*
* Structural IDs may be intentionally copied by native list splitting so
* related items can retain style inheritance. They are not treated as
* unique runtime cursor identifiers.
*/
getOrCreateUuid(element, type) {
const attrName = type === 'list' ? LIST_ID_ATTR : LIST_ITEM_ID_ATTR;
let uuid = element.getAttribute(attrName);
if (!uuid) {
uuid = normalizeRuntimeUuid(
element.getAttribute(
type === 'list'
? LIST_RUNTIME_UUID_ATTR
: LIST_ITEM_RUNTIME_UUID_ATTR
)
) || this.generateTempUuid();
element.setAttribute(attrName, uuid);
}
return uuid;
},
/**
* Return the existing runtime UUID for one element or create one.
*
* Caller-supplied runtime UUIDs win for newly created items/lists. When an
* element already belongs to the previous tracker build, its existing
* runtime UUID is preserved so API references remain stable across rebuilds.
*
* @param {Object} tracker Active list tracker.
* @param {Element} element Live list or list-item element.
* @param {string} type Supported runtime identity type.
* @param {Map} previousRuntimeEntries Previous runtime entry map.
* @returns {string} Session-scoped runtime UUID.
*/
getOrCreateRuntimeUuid(
tracker,
element,
type,
previousRuntimeEntries = new Map()
) {
const attrName = getRuntimeUuidAttributeName(type);
if (!attrName || !isRuntimeIdentityElement(element, type)) {
return '';
}
let runtimeUuid = normalizeRuntimeUuid(element.getAttribute(attrName));
if (!runtimeUuid) {
for (const [candidateUuid, entry] of previousRuntimeEntries.entries()) {
if (entry?.element === element && entry.type === type) {
runtimeUuid = normalizeRuntimeUuid(candidateUuid);
break;
}
}
}
if (this.isRuntimeUuidClaimedByDifferentElement(tracker, runtimeUuid, element)) {
runtimeUuid = '';
}
if (!runtimeUuid) {
runtimeUuid = this.generateTempUuid();
}
element.setAttribute(attrName, runtimeUuid);
return runtimeUuid;
},
/**
* Generate a RFC4122 version 4 UUID
*/
generateTempUuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
const r = Math.random() * 16 | 0;
const v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
},
/**
* Return the zero-based tree path for one list item inside the tracked list.
*
* @param {Object} tracker Active list tracker.
* @param {HTMLLIElement} listItem Candidate list item.
* @returns {number[]|null} Zero-based indexes, or null on failure.
*/
getPathIndexesForItem(tracker, listItem) {
if (
!tracker?.listElement ||
!listItem ||
listItem.nodeType !== Node.ELEMENT_NODE ||
listItem.tagName !== 'LI' ||
!tracker.listElement.contains(listItem)
) {
return null;
}
const indexes = [];
let currentItem = listItem;
while (currentItem && tracker.listElement.contains(currentItem)) {
const parentList = currentItem.parentElement;
if (!parentList || (parentList.tagName !== 'UL' && parentList.tagName !== 'OL')) {
return null;
}
const siblingItems = getDirectListItems(parentList);
const itemIndex = siblingItems.indexOf(currentItem);
if (itemIndex < 0) {
return null;
}
indexes.unshift(itemIndex);
const nextItem = parentList.closest('li');
if (!nextItem || !tracker.listElement.contains(nextItem)) {
break;
}
currentItem = nextItem;
}
return indexes.length ? indexes : null;
},
/**
* Return the direct list item currently living at one tree path.
*
* @param {Object} tracker Active list tracker.
* @param {string|Array} pathValue Zero-based path value.
* @returns {HTMLLIElement|null} Matching list item.
*/
getItemByPath(tracker, pathValue) {
const indexes = normalizePathIndexes(pathValue);
if (!tracker?.listElement || !Array.isArray(indexes) || !indexes.length) {
return null;
}
let currentList = tracker.listElement;
let currentItem = null;
for (let index = 0; index < indexes.length; index++) {
const itemIndex = indexes[index];
const siblingItems = getDirectListItems(currentList);
currentItem = siblingItems[itemIndex] || null;
if (!currentItem) {
return null;
}
if (index === indexes.length - 1) {
return currentItem;
}
currentList = getDirectChildList(currentItem);
if (!currentList) {
return null;
}
}
return currentItem;
},
/**
* Resolve one list element back to its public list path.
*
* The root list is addressed as an empty string. Nested child lists are
* addressed by the path of the parent list item that owns them.
*
* @param {Object|null} tracker Active list tracker.
* @param {HTMLElement|null} listElement Candidate list element.
* @returns {string} Root-relative list path.
*/
getPathForList(tracker, listElement) {
if (!tracker) tracker = this.active;
if (!tracker?.listElement || !listElement || listElement.nodeType !== Node.ELEMENT_NODE) {
return '';
}
if (listElement === tracker.listElement) {
return '';
}
const parentItem = (
listElement.parentElement &&
listElement.parentElement.tagName === 'LI'
)
? listElement.parentElement
: null;
if (!parentItem) {
return '';
}
const indexes = this.getPathIndexesForItem(tracker, parentItem);
return Array.isArray(indexes) ? indexes.join('_') : '';
},
/**
* Return one tracked list item by runtime UUID.
*
* @param {Object|null} tracker Active list tracker.
* @param {string} runtimeUuid Session-scoped item UUID.
* @returns {HTMLLIElement|null} Matching list item.
*/
getItemByRuntimeUuid(tracker, runtimeUuid) {
if (!tracker) tracker = this.active;
const element = findElementByRuntimeUuid(tracker, runtimeUuid, 'item');
return element && element.tagName === 'LI' ? element : null;
},
/**
* Return one tracked list by runtime UUID.
*
* @param {Object|null} tracker Active list tracker.
* @param {string} runtimeUuid Session-scoped list UUID.
* @returns {HTMLElement|null} Matching list element.
*/
getListByRuntimeUuid(tracker, runtimeUuid) {
if (!tracker) tracker = this.active;
const element = findElementByRuntimeUuid(tracker, runtimeUuid, 'list');
return isListElementForRuntimeLookup(element) ? element : null;
},
/**
* Return the runtime UUID for one tracked list item.
*
* @param {Object|null} tracker Active list tracker.
* @param {HTMLLIElement} listItem Live list item.
* @returns {string} Session-scoped item UUID.
*/
getRuntimeUuidForItem(tracker, listItem) {
if (!tracker) tracker = this.active;
if (!tracker?.listElement || !listItem || listItem.tagName !== 'LI') {
return '';
}
return normalizeRuntimeUuid(
listItem.getAttribute(LIST_ITEM_RUNTIME_UUID_ATTR)
|| tracker.runtimeDomMap?.get(listItem)
);
},
/**
* Return the runtime UUID for one tracked list.
*
* @param {Object|null} tracker Active list tracker.
* @param {HTMLElement} listElement Live list element.
* @returns {string} Session-scoped list UUID.
*/
getRuntimeUuidForList(tracker, listElement) {
if (!tracker) tracker = this.active;
if (!tracker?.listElement || !isListElementForRuntimeLookup(listElement)) {
return '';
}
return normalizeRuntimeUuid(
listElement.getAttribute(LIST_RUNTIME_UUID_ATTR)
|| tracker.runtimeDomMap?.get(listElement)
);
},
/**
* Parse current DOM list structure to WordPress block format
* Uses UUID to preserve original attrs, updates only content and ordered
*
* @param {HTMLElement} listElement Live UL/OL element.
* @param {Object} tracker Active list tracker.
* @param {boolean} allowUuidOwnership True only for the outermost
* core/list. Nested lists must
* serialize without persisted
* plugin UUID attrs.
*/
parseListToBlock(listElement, tracker, allowUuidOwnership = true) {
const isOrdered = listElement.tagName === 'OL';
const uuid = listElement.getAttribute(LIST_ID_ATTR);
let attrs = { ordered: isOrdered };
if (uuid && tracker && tracker.uuidMap.has(uuid)) {
const original = tracker.uuidMap.get(uuid);
const originalAttrs = (Array.isArray(original.attrs) || !original.attrs)
? {}
: cloneListAttrs(original.attrs, allowUuidOwnership);
attrs = { ...originalAttrs, ordered: isOrdered };
}
const listItems = Array.from(listElement.children).filter(el => el.tagName === 'LI');
const innerBlocks = listItems.map(li => this.parseListItemToBlock(li, tracker));
return createBlock('core/list', attrs, innerBlocks);
},
/**
* Parse a list item to WordPress block format
* Preserves original attrs if UUID exists
*/
parseListItemToBlock(liElement, tracker) {
const uuid = liElement.getAttribute(LIST_ITEM_ID_ATTR);
let attrs = {};
if (uuid && tracker && tracker.uuidMap.has(uuid)) {
const original = tracker.uuidMap.get(uuid);
attrs = JSON.parse(JSON.stringify(original.attrs || {}));
}
// Recurse into nested list using the live element before cloning
const innerBlocks = [];
const nestedListEl = liElement.querySelector(':scope > ul, :scope > ol');
if (nestedListEl) {
innerBlocks.push(this.parseListToBlock(nestedListEl, tracker, false));
}
const clone = liElement.cloneNode(true);
const directSurface = clone.querySelector(`:scope > [${LIST_ITEM_TEXT_ATTR}="1"]`);
let content = '';
if (directSurface) {
const cleanedSurface = this.cleanElement(directSurface);
content = cleanedSurface.innerHTML.trim();
} else {
const nestedInClone = clone.querySelector(':scope > ul, :scope > ol');
if (nestedInClone) nestedInClone.remove();
const cleaned = this.cleanElement(clone);
content = cleaned.innerHTML.trim();
}
return createBlock('core/list-item', { ...attrs, content }, innerBlocks);
},
/**
* Clean element using ElementPrep
* Removes editing artifacts while preserving UUIDs and content
*/
cleanElement(element) {
if (SFE.ElementPrep) {
return SFE.ElementPrep.clean(element, {
removeIdentity: true,
removeControls: true,
clone: false // Already working with a clone
});
}
console.error('ElementPrep not found');
return element;
},
/**
* Serialize the current list structure to WordPress block format
* Preserves all original attrs, updates only content and ordered
*/
serialize(tracker) {
if (!tracker) tracker = this.active;
if (!tracker) return null;
const block = this.parseListToBlock(tracker.listElement, tracker);
return serializeBlocks([block]);
},
/**
* Update the tracker's element reference
* Used when the list element is replaced (e.g., OL to UL conversion)
*/
updateElement(tracker, newElement) {
if (!tracker) tracker = this.active;
if (!tracker) return;
// Ensure new element keeps the tracker reference
newElement._mwpListTracker = tracker;
this.syncEditableTextSurfaces(newElement);
tracker.listElement = newElement;
// Update element references in uuidMap
tracker.uuidMap.forEach((value, key) => {
if (value.type === 'list') {
const newEl = newElement.querySelector(`[${LIST_ID_ATTR}="${key}"]`) ||
(newElement.getAttribute(LIST_ID_ATTR) === key ? newElement : null);
if (newEl) {
value.element = newEl;
}
} else if (value.type === 'item') {
const newEl = newElement.querySelector(`[${LIST_ITEM_ID_ATTR}="${key}"]`);
if (newEl) {
value.element = newEl;
}
}
});
tracker.runtimeUuidMap.forEach((value, key) => {
if (value.type === 'list') {
const newEl = this.getListByRuntimeUuid(tracker, key);
if (newEl) {
value.element = newEl;
tracker.runtimeDomMap.set(newEl, key);
}
} else if (value.type === 'item') {
const newEl = this.getItemByRuntimeUuid(tracker, key);
if (newEl) {
value.element = newEl;
tracker.runtimeDomMap.set(newEl, key);
}
}
});
},
/**
* Return one tree-aware structural snapshot for the active list.
*
* @param {Object|null} tracker Active list tracker.
* @returns {Object|null} Lightweight structure snapshot.
*/
getStructure(tracker) {
if (!tracker) tracker = this.active;
if (!tracker?.listElement) {
return null;
}
const buildListNode = (listElement, listPath = '', parentIndexes = []) => ({
listUuid: this.getRuntimeUuidForList(tracker, listElement),
listPath,
ordered: listElement.tagName === 'OL',
items: getDirectListItems(listElement).map((listItem, index) => {
const indexes = [ ...parentIndexes, index ];
const pathMeta = buildPathMeta(indexes);
const directSurface = ensureDirectItemTextSurface(listItem);
const nestedList = getDirectChildList(listItem);
return {
itemUuid: this.getRuntimeUuidForItem(tracker, listItem),
path: pathMeta.path,
pathLabel: pathMeta.pathLabel,
depth: pathMeta.depth,
contentHtml: directSurface ? directSurface.innerHTML.trim() : '',
childList: nestedList
? buildListNode(nestedList, pathMeta.path, indexes)
: null,
};
}),
});
return buildListNode(tracker.listElement, '', []);
},
/**
* Apply one primitive structural list operation against the live tracked
* DOM.
*
* Public API calls are translated into this lower-level operation set by
* the shared schema executor so the tracker only needs to understand the
* canonical primitive mutation layer.
*
* Supported primitive kinds:
* - `insert_list_item`
* - `remove_list_item`
* - `move_list_item`
* - `indent_list_item`
* - `outdent_list_item`
* - `update_list_item_text`
* - `toggle_list_type`
*
* @param {Object|null} tracker Active list tracker.
* @param {Object} rawOperation Structural operation payload.
* @returns {Object|null} Result summary when applied.
*/
applyOperation(tracker, rawOperation, options = {}) {
if (!tracker) tracker = this.active;
if (!tracker?.listElement || !rawOperation || typeof rawOperation !== 'object') {
return null;
}
const kind = typeof rawOperation.kind === 'string' ? rawOperation.kind.trim().toLowerCase() : '';
const path = rawOperation.path ?? rawOperation.itemPath ?? rawOperation.item_path ?? '';
const listItem = this.getItemByPath(tracker, path);
let didApply = false;
if (kind === 'remove_list_item' && listItem) {
didApply = applyRemoveListItemOperation(tracker, listItem);
} else if (kind === 'indent_list_item' && listItem) {
didApply = applyIndentListItemOperation(tracker, listItem);
} else if (kind === 'outdent_list_item' && listItem) {
didApply = applyOutdentListItemOperation(tracker, listItem);
} else if (kind === 'toggle_list_type') {
didApply = applyToggleListTypeOperation(tracker, rawOperation, options);
} else if (kind === 'update_list_item_text' && listItem) {
didApply = applyUpdateListItemTextOperation(listItem, rawOperation);
} else if (kind === 'insert_list_item') {
didApply = applyInsertListItemOperation(tracker, rawOperation, this);
} else if (kind === 'move_list_item' && listItem) {
didApply = applyMoveListItemOperation(tracker, listItem, rawOperation, this);
}
if (!didApply) {
return null;
}
this.syncEditableTextSurfaces(tracker.listElement);
this.buildFromDOM(tracker, tracker.listElement, tracker.originalBlock || {});
return {
kind,
structure: this.getStructure(tracker),
};
},
/**
* Ensure every list item in one tree has one direct text surface.
*
* @param {HTMLElement|null} rootElement Candidate list root or list item.
* @returns {HTMLElement|null} Normalized root element.
*/
syncEditableTextSurfaces(rootElement) {
if (!rootElement || rootElement.nodeType !== Node.ELEMENT_NODE) {
return null;
}
if (rootElement.tagName === 'LI') {
ensureDirectItemTextSurface(rootElement);
Array.from(rootElement.children || [])
.filter(child => isNestedListNode(child))
.forEach(childList => this.syncEditableTextSurfaces(childList));
return rootElement;
}
if (rootElement.tagName !== 'UL' && rootElement.tagName !== 'OL') {
return rootElement;
}
Array.from(rootElement.children || [])
.filter(child => child.tagName === 'LI')
.forEach(li => this.syncEditableTextSurfaces(li));
return rootElement;
},
/**
* Ensure runtime UUID attributes are unique within one live list tree.
*
* Native contenteditable list splitting can clone `li` and nested list
* attributes verbatim before FrontEdit regains control. This pass reseeds only the
* session-scoped runtime UUID attributes so freshly created structures become
* distinct live API/editor targets immediately, while leaving `data-item-id`
* and `data-list-id` untouched for their separate responsibilities.
*
* @param {HTMLElement|null} rootElement Candidate list root.
* @returns {HTMLElement|null} Normalized root element.
*/
ensureUniqueRuntimeUuids(rootElement) {
if (
!rootElement ||
rootElement.nodeType !== Node.ELEMENT_NODE ||
(rootElement.tagName !== 'UL' && rootElement.tagName !== 'OL')
) {
return rootElement || null;
}
const seenListRuntimeUuids = new Set();
const seenItemRuntimeUuids = new Set();
const collectLists = [ rootElement, ...Array.from(rootElement.querySelectorAll('ul, ol')) ];
const collectItems = Array.from(rootElement.querySelectorAll('li'));
collectLists.forEach(listElement => {
const runtimeUuid = normalizeRuntimeUuid(
listElement.getAttribute(LIST_RUNTIME_UUID_ATTR)
);
if (!runtimeUuid) {
return;
}
if (seenListRuntimeUuids.has(runtimeUuid)) {
listElement.setAttribute(LIST_RUNTIME_UUID_ATTR, this.generateTempUuid());
return;
}
seenListRuntimeUuids.add(runtimeUuid);
});
collectItems.forEach(listItem => {
const runtimeUuid = normalizeRuntimeUuid(
listItem.getAttribute(LIST_ITEM_RUNTIME_UUID_ATTR)
);
if (!runtimeUuid) {
return;
}
if (seenItemRuntimeUuids.has(runtimeUuid)) {
listItem.setAttribute(LIST_ITEM_RUNTIME_UUID_ATTR, this.generateTempUuid());
return;
}
seenItemRuntimeUuids.add(runtimeUuid);
});
return rootElement;
},
/**
* Ensure one live list tree has the required structural IDs and runtime UUIDs.
*
* On first editor activation, list elements may not yet have either identity
* attribute family. Seed both from one generated UUID per element so the
* initial history snapshot captures stable targeting data. Later native list
* splits may intentionally copy the structural IDs; in those cases this pass
* preserves the structural IDs and only reseeds duplicated runtime UUIDs.
*
* @param {HTMLElement|null} rootElement Candidate list root.
* @returns {HTMLElement|null} Normalized root element.
*/
ensureIdentityAttributes(rootElement) {
if (
!rootElement ||
rootElement.nodeType !== Node.ELEMENT_NODE ||
(rootElement.tagName !== 'UL' && rootElement.tagName !== 'OL')
) {
return rootElement || null;
}
const syncIdentityPair = (element, structuralAttrName, runtimeAttrName) => {
if (!element || element.nodeType !== Node.ELEMENT_NODE) {
return;
}
let structuralId = normalizeRuntimeUuid(
element.getAttribute(structuralAttrName)
);
let runtimeUuid = normalizeRuntimeUuid(
element.getAttribute(runtimeAttrName)
);
if (!structuralId && !runtimeUuid) {
runtimeUuid = this.generateTempUuid();
structuralId = runtimeUuid;
} else if (!runtimeUuid) {
runtimeUuid = structuralId;
} else if (!structuralId) {
structuralId = runtimeUuid;
}
element.setAttribute(structuralAttrName, structuralId);
element.setAttribute(runtimeAttrName, runtimeUuid);
};
syncIdentityPair(rootElement, LIST_ID_ATTR, LIST_RUNTIME_UUID_ATTR);
Array.from(rootElement.querySelectorAll('ul, ol')).forEach(listElement => {
syncIdentityPair(listElement, LIST_ID_ATTR, LIST_RUNTIME_UUID_ATTR);
});
Array.from(rootElement.querySelectorAll('li')).forEach(listItem => {
syncIdentityPair(listItem, LIST_ITEM_ID_ATTR, LIST_ITEM_RUNTIME_UUID_ATTR);
});
return this.ensureUniqueRuntimeUuids(rootElement);
},
getDirectItemTextSurface,
normalizePathIndexes,
buildPathMeta,
getRuntimeUuidAttributeName,
getListRuntimeUuidAttributeName() {
return LIST_RUNTIME_UUID_ATTR;
},
getListItemRuntimeUuidAttributeName() {
return LIST_ITEM_RUNTIME_UUID_ATTR;
},
getListIdAttributeName() {
return LIST_ID_ATTR;
},
getListItemIdAttributeName() {
return LIST_ITEM_ID_ATTR;
},
/**
* Destroy tracker and clean up
*/
destroy(tracker) {
if (!tracker) tracker = this.active;
if (!tracker) return;
tracker.uuidMap.clear();
tracker.runtimeUuidMap.clear();
if (tracker.listElement) {
delete tracker.listElement._mwpListTracker;
}
if (this.active === tracker) this.active = null;
}
};
/**
* Return whether one element is a live list node for runtime lookup helpers.
*
* @param {Element|null} element Candidate DOM element.
* @returns {boolean} True when the element is `UL` or `OL`.
*/
function isListElementForRuntimeLookup(element) {
return !!(
element &&
element.nodeType === Node.ELEMENT_NODE &&
(element.tagName === 'UL' || element.tagName === 'OL')
);
}
// Expose globally
SFE.ListBlockTracker = ListBlockTracker;
})();
.elementor-element,.elementor-lightbox{--swiper-theme-color:#000;--swiper-navigation-size:44px;--swiper-pagination-bullet-size:6px;--swiper-pagination-bullet-horizontal-gap:6px}.elementor-element .swiper .swiper-slide figure,.elementor-lightbox .swiper .swiper-slide figure{line-height:0}.elementor-element .swiper .elementor-lightbox-content-source,.elementor-lightbox .swiper .elementor-lightbox-content-source{display:none}.elementor-element .swiper .elementor-swiper-button,.elementor-element .swiper~.elementor-swiper-button,.elementor-lightbox .swiper .elementor-swiper-button,.elementor-lightbox .swiper~.elementor-swiper-button{color:hsla(0,0%,93%,.9);cursor:pointer;display:inline-flex;font-size:25px;position:absolute;top:50%;transform:translateY(-50%);z-index:1}.elementor-element .swiper .elementor-swiper-button svg,.elementor-element .swiper~.elementor-swiper-button svg,.elementor-lightbox .swiper .elementor-swiper-button svg,.elementor-lightbox .swiper~.elementor-swiper-button svg{fill:hsla(0,0%,93%,.9);height:1em;width:1em}.elementor-element .swiper .elementor-swiper-button-prev,.elementor-element .swiper~.elementor-swiper-button-prev,.elementor-lightbox .swiper .elementor-swiper-button-prev,.elementor-lightbox .swiper~.elementor-swiper-button-prev{left:10px}.elementor-element .swiper .elementor-swiper-button-next,.elementor-element .swiper~.elementor-swiper-button-next,.elementor-lightbox .swiper .elementor-swiper-button-next,.elementor-lightbox .swiper~.elementor-swiper-button-next{right:10px}.elementor-element .swiper .elementor-swiper-button.swiper-button-disabled,.elementor-element .swiper~.elementor-swiper-button.swiper-button-disabled,.elementor-lightbox .swiper .elementor-swiper-button.swiper-button-disabled,.elementor-lightbox .swiper~.elementor-swiper-button.swiper-button-disabled{opacity:.3}.elementor-element .swiper .swiper-image-stretch .swiper-slide .swiper-slide-image,.elementor-lightbox .swiper .swiper-image-stretch .swiper-slide .swiper-slide-image{width:100%}.elementor-element .swiper .swiper-horizontal>.swiper-pagination-bullets,.elementor-element .swiper .swiper-pagination-bullets.swiper-pagination-horizontal,.elementor-element .swiper .swiper-pagination-custom,.elementor-element .swiper .swiper-pagination-fraction,.elementor-element .swiper~.swiper-pagination-bullets.swiper-pagination-horizontal,.elementor-element .swiper~.swiper-pagination-custom,.elementor-element .swiper~.swiper-pagination-fraction,.elementor-lightbox .swiper .swiper-horizontal>.swiper-pagination-bullets,.elementor-lightbox .swiper .swiper-pagination-bullets.swiper-pagination-horizontal,.elementor-lightbox .swiper .swiper-pagination-custom,.elementor-lightbox .swiper .swiper-pagination-fraction,.elementor-lightbox .swiper~.swiper-pagination-bullets.swiper-pagination-horizontal,.elementor-lightbox .swiper~.swiper-pagination-custom,.elementor-lightbox .swiper~.swiper-pagination-fraction{bottom:5px}.elementor-element .swiper.swiper-cube .elementor-swiper-button,.elementor-element .swiper.swiper-cube~.elementor-swiper-button,.elementor-lightbox .swiper.swiper-cube .elementor-swiper-button,.elementor-lightbox .swiper.swiper-cube~.elementor-swiper-button{transform:translate3d(0,-50%,1px)}.elementor-element :where(.swiper-horizontal)~.swiper-pagination-bullets,.elementor-lightbox :where(.swiper-horizontal)~.swiper-pagination-bullets{bottom:5px;left:0;width:100%}.elementor-element :where(.swiper-horizontal)~.swiper-pagination-bullets .swiper-pagination-bullet,.elementor-lightbox :where(.swiper-horizontal)~.swiper-pagination-bullets .swiper-pagination-bullet{margin:0 var(--swiper-pagination-bullet-horizontal-gap,4px)}.elementor-element :where(.swiper-horizontal)~.swiper-pagination-progressbar,.elementor-lightbox :where(.swiper-horizontal)~.swiper-pagination-progressbar{height:4px;left:0;top:0;width:100%}.elementor-element.elementor-pagination-position-outside .swiper,.elementor-lightbox.elementor-pagination-position-outside .swiper{padding-bottom:30px}.elementor-element.elementor-pagination-position-outside .swiper .elementor-swiper-button,.elementor-element.elementor-pagination-position-outside .swiper~.elementor-swiper-button,.elementor-lightbox.elementor-pagination-position-outside .swiper .elementor-swiper-button,.elementor-lightbox.elementor-pagination-position-outside .swiper~.elementor-swiper-button{top:calc(50% - 30px / 2)}.elementor-element .elementor-swiper,.elementor-lightbox .elementor-swiper{position:relative}.elementor-element .elementor-main-swiper,.elementor-lightbox .elementor-main-swiper{position:static}.elementor-element.elementor-arrows-position-outside .swiper,.elementor-lightbox.elementor-arrows-position-outside .swiper{width:calc(100% - 60px)}.elementor-element.elementor-arrows-position-outside .swiper .elementor-swiper-button-prev,.elementor-element.elementor-arrows-position-outside .swiper~.elementor-swiper-button-prev,.elementor-lightbox.elementor-arrows-position-outside .swiper .elementor-swiper-button-prev,.elementor-lightbox.elementor-arrows-position-outside .swiper~.elementor-swiper-button-prev{left:0}.elementor-element.elementor-arrows-position-outside .swiper .elementor-swiper-button-next,.elementor-element.elementor-arrows-position-outside .swiper~.elementor-swiper-button-next,.elementor-lightbox.elementor-arrows-position-outside .swiper .elementor-swiper-button-next,.elementor-lightbox.elementor-arrows-position-outside .swiper~.elementor-swiper-button-next{right:0}/*! elementor-pro - v3.23.0 - 05-08-2024 */
"use strict";(self.webpackChunkelementor_pro=self.webpackChunkelementor_pro||[]).push([[253],{9999:(e,t,o)=>{var n=o(3203);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=n(o(2463));class LoopFilter extends elementorModules.editor.utils.Module{onElementorInit(){this.taxonomyFilter=new r.default("taxonomy-filter")}}t.default=LoopFilter},2463:(e,t,o)=>{var n=o(8003).__;const r=o(8200);e.exports=r.extend({__construct(){this.cache={},r.prototype.__construct.apply(this,arguments)},onInit(){elementor.channels.editor.on("editor:widget:taxonomy-filter:section_taxonomy_filter:activated",this.onTaxonomyFilterSectionActive)},onTaxonomyFilterSectionActive(){this.updateSelectedElementOptions();const e=this.getEditorControlView("selected_element").getControlValue();e&&this.updateTaxonomyOptions(e)},updateSelectedElementOptions(){const e=this.getEditorControlView("selected_element"),t=e.getControlValue();(t?elementor.$previewContents[0].querySelector(`[data-elementor-id="${elementor.config.document.id}"] .elementor-element-${t}`):"")||e.setValue("");const o=elementor.$previewContents[0].querySelectorAll(`[data-elementor-id="${elementor.config.document.id}"] .elementor-widget-loop-grid`),r={"":n("Select a widget","elementor-pro")};o.length||(this.updateOptions("selected_element",r),e.setValue(""));let s=1;for(const e of o)r[e.dataset.id]=`${n("Loop Grid","elementor-pro")} ${s++}`;this.updateOptions("selected_element",r)},onElementChange(e,t){if("selected_element"!==e)return;const o=t.getControlValue();o?this.updateTaxonomyOptions(o):this.updateOptions("taxonomy",{"":n("Select a taxonomy","elementor-pro")})},getPostSourceQueryPostType(e){const t=e.settings.attributes.post_query_post_type;let o="";switch(t){case"current_query":o=elementorPro.config.loopFilter.mainQueryPostType;break;case"by_id":case"related":o="post";break;default:o=t}return o},getLoopQueryPostType(e){const t=elementor.getContainer(e);return"post"===t.settings.attributes._skin?this.getPostSourceQueryPostType(t):"product"},updateTaxonomyOptions(e){const t=this.getLoopQueryPostType(e);return this.getPostTypeTaxonomies(t).then((e=>e instanceof Response?!e.ok||400<=e.status?(this.displayErrorDialog(),{}):e.json():e)).catch((()=>(this.displayErrorDialog(),{}))).then((e=>{let o=e?.data||e;Object.keys(o).length?(o={"":n("Select a taxonomy","elementor-pro"),...o},this.cache[t]=o,this.updateOptions("taxonomy",o)):this.updateOptions("taxonomy",{"":n("No taxonomies found","elementor-pro")})}))},getPostTypeTaxonomies(e){return this.cache[e]&&Object.keys(this.cache[e]).length?Promise.resolve(this.cache[e]):this.fetchPostTypeTaxonomies(e)},fetchPostTypeTaxonomies:e=>fetch(`${elementorCommon.config.urls.rest}elementor-pro/v1/get-post-type-taxonomies`,{method:"POST",headers:{"Content-Type":"application/json","X-WP-Nonce":elementorWebCliConfig.nonce},body:JSON.stringify({post_type:e})}),displayErrorDialog(){elementorCommon.dialogsManager.createWidget("alert",{id:"e-filter-error-message",className:"e-filter__error-message",headerMessage:n("Something went wrong","elementor-pro"),message:n("We are experiencing technical difficulties on our end. Please try again to reconnect.","elementor-pro"),position:{my:"center center",at:"center center"},strings:{confirm:n("OK","elementor-pro")}}).show()}})}}]);@font-face{font-family:"Rubik";src:url("fonts/Rubik-Regular.ttf") format("truetype");font-weight:normal;font-style:normal}@font-face{font-family:"Rubik";src:url("/fonts/Rubik-Bold.ttf") format("truetype");font-weight:bold;font-style:normal}#toplevel_page_tve_dash_section ul li.current a[href="admin.php?page=about_tve_theme_team"]{font-weight:600;color:#fff}.tve-about-us-content-wrapper{margin:0 0 0 -20px}html body #wpbody{font-family:Rubik,sans-serif;color:#434648;line-height:20px}#wpbody .tvd-header{margin:0 auto;padding:0 10%;display:flex;flex-direction:column;justify-content:space-between;align-items:baseline}#wpbody .tvd-header nav{height:auto !important}#wpbody .tvd-header div.tve-about-us-content{display:flex;flex-direction:row;justify-content:space-between;align-items:flex-start;padding:20px 0;gap:6%;letter-spacing:.03px;text-align:left;line-height:20px;color:#434648}#wpbody .tvd-header div.tve-about-us-content div.about-us{width:506px}#wpbody .tvd-header div.tve-about-us-content div.about-us p{line-height:20px;font-weight:400}#wpbody .tvd-header div.tve-about-us-content div.about-us p:first-child{margin:0 0 2rem 0;font-weight:700}#wpbody .tvd-header div.tve-about-us-content div.about-us p:last-child{margin:1rem 0 0 0}#wpbody .tvd-header div.tve-about-us-content div.about-us p span{font-weight:700}#wpbody .tvd-header div.tve-about-us-content div.about-us p a{color:#039be5;text-decoration:none}#wpbody .tvd-header div.tve-about-us-content div.the-tve-team{text-align:center;position:relative;flex:1}#wpbody .tvd-header div.tve-about-us-content div.the-tve-team img.image-behind-the-team{width:100%;height:auto;border-radius:13px 0 0 0;margin-bottom:15px}#wpbody .tvd-header div.tve-about-us-content div.the-tve-team div.image-info{text-align:center}.gt-page-header{margin:0 auto;padding:10px 10%;display:flex;flex-direction:row;justify-content:space-between;align-items:center;min-width:100%;min-height:100px}.gt-page-header div.gt-page-header-left{width:45%}.gt-page-header div.gt-page-header-left span{display:block}.gt-page-header div.gt-page-header-left .tvd-header-title{font-size:18px;line-height:23px;margin-bottom:6px}.gt-page-header div.gt-page-header-left .tvd-header-summary{color:#737d87}.gt-page-header div.tvd-filter{height:36px;display:flex;flex-direction:row;flex-wrap:nowrap;justify-content:space-between;align-items:flex-start;gap:20px}.gt-page-header div.tvd-filter .tvd-search-elem{position:relative;width:100%}.gt-page-header div.tvd-filter .tvd-search-elem input[type=search]{background:#fff;min-height:36px !important;max-height:36px !important;height:36px !important;border:1px solid #cdd3d8 !important;font-size:14px;color:#9a9ea9;line-height:19.6px;padding:0 40px 0 10px !important;width:258px;border-radius:4px;display:block;margin:0}.gt-page-header div.tvd-filter .tvd-search-elem input[type=search]::placeholder{font-size:14px;color:#9a9ea9;line-height:19.6px}.gt-page-header div.tvd-filter .tvd-search-elem input[type=search]:focus,.gt-page-header div.tvd-filter .tvd-search-elem input[type=search]:hover{outline:none;box-shadow:none !important;border-color:#9a9ea9 !important}.gt-page-header div.tvd-filter .tvd-search-elem input[type=search]:focus::placeholder,.gt-page-header div.tvd-filter .tvd-search-elem input[type=search]:hover::placeholder{color:#444648}.gt-page-header div.tvd-filter .tvd-search-elem .tvd-tools-search-icon,.gt-page-header div.tvd-filter .tvd-search-elem .tvd-clear-search-icon{position:absolute;border:none;background-color:#fff;cursor:pointer;right:11px;top:3px;padding:0;height:32px;display:flex;align-items:center;justify-content:center;transform:translate(0, 0)}.gt-page-header div.tvd-filter .tvd-search-elem .tvd-tools-search-icon:active,.gt-page-header div.tvd-filter .tvd-search-elem .tvd-tools-search-icon:focus,.gt-page-header div.tvd-filter .tvd-search-elem .tvd-tools-search-icon:visited,.gt-page-header div.tvd-filter .tvd-search-elem .tvd-clear-search-icon:active,.gt-page-header div.tvd-filter .tvd-search-elem .tvd-clear-search-icon:focus,.gt-page-header div.tvd-filter .tvd-search-elem .tvd-clear-search-icon:visited{background:none}.gt-page-header div.tvd-filter .tvd-search-elem .tvd-tools-search-icon svg{height:16px;width:16px;fill:#b0b9c1}.gt-page-header div.tvd-filter .tvd-search-elem .tvd-clear-search-icon svg{height:36px;width:36px}.gt-page-header div.tvd-filter .tvd-filter-tools span.select2-container{height:36px;width:220px !important;border:1px solid #cdd3d8;background:var(--colour-surface-screen, rgb(255, 255, 255));padding:0 25px 0 10px;margin:0;border-radius:4px;display:block;line-height:19.6px;text-align:left}.gt-page-header div.tvd-filter .tvd-filter-tools span.select2-container .select2-selection--single .select2-selection__rendered{color:#444648;line-height:36px;font-size:14px;padding-top:0;padding-bottom:0}.gt-page-header div.tvd-filter .tvd-filter-tools span.select2-container--open{border-radius:4px 4px 0 0}.select2-results__option{line-height:19.6px;text-align:left;color:#626670}.select2-results__option{padding-top:4px;padding-bottom:5px}.select2-container--default .select2-results__option--highlighted[aria-selected]{background:var(--colour-type-primary, rgb(68, 70, 72))}.select2-container--default .select2-results__option[aria-selected=true]{background:none}.select2-container--default .select2-selection--single{border-bottom:none}.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b{top:60%;border:none;background:url("drop-down-open.svg") no-repeat center center;background-size:contain;width:7px;height:7px;display:inline-block;content:""}.select2-container--default .select2-selection--single .select2-selection__arrow b{top:60%;border:none;background:url("drop-down-closed.svg") no-repeat center center;background-size:contain;width:7px;height:7px;display:inline-block;content:""}.select2-dropdown{margin-top:-8px;box-shadow:none;border:1px solid #cdd3d8;border-bottom-left-radius:4px;border-bottom-right-radius:4px}.select2-dropdown--below{padding-top:0;padding-bottom:2px}.select2-results__option{padding-top:4px;padding-bottom:5px}select.tools-category-select option{padding:20px 0 8px 12px !important;border:1px solid #bcbcbc !important}select.tools-category-select option:hover{background-color:#bcbcbc}.select2-container--default .select2-results__option--highlighted[aria-selected]{background:#f6f6f6 !important;color:#444648}.tvd-search-elem input[type=search]:hover+.tvd-tools-search-icon svg use{fill:#444648}.growth-tools-list{margin:0 auto;padding:1% 10% !important;display:flex;flex-direction:column;justify-content:space-between;align-items:center;min-width:100%}.growth-tools-list div.growth-tools-category-item{width:100%}.growth-tools-list div.growth-tools-category-item:first-child{margin:0}.growth-tools-list div.growth-tools-category-item:not(:first-child){margin:25px 0}.growth-tools-list div.growth-tools-category-item span.category-title{line-height:18.75px;letter-spacing:0;text-align:left;color:#434648;display:block;margin-bottom:8px}.growth-tools-list div.growth-tools-category-item div.growth-tools-card{border:1px solid rgba(205,211,216,.3019607843);background:#fff;padding:20px;border-radius:4px}.growth-tools-list div.growth-tools-category-item div.growth-tools-card .growth-tools-card-item{display:flex;flex-direction:row;justify-content:space-between;align-items:center;gap:20px}.growth-tools-list div.growth-tools-category-item div.growth-tools-card .growth-tools-card-item:not(:last-child){border-bottom:1px solid rgba(115,125,135,.2);padding-bottom:20px;margin-bottom:20px}.growth-tools-list div.growth-tools-category-item div.growth-tools-card .growth-tools-card-item div.growth-tool-logo{width:52px;height:52px;flex:none;display:flex;align-items:center;justify-content:center;margin:0;border:1px solid rgba(205,211,216,.3);border-radius:10px}.growth-tools-list div.growth-tools-category-item div.growth-tools-card .growth-tools-card-item div.growth-tool-logo svg{width:50px;height:50px;border-radius:10px;speak:none;display:inline-block;font-style:normal;font-weight:normal;font-variant:normal;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;transform:translate(0, 0)}.growth-tools-list div.growth-tools-category-item div.growth-tools-card .growth-tools-card-item div.growth-tool-content{flex:1;padding:0;min-width:auto;max-width:inherit}.growth-tools-list div.growth-tools-category-item div.growth-tools-card .growth-tools-card-item div.growth-tool-content>br{display:none}.growth-tools-list div.growth-tools-category-item div.growth-tools-card .growth-tools-card-item div.growth-tool-content span{line-height:18px;letter-spacing:0;text-align:left;color:#737d87;display:block}.growth-tools-list div.growth-tools-category-item div.growth-tools-card .growth-tools-card-item div.growth-tool-content span.tool-name{font-size:14px;font-weight:700;margin-bottom:5px;cursor:pointer;color:#202223}.growth-tools-list div.growth-tools-category-item div.growth-tools-card .growth-tools-card-item div.growth-tool-content span.tool-summary{font-size:13px;font-weight:400}.tve-btn{width:120px;height:36px;border-radius:3px;border:none;color:#fff;font-family:Rubik,sans-serif;font-size:14px;font-weight:500;line-height:16px;letter-spacing:-.1071429029px;text-align:center;transition:.3s;-webkit-transition:.3s;-moz-transition:.3s;-ms-transition:.3s;-o-transition:.3s}.tve-btn>span>svg{height:13px;width:13px;margin-bottom:-2px}svg.td-icon-learn-more,svg.td-icon-install-now,svg.td-icon-activate{margin-left:3px}svg.td-icon-get-started{margin-right:3px}.tve-btn-learn-more{background:#fff;color:#737d87;border:1px solid #cdd3d8}.tve-btn-learn-more:hover{background:rgba(205,211,216,.5);color:#737d87;border:1px solid #cdd3d8}.tve-btn-learn-more:active,.tve-btn-learn-more:focus{background:#fff;color:#737d87;border:1px solid #cdd3d8}.tve-btn-install-now{background:#32a2d3}.tve-btn-install-now:hover{background:#44c0f7}.tve-btn-install-now:active,.tve-btn-install-now:focus{background:#32a2d3}.tve-btn-action-installing{background:#32a2d3 linear-gradient(0deg, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2))}.tve-btn-action-activate{background:#32a2d3}.tve-btn-action-activate:hover{background:#44c0f7}.tve-btn-action-activate:focus,.tve-btn-action-activate:active{background:#32a2d3}.tve-btn-action-activating{background:#32a2d3 linear-gradient(0deg, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2))}.tve-btn-get-started{background:#4bb35e;border:1px solid #4bb35e}.tve-btn-get-started:hover{background:#6cd07f;border:1px solid #6cd07f}.tve-btn-get-started:active,.tve-btn-get-started:focus{background:#4bb35e;border:1px solid #4bb35e}.growth-tools-not-found{display:flex;align-items:center;flex-direction:column;justify-content:space-between;margin-top:20px}.growth-tools-not-found span{font-size:16px;line-height:18.75px;text-align:center;color:#434648;margin-bottom:20px}.growth-tools-not-found svg{display:block;height:70px;width:73px}@media(min-width: 1600px){#wpbody .tvd-header{width:1200px;padding:0 75px}.gt-page-header{width:1200px;padding:1% 0;min-width:0}.growth-tools-list div.growth-tools-category-item{width:1200px}}@media(max-width: 1360px){#wpbody .tvd-header div.tve-about-us-content div.about-us{width:460px}}@media(max-width: 1200px){#wpbody .tvd-header div.tve-about-us-content div.about-us{width:360px}}@media(max-width: 1160px){#wpbody .tvd-header{flex-direction:column;justify-content:flex-start;align-items:flex-start}#wpbody .tvd-header div.tve-about-us-content .about-us{width:360px}#wpbody .tvd-header div.tve-about-us-content div.the-tve-team{width:100%}#wpbody .tvd-header div.tve-about-us-content div.the-tve-team img.image-behind-the-team{width:100%;height:auto}.gt-page-header{flex-direction:column}.gt-page-header div.gt-page-header-left{width:100%}.gt-page-header div.tvd-filter{justify-content:flex-start;align-items:flex-start;margin-top:20px;gap:10px;margin-bottom:10px;width:100%}}@media(max-width: 768px){#wpbody .tvd-header div.tve-about-us-content{gap:6%}}@media(max-width: 1000px){#wpbody .tvd-header div.tve-about-us-content{flex-direction:column;gap:10px}#wpbody .tvd-header div.tve-about-us-content div.about-us{flex-direction:column;width:100%;padding:0;margin-bottom:10%}#wpbody .tvd-header div.tve-about-us-content div.the-tve-team img{width:100%;height:auto}}@media(max-width: 600px){#wpbody .tvd-header{padding:1% 10%}#wpbody .tvd-header div.tve-about-us-content{flex-direction:column;gap:10px}#wpbody .tvd-header div.tve-about-us-content div.about-us{flex-direction:column;padding:0;margin-bottom:10%}#wpbody .tvd-header div.tve-about-us-content div.the-tve-team img{width:100%;height:auto}.gt-page-header{flex-direction:column}.gt-page-header div.gt-page-header-left{width:100%}.gt-page-header div.tvd-filter{flex-direction:column;height:auto;margin-top:20px;gap:10px;margin-bottom:10px}.gt-page-header div.tvd-filter div.tvd-filter-tools,.gt-page-header div.tvd-filter div.tvd-filter-search,.gt-page-header div.tvd-filter div.tvd-search-elem input[type=search],.gt-page-header div.tvd-filter div.tvd-filter-tools span.select2-container{width:100% !important}.tvd-flex{align-items:normal}span.select2-container{width:100% !important;max-width:100%}.growth-tools-card .growth-tools-card-item{flex-direction:column;align-items:flex-start}}@media(max-width: 500px){.growth-tools-list div.growth-tools-category-item div.growth-tools-card .growth-tools-card-item{flex-direction:column}}
/**
* External dependencies
*/
import { text, boolean } from '@storybook/addon-knobs';
import {
useValidationContext,
ValidationContextProvider,
} from '@woocommerce/base-context';
/**
* Internal dependencies
*/
import CouponInput from '../';
export default {
title: 'WooCommerce Blocks/@base-components/CouponInput',
component: CouponInput,
};
const StoryComponent = ( { validCoupon, isLoading, invalidCouponText } ) => {
const { setValidationErrors } = useValidationContext();
const onSubmit = ( coupon ) => {
if ( coupon !== validCoupon ) {
setValidationErrors( { coupon: invalidCouponText } );
}
};
return ;
};
export const Default = () => {
const validCoupon = text( 'A valid coupon code', 'validcoupon' );
const invalidCouponText = text(
'Error message for invalid code',
'Invalid coupon code.'
);
const isLoading = boolean( 'Toggle isLoading state', false );
return (
);
};
(o=>{var t={loading:!1,init:function(){var t;o("a[data-embed-checkout]").length&&(t=this,o(document).on("click","a[data-embed-checkout]",function(e){e.preventDefault(),t.modal.open(o(this))}))},modal:{open:function(e){this.$target=e,this.product_url&&(this.product_url,this.product_url==e.data("embed-checkout"))||(this.product_url=e.data("embed-checkout")),this.show_checkout()},setup:function(){this.$el&&(this.$el.remove(),this.$el=null);var e=o("#udp-modal-template").html();this.$el=o(e),window.addEventListener("message",function(e){var t=e.data;if(t&&t.action)switch(t.action){case"domready":this.$el.removeClass("loading");break;case"closemodal":o(document).trigger("udp/checkout/close",t.data,this.$target),this.close();break;case"ordercomplete":console.log("Order complete:",t.data),o(document).trigger("udp/checkout/done",t.data,this.$target)}}.bind(this))},close:function(e){e&&e.preventDefault(),o("body").removeClass("udp-modal-is-opened"),this.$iframe&&(this.$iframe.remove(),this.$iframe_container.remove()),this.$el.hide()},show_checkout:function(){window.open(this.product_url,"_blank","noopener, noreferrer")}}};jQuery(function(e){t.init()})})(jQuery);(function ( $ ) {
/**
* Generate pie/doughnut charts
*
* Legend must be generated manually. If color is array (gradient), then legend won't show it.
*/
$.fn.vcRoundChart = function () {
this.each( function ( ) {
var data,
gradient,
chart,
i,
j,
$this = $( this ),
ctx = $this.find( 'canvas' )[ 0 ].getContext( '2d' ),
stroke_width = $this.data( 'vcStrokeWidth' ) ? parseInt( $this.data( 'vcStrokeWidth' ), 10 ) : 0,
options = {
showTooltips: $this.data( 'vcTooltips' ),
animationEasing: $this.data( 'vcAnimation' ),
segmentStrokeColor: $this.data( 'vcStrokeColor' ),
segmentShowStroke: 0 !== stroke_width,
segmentStrokeWidth: stroke_width,
responsive: true
},
color_keys = [
'color',
'highlight'
];
// If plugin has been called on already initialized element, reload it
if ( $this.data( 'chart' ) ) {
$this.data( 'chart' ).destroy();
}
data = $this.data( 'vcValues' );
ctx.canvas.width = $this.width();
ctx.canvas.height = $this.width();
// If color/highlight is array (of 2 colors), replace it with generated gradient
for ( i = data.length - 1;
0 <= i;
i -- ) {
for ( j = color_keys.length - 1;
0 <= j;
j -- ) {
if ( 'object' === typeof( data[ i ][ color_keys[ j ] ] ) && 2 === data[ i ][ color_keys[ j ] ].length ) {
gradient = ctx.createLinearGradient( 0, 0, 0, ctx.canvas.height );
gradient.addColorStop( 0, data[ i ][ color_keys[ j ] ][ 0 ] );
gradient.addColorStop( 1, data[ i ][ color_keys[ j ] ][ 1 ] );
data[ i ][ color_keys[ j ] ] = gradient;
}
}
}
if ( 'doughnut' === $this.data( 'vcType' ) ) {
chart = new Chart( ctx ).Doughnut( data, options );
} else {
chart = new Chart( ctx ).Pie( data, options );
}
$this.data( 'vcChartId', chart.id );
// We can later access chart to call methods on it
$this.data( 'chart', chart );
} );
return this;
};
/**
* Allows users to rewrite function inside theme.
*/
if ( 'function' !== typeof( window.vc_round_charts ) ) {
window.vc_round_charts = function ( model_id ) {
var selector = '.vc_round-chart';
if ( 'undefined' !== typeof( model_id ) ) {
selector = '[data-model-id="' + model_id + '"] ' + selector;
}
$( selector ).vcRoundChart();
};
}
$( document ).ready( function () {
! window.vc_iframe && vc_round_charts();
} );
}( jQuery ));
https://www.emiratesrdf.ae/page-sitemap.xml
2021-10-28T09:18:18+00:00
https://www.emiratesrdf.ae/category-sitemap.xml
2026-08-14T11:45:53+00:00
https://www.emiratesrdf.ae/post_tag-sitemap.xml
2026-08-14T11:45:53+00:00