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.
This commit is contained in:
@@ -0,0 +1,312 @@
|
||||
'use strict';
|
||||
|
||||
(() => {
|
||||
const { createBlock } = wp.blocks;
|
||||
const { dispatch, select } = wp.data;
|
||||
class atfpCreateNewBlock {
|
||||
constructor() {
|
||||
this.updateBlockStore = {};
|
||||
this.loaderRemove = null;
|
||||
this.loader = null;
|
||||
this.replaceAttributes = null;
|
||||
this.updateBlockId = new Array();
|
||||
}
|
||||
|
||||
copyTranslateText = () => {
|
||||
// Get the current selection object
|
||||
const selection = window.getSelection();
|
||||
// Create a new range object
|
||||
const range = document.createRange();
|
||||
// Select the contents of the copy text element
|
||||
range.selectNodeContents(document.getElementById('atfp-copy-text'));
|
||||
// Remove any existing selections
|
||||
selection.removeAllRanges();
|
||||
// Add the new range to the selection
|
||||
selection.addRange(range);
|
||||
// Execute the copy command
|
||||
document.execCommand('copy');
|
||||
// Clear the selection
|
||||
selection.removeAllRanges();
|
||||
}
|
||||
|
||||
noticeInitialize = () => {
|
||||
dispatch("core/notices").createNotice('info', 'To enable translation, please include the Make This Content Available for Translation text in your block content. For help, watch the video and click <b>"Copy Text"</b> to use. Then, paste it into the section of your block you want automatically translated',
|
||||
{
|
||||
isDismissible : false,
|
||||
id: 'atfp-notice-id',
|
||||
actions: [
|
||||
{
|
||||
label: 'Watch Video.',
|
||||
url: `${atfpAddBlockVars.atfp_demo_page_url}#custom-block-translate`,
|
||||
},
|
||||
],
|
||||
__unstableHTML: true
|
||||
}).then(()=>{
|
||||
const targetAnchor=document.querySelector(`a[href^="${atfpAddBlockVars.atfp_demo_page_url}#custom-block-translate"]`);
|
||||
|
||||
if(targetAnchor){
|
||||
targetAnchor.addEventListener('click', (e)=>{
|
||||
e.preventDefault();
|
||||
window.open(targetAnchor.href, '_blank');
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
copyBtnInitialize = () => { // Initialize the copy button
|
||||
const copyBtn = document.createElement('div'); // Create a new div element for the copy button
|
||||
copyBtn.id = 'atfp-copy-btn'; // Set the ID of the copy button
|
||||
copyBtn.innerHTML = 'Copy Text'; // Set the inner HTML of the copy button
|
||||
copyBtn.addEventListener('click', this.copyTranslateText); // Add click event listener to copy text
|
||||
copyBtn.ariaLabel = 'Copy Text'; // Set the aria-label for accessibility
|
||||
copyBtn.title = 'Click to copy the text "Make This Content Available for Translation"'; // Tooltip message
|
||||
|
||||
const copyText = document.createElement('div'); // Create a new div element for the copy text
|
||||
copyText.id = 'atfp-copy-text'; // Set the ID of the copy text div
|
||||
copyText.innerHTML = 'Make This Content Available for Translation'; // Set the inner HTML of the copy text div
|
||||
|
||||
document.body.appendChild(copyBtn); // Append the copy button to the document body
|
||||
document.body.appendChild(copyText); // Append the copy text to the document body
|
||||
}
|
||||
|
||||
addBlockInitialize = (newBlock) => {
|
||||
this.newBlock = newBlock;
|
||||
this.creteNewBlock();
|
||||
this.skeletonLoader();
|
||||
}
|
||||
|
||||
removeLoader = () => {
|
||||
clearTimeout(this.loaderRemove);
|
||||
|
||||
this.loaderRemove = setTimeout(() => {
|
||||
if (this.loader) {
|
||||
this.loader.remove();
|
||||
}
|
||||
}, 2000);
|
||||
|
||||
}
|
||||
|
||||
creteNewBlock = () => {
|
||||
const newBlock = createBlock(this.newBlock);
|
||||
this.updateBlockData(newBlock);
|
||||
}
|
||||
|
||||
updateBlockData = async (Block) => {
|
||||
await dispatch('core/block-editor').insertBlocks([Block]);
|
||||
|
||||
setTimeout(() => {
|
||||
const blockWrp = document.getElementById(`block-${Block.clientId}`);
|
||||
if (blockWrp) {
|
||||
blockWrp.appendChild(this.loader);
|
||||
}
|
||||
}, 100);
|
||||
|
||||
setTimeout(() => {
|
||||
this.updateBlockContent(Block);
|
||||
}, 400);
|
||||
}
|
||||
|
||||
updateBlockContent = (Block) => {
|
||||
const newBlock = document.getElementById(`block-${Block.clientId}`);
|
||||
|
||||
if (newBlock) {
|
||||
this.updateContent(newBlock);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
updateContent = async (ele) => {
|
||||
const element = ele;
|
||||
let i = 1;
|
||||
this.removeLoader();
|
||||
|
||||
if (element) {
|
||||
if (element.contentEditable == 'true' && element.children.length < 2) {
|
||||
element.innerHTML = 'Make This Content Available for Translation';
|
||||
} else {
|
||||
const innerElements = element.getElementsByTagName('*');
|
||||
|
||||
for (let innerElement of innerElements) {
|
||||
if (i === innerElements.length) {
|
||||
this.removeLoader();
|
||||
setTimeout(() => {
|
||||
this.updateBlockFromStore();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
i++;
|
||||
if (["SCRIPT", "STYLE", "META", "LINK", "TITLE", "NOSCRIPT", "STYLE", "SCRIPT", "NOSCRIPT", "STYLE", "SCRIPT", "NOSCRIPT", "STYLE", "SCRIPT", "NOSCRIPT"].includes(innerElement.tagName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (innerElement.childNodes.length > 0) {
|
||||
innerElement.childNodes.forEach((child) => {
|
||||
if (child.nodeType === Node.TEXT_NODE) {
|
||||
this.updateBlockAttr(innerElement, child);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateBlockAttr = (innerElement, child) => {
|
||||
let blockId = false;
|
||||
if (innerElement.classList.contains('wp-block')) {
|
||||
blockId = innerElement.dataset.block;
|
||||
} else {
|
||||
const parentBlock = innerElement.closest('.wp-block');
|
||||
if (parentBlock) {
|
||||
blockId = parentBlock.dataset.block;
|
||||
}
|
||||
}
|
||||
|
||||
const blockAttributes = select('core/block-editor').getBlockAttributes(blockId);
|
||||
|
||||
let index = 0;
|
||||
|
||||
if (!this.updateBlockStore[blockId]) {
|
||||
let attributes = JSON.parse(JSON.stringify(blockAttributes));
|
||||
this.updateBlockStore[blockId] = { attributes: attributes };
|
||||
this.updateBlockStore[blockId].updateBlockData = {};
|
||||
}
|
||||
|
||||
const updateNestedAttributes = async (attributes, child) => {
|
||||
const updateAttributes = async (key) => {
|
||||
index++;
|
||||
|
||||
if (typeof attributes[key] === 'string' && attributes[key].trim() !== '' && (attributes[key].trim() === child.textContent.trim() || attributes[key] === child.textContent.trim())) {
|
||||
const originalValue = attributes[key];
|
||||
const newValue = 'Make This Content Available for Translation ' + index;
|
||||
this.updateBlockStore[blockId].updateBlockData[newValue.replace(/\s+/g, '-')] = originalValue;
|
||||
attributes[key] = newValue;
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof attributes === 'object' && attributes !== null) {
|
||||
for (const key of Object.keys(attributes)) {
|
||||
await updateAttributes(key);
|
||||
|
||||
if (typeof attributes[key] === 'object' && attributes[key] !== null) {
|
||||
await updateNestedAttributes(attributes[key], child); // Recursively update nested objects
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const blockStoreAttributes = this.updateBlockStore[blockId].attributes;
|
||||
updateNestedAttributes(blockStoreAttributes, child);
|
||||
}
|
||||
|
||||
updateBlockFromStore = () => {
|
||||
const blockStoreAttributes = this.updateBlockStore;
|
||||
|
||||
Object.keys(blockStoreAttributes).forEach((blockId) => {
|
||||
const blockAttributes = blockStoreAttributes[blockId].attributes;
|
||||
this.removeLoader();
|
||||
dispatch('core/block-editor').updateBlockAttributes(blockId, blockAttributes).then(() => {
|
||||
clearTimeout(this.replaceAttributes);
|
||||
this.replaceAttributes = setTimeout(() => {
|
||||
this.removeLoader();
|
||||
const blockIds = Object.keys(this.updateBlockStore);
|
||||
this.replaceBlockContent(blockIds[0]);
|
||||
}, 500);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
replaceBlockContent = (blockId) => {
|
||||
const blockStoreAttributes = this.updateBlockStore;
|
||||
|
||||
const checkValidAttributes = (value = false, blockId) => {
|
||||
const blockElement = document.querySelector(`#block-${blockId}`);
|
||||
const regex = new RegExp(value, 'g'); // Create regex from the value parameter with global flag
|
||||
const matchFound = regex.test(blockElement.innerText); // Check if the regex matches
|
||||
return matchFound; // Return the result of the regex test directly
|
||||
};
|
||||
|
||||
const blockAttributes = blockStoreAttributes[blockId].attributes;
|
||||
|
||||
const upateNestedAttributes = async (attributes) => {
|
||||
const updateAttributes = async (key) => {
|
||||
|
||||
if (typeof attributes[key] === 'string' && attributes[key].includes('Make This Content Available for Translation')) {
|
||||
try {
|
||||
const keyWithDashes = attributes[key].replace(/\s+/g, '-');
|
||||
const originalValue = this.updateBlockStore[blockId].updateBlockData[keyWithDashes];
|
||||
|
||||
const status = checkValidAttributes(attributes[key], blockId);
|
||||
|
||||
if (!status) {
|
||||
attributes[key] = originalValue;
|
||||
} else {
|
||||
attributes[key] = 'Make This Content Available for Translation';
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(`${attributes[key]} is not valid JSON.`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof attributes === 'object' && attributes !== null) {
|
||||
for (const key of Object.keys(attributes)) {
|
||||
await updateAttributes(key);
|
||||
|
||||
if (typeof attributes[key] === 'object' && attributes[key] !== null) {
|
||||
await upateNestedAttributes(attributes[key]); // Recursively update nested objects
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
upateNestedAttributes(blockAttributes);
|
||||
|
||||
setTimeout(() => {
|
||||
dispatch('core/block-editor').updateBlockAttributes(blockId, blockAttributes).then(() => {
|
||||
const blockIds = Object.keys(this.updateBlockStore);
|
||||
if (blockIds.length > 0) {
|
||||
this.updateBlockId.push(blockId);
|
||||
dispatch('core/block-editor').selectBlock(null);
|
||||
this.removeLoader();
|
||||
const firstBlockId = blockIds.find(id => !this.updateBlockId.includes(id));
|
||||
if (firstBlockId) {
|
||||
this.replaceBlockContent(firstBlockId);
|
||||
}
|
||||
}
|
||||
});
|
||||
}, 500);
|
||||
}
|
||||
|
||||
skeletonLoader = () => {
|
||||
const loader = document.createElement('div');
|
||||
|
||||
const loaderContainer = () => {
|
||||
const container = '<style>.atfp-loader-wrapper{position:absolute;width:100%;height:100%;top:0;left:0;z-index:99999;}.atfp-loader-container{width:100%;height:100%;}.atfp-loader-skeleton{--skbg:hsl(227deg, 13%, 50%, 0.2);display:grid;gap:20px;width:100%;height:100%;background:#ffffff;padding:15px;border-radius:8px;box-shadow:0 4px 12px rgba(0, 0, 0, 0.1);transition:transform 0.3s ease;transform:scale(1.02);}.atfp-loader-shimmer{display:flex;aspect-ratio:2/1;width:100%;height:100%;background:var(--skbg);border-radius:4px;overflow:hidden;position:relative;}.atfp-loader-shimmer::before{content:"";position:absolute;width:100%;height:100%;background-image:linear-gradient(-90deg,transparent 8%,rgba(255,255,255,0.28) 18%,transparent 33%);background-size:200%;animation:shimerAnimate 1.5s ease-in-out infinite;}@keyframes shimerAnimate{0%{background-position:100% 0;}100%{background-position:-100% 0;}}</style>'
|
||||
|
||||
return '<div class="atfp-loader-container">' + container + '<div class="atfp-loader-skeleton"><span class="atfp-loader-shimmer"></span></div></div>';
|
||||
}
|
||||
|
||||
loader.className = 'atfp-loader-wrapper'; // Add the atfp class to the loader
|
||||
loader.innerHTML = loaderContainer();
|
||||
|
||||
this.loader = loader;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
const atfpCreateBlockObj = new atfpCreateNewBlock();
|
||||
|
||||
atfpCreateBlockObj.copyBtnInitialize();
|
||||
atfpCreateBlockObj.noticeInitialize();
|
||||
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
let newBlock = '';
|
||||
|
||||
if (urlParams.has('atfp_new_block') && '' !== urlParams.get('atfp_new_block').trim()) {
|
||||
newBlock = urlParams.get('atfp_new_block');
|
||||
atfpCreateBlockObj.addBlockInitialize(newBlock);
|
||||
}
|
||||
});
|
||||
})();
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,34 @@
|
||||
jQuery(document).ready(function(){
|
||||
const atfpSubsubsubList = jQuery('.atfp_subsubsub');
|
||||
const atfpBulkTranslateBtn = jQuery('.atfpp-bulk-translate-btn');
|
||||
|
||||
if(atfpSubsubsubList.length){
|
||||
const $defaultSubsubsub = jQuery('ul.subsubsub:not(.atfp_subsubsub_list)');
|
||||
|
||||
if($defaultSubsubsub.length){
|
||||
$defaultSubsubsub.after(atfpSubsubsubList);
|
||||
atfpSubsubsubList.show();
|
||||
}
|
||||
}
|
||||
|
||||
if(atfpBulkTranslateBtn.length){
|
||||
const $defaultFilter = jQuery('.actions:not(.bulkactions)');
|
||||
const $bulkAction=jQuery('.actions.bulkactions');
|
||||
|
||||
if($defaultFilter.length){
|
||||
$defaultFilter.each(function(){
|
||||
const clone=atfpBulkTranslateBtn.clone(true);
|
||||
jQuery(this).append(clone);
|
||||
clone.show();
|
||||
});
|
||||
|
||||
atfpBulkTranslateBtn.remove();
|
||||
}else if($bulkAction.length){
|
||||
$bulkAction.each(function(){
|
||||
const clone=atfpBulkTranslateBtn.clone(true);
|
||||
jQuery(this).after(clone);
|
||||
clone.show();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,221 @@
|
||||
class BlockFilterSorter {
|
||||
constructor() {
|
||||
this.tableBody = document.querySelector('.atfp-custom-data-table-table tbody');
|
||||
this.filters = document.querySelectorAll('.atfp-custom-data-table-filters .atfp-filter-tab');
|
||||
this.atfpDataTableObj = null;
|
||||
this.saveButtonEnabled = false;
|
||||
this.saveButtonText = false;
|
||||
this.saveButtonClass = false;
|
||||
this.saveButtonAction = false;
|
||||
this.saveButtonNonce = false;
|
||||
this.displayAjaxNotice=false;
|
||||
this.ajaxUrl = false;
|
||||
|
||||
if (window.atfpCustomTableDataObject) {
|
||||
if (atfpCustomTableDataObject.save_button_enabled && '' !== atfpCustomTableDataObject.save_button_enabled) {
|
||||
this.saveButtonEnabled = atfpCustomTableDataObject.save_button_enabled;
|
||||
}
|
||||
if (atfpCustomTableDataObject.save_button_text && '' !== atfpCustomTableDataObject.save_button_text) {
|
||||
this.saveButtonText = atfpCustomTableDataObject.save_button_text;
|
||||
}
|
||||
if (atfpCustomTableDataObject.save_button_class && '' !== atfpCustomTableDataObject.save_button_class) {
|
||||
this.saveButtonClass = atfpCustomTableDataObject.save_button_class;
|
||||
}
|
||||
if (atfpCustomTableDataObject.save_button_handler && '' !== atfpCustomTableDataObject.save_button_handler) {
|
||||
this.saveButtonAction = atfpCustomTableDataObject.save_button_handler;
|
||||
}
|
||||
if (atfpCustomTableDataObject.save_button_nonce && '' !== atfpCustomTableDataObject.save_button_nonce) {
|
||||
this.saveButtonNonce = atfpCustomTableDataObject.save_button_nonce;
|
||||
}
|
||||
if (atfpCustomTableDataObject.admin_url && '' !== atfpCustomTableDataObject.admin_url) {
|
||||
this.ajaxUrl = atfpCustomTableDataObject.admin_url;
|
||||
}
|
||||
|
||||
const inputFields = document.querySelectorAll('#atfp-custom-datatable tbody input[name="atfp_fields_status"]');
|
||||
inputFields.forEach(input => {
|
||||
input.addEventListener('change', this.updateStatusHandler.bind(this));
|
||||
});
|
||||
}
|
||||
|
||||
if (this.tableBody) {
|
||||
this.atfpDataTable();
|
||||
|
||||
this.filters.forEach(filter => {
|
||||
filter.addEventListener('input', this.datatableFilterHandler.bind(this));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
atfpDataTable() {
|
||||
if (this.tableBody) {
|
||||
this.atfpDataTableObj = new DataTable('#atfp-custom-datatable', {
|
||||
pageLength: 25,
|
||||
infoCallback: function (settings, start, end, total, max) {
|
||||
return `Showing ${start} to ${end} of ${max} records`;
|
||||
}
|
||||
});
|
||||
|
||||
this.atfpDataTableObj.on('draw.dt', function (e) {
|
||||
const rows = jQuery(this).find('tbody tr');
|
||||
|
||||
if (rows.length.length === 0) {
|
||||
this.atfpDataTableObj.empty();
|
||||
}
|
||||
|
||||
const length = e.dt.page.info().length;
|
||||
const page = e.dt.page.info().page;
|
||||
|
||||
rows.each(function (index, row) {
|
||||
const emptyCell = row.querySelector('td.dt-empty');
|
||||
if (!emptyCell) {
|
||||
row.children[0].textContent = (page * length) + index + 1;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const tableWrp = document.getElementById('atfp-custom-datatable_wrapper');
|
||||
const selectWrapper = document.querySelector('.atfp-custom-data-table-filters');
|
||||
selectWrapper.remove();
|
||||
tableWrp.prepend(selectWrapper);
|
||||
|
||||
if (this.saveButtonEnabled && '' !== this.saveButtonText && 'false' !== this.saveButtonText) {
|
||||
const saveButton = this.appendSaveButton();
|
||||
const lastRow = tableWrp.querySelector('.dt-layout-row:last-child');
|
||||
lastRow.before(saveButton);
|
||||
|
||||
jQuery(`.${this.saveButtonClass}`).on('click', this.saveButtonHandler.bind(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
datatableFilterHandler(e) {
|
||||
if (this.atfpDataTableObj) {
|
||||
let value = e.target.value;
|
||||
let wrapper = e.target.closest('.atfp-filter-tab');
|
||||
let column = parseInt(wrapper.dataset.column);
|
||||
let defaultValue = wrapper.dataset.default;
|
||||
value = value === defaultValue ? false : value;
|
||||
this.atfpDataTableObj.column(column).search(value ? new RegExp('^' + value, 'i') : '', false, false, false).draw();
|
||||
}
|
||||
}
|
||||
|
||||
updateStatusHandler(e) {
|
||||
const table = jQuery('#atfp-custom-datatable').DataTable();
|
||||
|
||||
if (!table) return; // DataTable not initialized
|
||||
|
||||
const $tr = jQuery(e.target).closest('tr');
|
||||
if (!$tr.length) return; // no row found
|
||||
|
||||
const dtRow = table.row($tr);
|
||||
if (!dtRow.node()) return; // row doesn’t exist in DataTable
|
||||
|
||||
const checked = e.target.checked;
|
||||
const status = checked ? 'Supported' : 'Unsupported';
|
||||
|
||||
// Make sure cell exists
|
||||
const cell = dtRow.cell(dtRow.index(), 3);
|
||||
if (!cell) return;
|
||||
|
||||
// Update via DataTables API
|
||||
cell.data(status);
|
||||
}
|
||||
|
||||
saveButtonHandler(e) {
|
||||
e.preventDefault();
|
||||
const saveBtns = jQuery(`.${this.saveButtonClass}`);
|
||||
|
||||
if (saveBtns.hasClass('saving')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.saveButtonAction || '' === this.saveButtonAction || !this.saveButtonNonce || '' === this.saveButtonNonce || !this.ajaxUrl || '' === this.ajaxUrl) {
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedCheckbox = [];
|
||||
const tdNodes = this.atfpDataTableObj.column(4).nodes();
|
||||
|
||||
if (tdNodes.length > 0) {
|
||||
Array.from(tdNodes).forEach(tdNode => {
|
||||
const checkbox = tdNode.querySelector('input[type="checkbox"]');
|
||||
if (checkbox && checkbox.checked) {
|
||||
selectedCheckbox.push(checkbox.value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (selectedCheckbox.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const apiSendData = {
|
||||
action: this.saveButtonAction,
|
||||
atfp_nonce: this.saveButtonNonce,
|
||||
save_custom_fields_data: JSON.stringify(selectedCheckbox)
|
||||
};
|
||||
|
||||
saveBtns.addClass('saving').html('<span class="saving-text">Saving<span class="dot" style="--i:0"></span><span class="dot" style="--i:1"></span><span class="dot" style="--i:2"></span></span>', true);
|
||||
|
||||
fetch(this.ajaxUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
body: new URLSearchParams(apiSendData)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
saveBtns.removeClass('saving').html(this.saveButtonText, true);
|
||||
|
||||
if (data.success) {
|
||||
if (data.data.message) {
|
||||
this.appendMessageNotice(data.data.message, 'success');
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error);
|
||||
if (error.data.message) {
|
||||
this.appendMessageNotice(data.data.message, 'error');
|
||||
}
|
||||
saveBtns.removeClass('saving').html(this.saveButtonText, true);
|
||||
console.error(error);
|
||||
});
|
||||
}
|
||||
|
||||
appendMessageNotice(message, type) {
|
||||
|
||||
if(this.displayAjaxNotice){
|
||||
jQuery('#atfp-custom-fields-message-notice').remove();
|
||||
clearTimeout(this.displayAjaxNotice);
|
||||
}
|
||||
|
||||
this.displayAjaxNotice=setTimeout(() => {
|
||||
this.displayAjaxNotice=false;
|
||||
jQuery('#atfp-custom-fields-message-notice').remove();
|
||||
}, 10000);
|
||||
|
||||
let messageNotice = jQuery('<div id="atfp-custom-fields-message-notice"><p>' + message + '</p></div>');
|
||||
messageNotice.addClass('is-dismissible notice notice-' + type);
|
||||
jQuery('.atfpp-dashboard-wrapper').before(messageNotice);
|
||||
}
|
||||
|
||||
appendSaveButton() {
|
||||
|
||||
if (!this.saveButtonText || '' === this.saveButtonText || 'false' === this.saveButtonText || !this.saveButtonEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const saveButton = document.createElement('button');
|
||||
saveButton.className = 'button button-primary ' + this.saveButtonClass;
|
||||
saveButton.textContent = this.saveButtonText;
|
||||
return saveButton;
|
||||
}
|
||||
}
|
||||
|
||||
// Call the class after window load
|
||||
window.addEventListener('load', () => {
|
||||
new BlockFilterSorter();
|
||||
});
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,126 @@
|
||||
const { __, sprintf } = wp.i18n;
|
||||
|
||||
const atfpElementorConfirmBox = {
|
||||
init: function() {
|
||||
this.pageTitleEvent=false;
|
||||
if(window.atfpElementorConfirmBoxData){
|
||||
this.createConfirmBox();
|
||||
}
|
||||
},
|
||||
|
||||
createConfirmBox: function() {
|
||||
const sourceLangName=window.atfpElementorConfirmBoxData.sourceLangName;
|
||||
const targetLangName=window.atfpElementorConfirmBoxData.targetLangName;
|
||||
const confirmBox = jQuery(`<div class="atfp-elementor-translate-confirm-box modal-container" style="display:flex">
|
||||
<div class="modal-content">
|
||||
<p>
|
||||
${sprintf(
|
||||
__("The original page in %s was built with Elementor. Its content has already been copied into this new %s version. You can now translate it with Elementor to keep the same design, or edit it with the Gutenberg editor.", "autopoly-ai-translation-for-polylang-pro"),
|
||||
sourceLangName,
|
||||
targetLangName
|
||||
)}
|
||||
</p>
|
||||
<div>
|
||||
<button data-value="yes">
|
||||
${__("Translate with Elementor", "autopoly-ai-translation-for-polylang-pro")}
|
||||
</button>
|
||||
<button data-value="no">
|
||||
${__("Edit with Gutenberg", "autopoly-ai-translation-for-polylang-pro")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
|
||||
confirmBox.appendTo(jQuery('body'));
|
||||
|
||||
confirmBox.find('button[data-value="yes"]').on('click', (e)=>{this.confirmTranslation(e)});
|
||||
confirmBox.find('button[data-value="no"]').on('click', (e)=>{e.preventDefault();this.closeConfirmBox();});
|
||||
},
|
||||
|
||||
closeConfirmBox: function() {
|
||||
this.setPageTitle();
|
||||
const confirmBox = jQuery('.atfp-elementor-translate-confirm-box.modal-container');
|
||||
confirmBox.remove();
|
||||
},
|
||||
|
||||
confirmTranslation: function(e) {
|
||||
this.setPageTitle();
|
||||
e.preventDefault();
|
||||
const postId=window.atfpElementorConfirmBoxData.postId;
|
||||
const targetLangSlug=window.atfpElementorConfirmBoxData.targetLangSlug;
|
||||
|
||||
if(postId && targetLangSlug) {
|
||||
let oldData=localStorage.getItem('atfpElementorConfirmBox');
|
||||
let data={[postId+'_'+targetLangSlug]: true};
|
||||
|
||||
if(oldData && 'string' === typeof oldData && '' !== oldData) {
|
||||
oldData=JSON.parse(oldData);
|
||||
data={...oldData, ...data};
|
||||
}
|
||||
|
||||
localStorage.setItem('atfpElementorConfirmBox', JSON.stringify(data));
|
||||
|
||||
const elementorButton=document.getElementById('elementor-editor-button');
|
||||
const elementorEditModeButton=document.getElementById('elementor-edit-mode-button');
|
||||
|
||||
if(elementorEditModeButton) {
|
||||
elementorEditModeButton.click();
|
||||
}else if(elementorButton) {
|
||||
elementorButton.click();
|
||||
}
|
||||
|
||||
this.closeConfirmBox();
|
||||
}
|
||||
},
|
||||
|
||||
setPageTitle: function() {
|
||||
|
||||
if(window.atfpElementorConfirmBoxData.editorType !== 'classic') {
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.pageTitleEvent) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.pageTitleEvent=true;
|
||||
|
||||
const elementorButtons=document.querySelectorAll('#elementor-editor-button, #elementor-edit-mode-button');
|
||||
|
||||
elementorButtons.forEach(button=>{
|
||||
button.addEventListener('click', (e)=>{
|
||||
e.preventDefault();
|
||||
|
||||
if(window.wp && window.elementorAdmin && window.elementorAdmin.getDefaultElements){
|
||||
const defaultElements=window.elementorAdmin.getDefaultElements();
|
||||
|
||||
if(defaultElements) {
|
||||
$goToEditLink=defaultElements.$goToEditLink;
|
||||
|
||||
if($goToEditLink) {
|
||||
var $wpTitle = jQuery('#title');
|
||||
|
||||
if (!$wpTitle.val()) {
|
||||
$wpTitle.val('Elementor #' + jQuery('#post_ID').val());
|
||||
}
|
||||
|
||||
if (wp.autosave) {
|
||||
wp.autosave.server.triggerSave();
|
||||
}
|
||||
|
||||
jQuery(document).on('heartbeat-tick.autosave', function () {
|
||||
window.elementorCommon.elements.$window.off('beforeunload.edit-post');
|
||||
location.href = $goToEditLink.attr('href');
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
jQuery(document).ready(function($) {
|
||||
atfpElementorConfirmBox.init();
|
||||
});
|
||||
@@ -0,0 +1,333 @@
|
||||
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 don’t 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();
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
4
wp-content/plugins/autopoly-ai-translation-for-polylang-pro/assets/js/dataTables.min.js
vendored
Normal file
4
wp-content/plugins/autopoly-ai-translation-for-polylang-pro/assets/js/dataTables.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user