// Use bootstrap mixin for transition
.transition-all() {
.transition('all 0.3s ease-in-out');
}
// Condition select if @color is a color
// This mixin will do nothing if @color is not a color (like false or etc)
.if_color (@color, @property, @value) when (iscolor(@color)) {
@{property}: @value !important;
}
//Content
.vc_grid {
&.vc_row {
padding-left: 0;
padding-right: 0;
margin-left: 0;
margin-right: 0;
}
}
.vc-row[data-vc-full-width] {
.vc_grid.vc_row {
overflow: hidden;
}
}
@import "vc_grid_gap.less";
@import "../../params/vc_grid_item/vc_grid_item.less";
@import "vc_grid_style.less";
@import "vc_grid_loading.less";
// Import all other extensions
@import "vc_grid_filter.less";
@import "vc_grid_carousel.less";
/**
* API utilities - unified fetch wrapper and block-state loader
*
* Reads (from existing globals):
* SFE.ManagerData.restUrl - REST base URL
* SFE.ManagerData.nonce - WP nonce
* SFE.ManagerData.postId - current post ID
* SFE.ListBlockTracker
* SFE.Context.activeEditor - live reference via getter
*
* Exposes: SFE.Api
* {
* apiCall,
* hydrateEditorBlockStateOnOpen,
* fetchBlockAttributes,
* resolveMediaAttributes,
* queueResolvedMediaAttributes,
* ensureResolvedMediaAttributes
* }
*/
(function() {
'use strict';
window.MWP = window.MWP || {};
window.MWP.SFE = window.MWP.SFE || {};
const SFE = window.MWP.SFE;
SFE.ManagerData = SFE.ManagerData || {};
/**
* Unified API call handler with consistent error handling
*/
async function apiCall(endpoint, data, button = null) {
const restBase = (SFE.ManagerData.restUrl || '').replace(/\/$/, '');
const path = endpoint.startsWith('/') ? endpoint : '/' + endpoint;
const originalText = button?.textContent;
const wasDisabled = button?.disabled;
if (button) {
button.disabled = true;
button.setAttribute('mwp-sfe-btn-loading', 'true');
}
try {
const response = await fetch(restBase + path, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': SFE.ManagerData.nonce
},
body: JSON.stringify(data)
});
const result = await response.json();
if (!response.ok) {
const error = new Error(result?.error || `HTTP ${response.status}: ${response.statusText}`);
error.payload = result;
throw error;
}
// Check for error in response
if (result.success === false || result.error) {
const error = new Error(result.error || 'Operation failed');
error.payload = result;
throw error;
}
return result;
} catch (error) {
// Reset button state on error
if (button) {
button.disabled = wasDisabled || false;
button.removeAttribute('mwp-sfe-btn-loading');
if (originalText) button.textContent = originalText;
}
throw error;
}
}
function resolveBlockStateOverride(editorState) {
const publicApiBridge = SFE.PublicApiBridge || null;
const editorUuid = String(editorState?.uuid || '').trim();
if (
publicApiBridge &&
editorUuid &&
publicApiBridge.stagedBlockStates instanceof Map &&
publicApiBridge.stagedBlockStates.has(editorUuid)
) {
const stagedEntry = publicApiBridge.stagedBlockStates.get(editorUuid) || null;
publicApiBridge.stagedBlockStates.delete(editorUuid);
if (stagedEntry && stagedEntry.blockState) {
return publicApiBridge.clonePlainData(stagedEntry.blockState);
}
}
if (typeof SFE.ResolveBlockState === 'function') {
try {
const resolved = SFE.ResolveBlockState(editorState);
if (resolved) return resolved;
} catch (error) {
console.warn('FrontEdit: block-state resolver hook failed', error);
}
}
const batchManager = SFE.BatchEditManager || null;
if (
editorState?.saveStrategy === 'batch' &&
batchManager &&
typeof batchManager.isSessionActive === 'function' &&
batchManager.isSessionActive() &&
typeof batchManager.getBlockStateForUuid === 'function'
) {
return batchManager.getBlockStateForUuid(editorState.uuid);
}
return null;
}
function resolveMediaSourceFromAttributes(editorState, blockState) {
const schemaRuntime = SFE.SchemaRuntime || null;
if (!schemaRuntime || typeof schemaRuntime.resolveInitialMediaSource !== 'function') {
return '';
}
const resolved = schemaRuntime.resolveInitialMediaSource(editorState, blockState);
if (typeof resolved === 'string' && resolved.trim()) {
return resolved;
}
return '';
}
function shouldInitListTracker(editorState, blockState) {
const tagName = editorState?.element?.tagName || '';
const isListElement = tagName === 'OL' || tagName === 'UL';
if (!isListElement) return false;
const schemaRuntime = SFE.SchemaRuntime || null;
const hasSchemaListBinding = (
schemaRuntime &&
typeof schemaRuntime.hasListBinding === 'function' &&
schemaRuntime.hasListBinding(editorState)
);
return hasSchemaListBinding || blockState?.blockName === 'core/list';
}
/**
* Resolve canonical attachment attributes for the current editor state.
*
* This lets schema-driven media saves preserve block-level intent such as an
* existing `sizeSlug` on `core/image` while a new attachment is selected from
* the frontend editor.
*
* @param {object} editorState Current editor state.
* @param {object} [options]
* @param {string} [options.expectedResolutionKey] Stable selection key that
* must still match before the
* resolved payload is applied.
* @returns {Promise