GIF94;
| Path : /var/www/wordpress/wp-content/plugins/oxymade/assets/js/ |
| Current File : /var/www/wordpress/wp-content/plugins/oxymade/assets/js/paste-import.js |
/**
* OxyMade Paste Import - Auto-Import Classes from Pasted JSON
*
* Automatically detects and imports classes when you paste design JSON
* into the Oxygen editor's structure panel.
*
* This script is automatically loaded in Oxygen Builder edit mode.
* Simply paste your design JSON and classes will be imported automatically.
*/
(function() {
'use strict';
console.log('%c📦 OxyMade Paste Import Script Loaded!', 'color: purple; font-weight: bold;');
let store = null;
let initAttempts = 0;
const MAX_ATTEMPTS = 20; // Try for ~10 seconds (20 * 500ms)
// Wait for Oxygen to be ready
function initStore() {
initAttempts++;
let foundStore = null;
// Method 1: Try [data-node-id] elements (for when canvas has elements)
const nodeElements = document.querySelectorAll('[data-node-id]');
const firstNode = nodeElements?.[0];
if (firstNode && firstNode.__vue__) {
const vueInstance = firstNode.__vue__;
foundStore = vueInstance?.$root?.$store;
}
// Method 2: Search entire DOM for Vue instances with $store (works on blank canvas)
if (!foundStore) {
const allElements = document.querySelectorAll('*');
for (let el of allElements) {
if (el.__vue__) {
const vueInstance = el.__vue__;
const store = vueInstance?.$root?.$store;
if (store) {
foundStore = store;
break;
}
}
}
}
// Method 3: Try window.__BREAKDANCE_STORE__ (direct Breakdance store access)
if (!foundStore && window.__BREAKDANCE_STORE__) {
foundStore = window.__BREAKDANCE_STORE__;
}
store = foundStore;
if (store) {
setupPasteDetection();
console.log('%c✅ OxyMade Paste Import Ready!', 'color: green; font-weight: bold;');
} else if (initAttempts < MAX_ATTEMPTS) {
// Retry in 500ms if store not found
setTimeout(initStore, 500);
}
}
// Get nonce
function findNonce() {
if (window.oxymadeSettings?.breakdanceNonce) {
return window.oxymadeSettings.breakdanceNonce;
}
const nonceProp = Object.keys(window).find(key =>
(key.includes('nonce') || key.includes('Nonce')) &&
typeof window[key] === 'string' &&
window[key].length > 20
);
if (nonceProp) {
return window[nonceProp];
}
return null;
}
// Function to add a class to Oxygen
function importClass(selector) {
if (!store) return false;
const nonce = findNonce();
if (!nonce) {
console.error('❌ Cannot save: No nonce found');
return false;
}
try {
const allSelectors = store.state.global.oxySelectors;
// Preserve original properties and wrap CSS if needed
const properties = JSON.parse(JSON.stringify(selector.properties || {}));
// Wrap CSS with %%selector%% if not already wrapped (check all breakpoints)
Object.keys(properties).forEach(breakpoint => {
if (properties[breakpoint]?.custom_css?.custom_css) {
let css = properties[breakpoint].custom_css.custom_css;
if (css && !css.includes('%%selector%%') && !css.includes(':selector')) {
properties[breakpoint].custom_css.custom_css = '%%selector%% { ' + css + ' }';
}
}
});
// Create selector object - preserve all original properties
const newSelector = {
id: selector.id,
name: selector.name,
type: 'class',
collection: selector.collection || 'Imported',
properties: properties,
children: selector.children || [],
locked: selector.locked || false
};
// Check if selector already exists
const existingIndex = allSelectors.findIndex(s => s.id === selector.id);
if (existingIndex >= 0) {
allSelectors[existingIndex] = newSelector;
} else {
allSelectors.push(newSelector);
}
return selector.name;
} catch (error) {
console.error('❌ Error importing class:', error.message);
return false;
}
}
// Note: Selectors are automatically saved by Oxygen's built-in store sync
// No separate AJAX call needed - they're already persistent in the Vuex store
// Main import function
window.importDesignJSON = function(jsonString) {
try {
const data = JSON.parse(jsonString);
if (!data.selectors || !Array.isArray(data.selectors)) {
console.error('❌ No selectors found in pasted JSON');
return false;
}
const importedNames = [];
const skippedNames = [];
const allSelectors = store.state.global.oxySelectors;
const seenIds = new Set(); // Track IDs we've already processed in this paste
data.selectors.forEach(selector => {
// Skip duplicates within the same paste
if (seenIds.has(selector.id)) {
return;
}
seenIds.add(selector.id);
const existingIndex = allSelectors.findIndex(s => s.id === selector.id);
if (existingIndex >= 0) {
// Already exists in store, skip it
skippedNames.push(selector.name);
} else {
// New selector, import it
const result = importClass(selector);
if (result) {
importedNames.push(result);
}
}
});
// Only log if there's something to report
if (importedNames.length > 0 || skippedNames.length > 0) {
let message = '';
if (importedNames.length > 0) {
message += `✅ Created ${importedNames.length} custom selector(s): [${importedNames.join(', ')}]`;
}
if (skippedNames.length > 0) {
if (message) message += ' | ';
message += `⏭️ Skipped ${skippedNames.length} existing: [${skippedNames.join(', ')}]`;
}
console.log(`%c${message}`, 'color: green; font-weight: bold;');
}
return true;
} catch (error) {
console.error('❌ JSON Parse Error:', error.message);
return false;
}
};
// Paste Detection - Listen for paste events across all contexts
function setupPasteDetection() {
let lastPastedText = null;
let lastPasteTime = 0;
let processingPaste = false;
const handlePaste = function(event) {
try {
// Prevent re-entrance during processing
if (processingPaste) {
return;
}
const clipboardData = event.clipboardData || window.clipboardData;
const pastedText = clipboardData.getData('text');
// Check if it looks like our design JSON
if (!pastedText.includes('"element"') || !pastedText.includes('"selectors"')) {
return; // Not design JSON, ignore
}
// Prevent duplicate handling of the same paste event
// Check both time and content to catch rapid duplicate events
const now = Date.now();
if (pastedText === lastPastedText && now - lastPasteTime < 200) {
return; // Same paste content within 200ms, already handled
}
lastPastedText = pastedText;
lastPasteTime = now;
processingPaste = true;
// Import the selectors
window.importDesignJSON(pastedText);
// Allow new pastes after a short delay
setTimeout(() => {
processingPaste = false;
}, 150);
} catch (error) {
console.error('❌ Error in paste handler:', error.message);
processingPaste = false;
}
};
// Listen on multiple targets with capture phase to catch pastes from all contexts
// (side panels, structure panel, main editor, etc.)
window.addEventListener('paste', handlePaste, true);
document.addEventListener('paste', handlePaste, true);
if (document.body) {
document.body.addEventListener('paste', handlePaste, true);
}
// Also listen on parent window if we're in an iframe
try {
if (window.parent && window.parent !== window) {
window.parent.addEventListener('paste', handlePaste, true);
}
} catch (error) {
// Cross-origin iframe, can't access parent - that's ok
}
}
// Initialize when document is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initStore);
} else {
setTimeout(initStore, 100);
}
})();