Files
Jacek Pyziak cd264483f8 Add PSR HTTP Message Interfaces and Dependencies
- Implemented StreamInterface, UploadedFileInterface, and UriInterface as per PSR standards.
- Added getallheaders function to retrieve HTTP headers in a compatible manner.
- Included LICENSE files for ralouphie/getallheaders and symfony/deprecation-contracts.
- Introduced function for triggering deprecation notices in Symfony.
2025-12-28 12:44:00 +01:00

333 lines
12 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const { parse } = wp.blocks;
const { select, subscribe } = wp.data;
class blockDataReterive {
constructor() {
this.blockLists = [];
this.customBlockTranslateData = {};
this.customBlocksData = [];
this.loaderContainer = null;
this.init();
}
init = () => {
this.fetchCustomBlocks();
// Create full-page overlay and append to <body>
this.loaderContainer = document.createElement('div');
this.loaderContainer.className = 'atfp-overlay';
this.loaderContainer.setAttribute('role', 'status');
this.loaderContainer.setAttribute('aria-live', 'polite');
this.loaderContainer.innerHTML = this.getOverlayTemplate(); // see section 2
document.body.appendChild(this.loaderContainer);
document.body.classList.add('atfp-overlay-open');
}
getBlocks = (blocks) => {
const innerBlocks = (block) => {
const innerBlock = block.innerBlocks;
if (innerBlock.length > 0) {
innerBlock.forEach(innerBlock => {
this.customBlocksData.push(innerBlock);
innerBlocks(innerBlock);
});
}
}
const blockLists = blocks;
blockLists.forEach(block => {
innerBlocks(block);
});
this.customBlocksData = [...this.customBlocksData, ...blockLists];
this.getBlockData();
}
fetchCustomBlocks = () => {
/**
* Prepare data to send in API request.
*/
const apiSendData = {
atfp_nonce: atfp_block_update_object.ajax_nonce,
action: atfp_block_update_object.action_get_content
};
const apiUrl = atfp_block_update_object.ajax_url;
fetch(apiUrl, {
method: 'POST',
headers: {
'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
},
body: new URLSearchParams(apiSendData)
})
.then(response => response.json())
.then(data => {
if (data.message === 'No custom blocks found.') {
this.loaderContainer && this.loaderContainer.remove();
return;
}
const customBlocks = parse(data.data.block_data);
this.getBlocks(customBlocks);
// Save new block translate data
this.saveBlockData();
})
.catch(error => {
this.loaderContainer && this.loaderContainer.remove();
console.error('Error fetching block rules:', error);
});
}
saveBlockData = () => {
if (Object.keys(this.customBlockTranslateData).length < 1) {
this.loaderContainer && this.loaderContainer.remove();
return;
}
/**
* Prepare data to send in API request & update latest translate block data.
*/
const apiSendData = {
atfp_nonce: atfp_block_update_object.ajax_nonce,
action: atfp_block_update_object.action_update_content,
save_block_data: JSON.stringify(this.customBlockTranslateData)
};
const apiUrl = atfp_block_update_object.ajax_url;
fetch(apiUrl, {
method: 'POST',
headers: {
'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
},
body: new URLSearchParams(apiSendData)
})
.then(response => response.json())
.then(data => {
this.setOverlayState('success');
this.teardownOverlay();
if (data.success && data.data.message) {
console.log(data.data.message);
}
})
.catch(error => {
this.setOverlayState('error');
this.teardownOverlay();
console.error('Error fetching block rules:', error);
});
}
nestedAttrValue = (idsArr) => {
const convertToArrays = (obj) => {
// Check if obj is an object
if (typeof obj !== 'object' || obj === null) {
return obj;
}
// Process each key-value pair in the object
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// If the current value is an object and has the key 'atfp_array_key_replace'
if (typeof obj[key] === 'object' && obj[key] !== null && obj[key].hasOwnProperty('atfp_array_key_replace')) {
// Replace the value with 'true' directly in the array
obj[key] = Object.values(obj[key]);
obj[key] = convertToArrays(obj[key]);
} else {
// Recursively call convertToArrays for nested objects or arrays
obj[key] = convertToArrays(obj[key]);
}
}
}
return obj;
}
const deepMerge = (target, source) => {
for (const key in source) {
if (source[key] instanceof Object && key in target) {
Object.assign(source[key], deepMerge(target[key], source[key]));
}
}
Object.assign(target || {}, source);
return target;
};
let currentElement = {};
let tempObj = currentElement;
let lastKey = idsArr[idsArr.length - 1];
idsArr.slice(0, -1).forEach((key) => {
tempObj[key] = tempObj[key] || {};
tempObj = tempObj[key];
});
tempObj[lastKey] = true;
const obj = convertToArrays(currentElement);
deepMerge(this.customBlockTranslateData, obj);
}
filterAttr = (idsArray, value) => {
if (null === value || undefined === value) {
return;
}
if (Object.getPrototypeOf(value) === Array.prototype) {
this.filterBlockArrayAttr(idsArray, value);
} else if (Object.getPrototypeOf(value) === Object.prototype) {
this.filterBlockObjectAttr(idsArray, value);
} else if (typeof value === 'string' && /Make This Content Available for Translation/i.test(value)) {
this.nestedAttrValue(idsArray, value);
} else if (value instanceof wp.richText.RichTextData && /Make This Content Available for Translation/i.test(value.originalHTML)) {
this.nestedAttrValue(idsArray, value.originalHTML);
}
}
filterBlockArrayAttr = (idsArr, blockData) => {
const newIdArr = new Array(...idsArr);
newIdArr.push('atfp_array_key_replace');
blockData.forEach((value, key) => {
if ((typeof value === 'string' && /Make This Content Available for Translation/i.test(value)) || (![null, undefined].includes(value) && [Array.prototype, Object.prototype].includes(Object.getPrototypeOf(value)))) {
this.filterAttr(newIdArr, value)
};
});
}
filterBlockObjectAttr = (idsArr, blockData) => {
Object.keys(blockData).forEach(key => {
const newIdArr = new Array(...idsArr);
const value = blockData[key];
if (value !== null && value !== undefined) {
if ((typeof value === 'string' && /Make This Content Available for Translation/i.test(value)) || [Array.prototype, Object.prototype].includes(Object.getPrototypeOf(value))) {
newIdArr.push(key);
this.filterAttr(newIdArr, blockData[key]);
};
}
})
}
filterBlockAttribute = (blockData) => {
Object.keys(blockData).map(clientId => {
const blockName = Object.keys(blockData[clientId])[0];
const attributes = blockData[clientId][blockName];
Object.keys(attributes).forEach(keytwo => {
const value = attributes[keytwo];
const idsArray = new Array(blockName, "attributes", keytwo);
this.filterAttr(idsArray, value);
});
})
}
getBlockData = () => {
if (typeof this.customBlocksData !== 'object' || Object.keys(this.customBlocksData).length === 0) {
return;
}
const blockData = this.customBlocksData;
const blockAttributes = {};
Object.values(blockData).forEach(block => {
if (Object.values(block.attributes).length > 0) {
blockAttributes[block.clientId] = {};
blockAttributes[block.clientId][block.name] = block.attributes;
}
});
if (Object.values(blockAttributes).length > 0) {
this.filterBlockAttribute(blockAttributes);
}
}
setOverlayState = (state /* 'loading' | 'success' | 'error' */) => {
if (!this.loaderContainer) return;
const panel = this.loaderContainer.querySelector('.atfp-overlay .atfp-box');
if (panel) panel.setAttribute('data-state', state);
};
teardownOverlay = (delayMs = 3000) => {
if (!this.loaderContainer) return;
setTimeout(() => {
this.loaderContainer.classList.add('atfp-overlay--closing');
setTimeout(() => {
this.loaderContainer.remove();
this.loaderContainer = null;
document.body.classList.remove('atfp-overlay-open');
}, 300);
}, delayMs);
};
getOverlayTemplate = () => {
return `
<div class="atfp-overlay" role="status" aria-live="polite">
<div class="atfp-backdrop"></div>
<div class="atfp-box" data-state="loading">
<div class="atfp-row">
<span class="atfp-spinner" aria-hidden="true"></span>
<span class="atfp-icon atfp-icon--ok" aria-hidden="true">✓</span>
<span class="atfp-icon atfp-icon--err" aria-hidden="true">!</span>
<div class="atfp-text">
<div class="atfp-title" data-label="loading">Saving block content</div>
<div class="atfp-title" data-label="success">Supported block content has been updated</div>
<div class="atfp-title" data-label="error">Update failed</div>
<div class="atfp-desc" data-label="loading">
Please dont close or refresh this window until the update is complete.
</div>
<div class="atfp-desc" data-label="success">
Supported block content has been updated. You may continue.
</div>
<div class="atfp-desc" data-label="error">
Something went wrong. You can retry without closing this window.
</div>
</div>
</div>
<div class="atfp-bar"><span></span></div>
</div>
</div>
`;
}
}
const debounce = (func, delay) => {
let timeoutId;
return function (...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func.apply(this, args), delay);
};
};
let isBlockContentUpdating = false;
const saveBlockContent = debounce(() => {
new blockDataReterive();
isBlockContentUpdating = false;
}, 300);
if (select && select('core/editor') && subscribe) {
subscribe(() => {
const {
isCurrentPostPublished,
isSavingPost,
isPublishingPost,
isAutosavingPost,
} = select('core/editor');
const isAutoSaving = isAutosavingPost();
const isPublishing = isPublishingPost();
const isSaving = isSavingPost();
const postPublished = isCurrentPostPublished();
if ((isPublishing || (postPublished && isSaving)) && !isAutoSaving && !isBlockContentUpdating) {
isBlockContentUpdating = true;
saveBlockContent();
}
})
}