Refactor URL pattern matching and improve image loading for product thumbnails
This commit is contained in:
292
apilo.js
292
apilo.js
@@ -4,163 +4,207 @@ const patterns = [
|
|||||||
/^https:\/\/projectpro\.apilo\.com\/order\/order\/in-progress\/?$/,
|
/^https:\/\/projectpro\.apilo\.com\/order\/order\/in-progress\/?$/,
|
||||||
/^https:\/\/projectpro\.apilo\.com\/order\/order\/to-send\/?$/,
|
/^https:\/\/projectpro\.apilo\.com\/order\/order\/to-send\/?$/,
|
||||||
/^https:\/\/projectpro\.apilo\.com\/order\/order\/completed\/?$/,
|
/^https:\/\/projectpro\.apilo\.com\/order\/order\/completed\/?$/,
|
||||||
/^https:\/\/projectpro\.apilo\.com\/order\/order\/all\/?$/
|
/^https:\/\/projectpro\.apilo\.com\/order\/order\/status\/?$/,
|
||||||
|
/^https:\/\/projectpro\.apilo\.com\/order\/order\/(news|in-progress|to-send|completed|all)\/?$/,
|
||||||
|
/^https:\/\/projectpro\.apilo\.com\/order\/order\/status\/[^\/?#]+\/?$/
|
||||||
];
|
];
|
||||||
if (patterns.some(pattern => pattern.test(currentUrl))) { console.log('test');
|
if (patterns.some(pattern => pattern.test(currentUrl))) {
|
||||||
|
console.log('test');
|
||||||
waitForTableAndSetImage();
|
waitForTableAndSetImage();
|
||||||
attachTableReloadListener();
|
attachTableReloadListener();
|
||||||
} else {
|
} else {
|
||||||
console.log('Nie pasuje do żadnego wzorca URL');
|
console.log('Nie pasuje do żadnego wzorca URL');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- 2) Czekanie na tabelę i start przetwarzania ---
|
||||||
function waitForTableAndSetImage() {
|
function waitForTableAndSetImage() {
|
||||||
|
const start = Date.now();
|
||||||
|
const maxWait = 10000; // 10s
|
||||||
const intervalId = setInterval(() => {
|
const intervalId = setInterval(() => {
|
||||||
let dataTables_scrollBody = document.getElementsByClassName('dataTables_scrollBody');
|
const tbody = document.querySelector('#DataTables_Table_0 tbody');
|
||||||
if (dataTables_scrollBody.length > 0) {
|
if (tbody && tbody.querySelector('tr')) {
|
||||||
let dataTables_tbody = dataTables_scrollBody[0].getElementsByTagName('tbody')[0];
|
clearInterval(intervalId);
|
||||||
let rows = dataTables_tbody.getElementsByTagName('tr');
|
setImageToProduct();
|
||||||
|
} else if (Date.now() - start > maxWait) {
|
||||||
if (rows.length > 0) {
|
clearInterval(intervalId);
|
||||||
clearInterval(intervalId);
|
|
||||||
setImageToProduct();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, 100);
|
}, 120);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- 3) Obserwator zmian w tabeli (przeładowanie/paginacja) ---
|
||||||
function attachTableReloadListener() {
|
function attachTableReloadListener() {
|
||||||
const table = document.querySelector('.dataTables_scrollBody table');
|
const tbody = document.querySelector('#DataTables_Table_0 tbody');
|
||||||
if (table) {
|
if (!tbody) return;
|
||||||
const observer = new MutationObserver((mutationsList, observer) => {
|
const observer = new MutationObserver(mutations => {
|
||||||
for (const mutation of mutationsList) {
|
for (const m of mutations) {
|
||||||
if (mutation.type === 'childList') {
|
if (m.type === 'childList') {
|
||||||
waitForTableAndSetImage();
|
setImageToProduct();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
observer.observe(tbody, { childList: true, subtree: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 4) Główny worker: wstawianie miniatur wg SKU ---
|
||||||
|
const imgCache = new Map(); // SKU -> imgURL
|
||||||
|
|
||||||
|
function setImageToProduct() {
|
||||||
|
const tbody = document.querySelector('#DataTables_Table_0 tbody');
|
||||||
|
if (!tbody) return;
|
||||||
|
|
||||||
|
const rows = Array.from(tbody.querySelectorAll('tr'));
|
||||||
|
rows.forEach(tr => {
|
||||||
|
const cells = tr.querySelectorAll('td');
|
||||||
|
if (cells.length < 4) return;
|
||||||
|
|
||||||
|
// Kolumna 2 zawiera info z domeną (wklejone w tym samym TD co numer zamówienia itp.)
|
||||||
|
const domain = detectDomainFromCell(cells[1]);
|
||||||
|
if (!domain) return;
|
||||||
|
|
||||||
|
// Kolumna 4: "Dane produktu"
|
||||||
|
const productsCell = cells[3];
|
||||||
|
// ============ POPRAWIONY FRAGMENT ============
|
||||||
|
|
||||||
|
// Każdy produkt: <div data-item="all-products"><div data-item="product">...</div></div>
|
||||||
|
const productBlocks = productsCell.querySelectorAll('[data-item="all-products"] [data-item="product"]');
|
||||||
|
|
||||||
|
productBlocks.forEach(block => {
|
||||||
|
// nie rób drugi raz
|
||||||
|
if (block.dataset.imgInserted === '1') return;
|
||||||
|
|
||||||
|
// Struktura: [data-item="product"] > .d-flex.mb-2 > [imgHolder DIV] + [dataHolder DIV]
|
||||||
|
const flex =
|
||||||
|
block.querySelector(':scope > .d-flex.mb-2') ||
|
||||||
|
block.querySelector('.d-flex.mb-2') ||
|
||||||
|
block.firstElementChild; // awaryjnie, gdyby klasy się zmieniły
|
||||||
|
|
||||||
|
if (!flex) return;
|
||||||
|
|
||||||
|
const imgHolder = flex.children?.[0]; // <div class="d-flex ... mr-3"><i .../></div>
|
||||||
|
const dataHolder = flex.children?.[1]; // <div> z nazwą, SKU, EAN, ceną
|
||||||
|
if (!imgHolder || !dataHolder) return;
|
||||||
|
|
||||||
|
// Jeśli już jest <img> w imgHolder, pomijamy
|
||||||
|
if (imgHolder.querySelector('img')) {
|
||||||
|
block.dataset.imgInserted = '1';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Znajdź konkretnie DIV z SKU (bez mieszania z innymi liniami)
|
||||||
|
const skuDiv = Array.from(dataHolder.querySelectorAll('div'))
|
||||||
|
.find(d => /SKU\s*:/i.test(d.textContent || ''));
|
||||||
|
|
||||||
|
const skuMatch = (skuDiv?.textContent || '').match(/SKU\s*:\s*([A-Za-z0-9_-]+)/i);
|
||||||
|
const sku = skuMatch?.[1]?.toUpperCase();
|
||||||
|
if (!sku) return;
|
||||||
|
|
||||||
|
const placeImage = (imgUrl) => {
|
||||||
|
if (!imgUrl) return;
|
||||||
|
// czyścimy ikonę <i> i wstawiamy miniaturę
|
||||||
|
imgHolder.innerHTML = '';
|
||||||
|
const imgEl = makeImg(imgUrl);
|
||||||
|
imgHolder.appendChild(imgEl);
|
||||||
|
setupPreview(imgEl, imgUrl);
|
||||||
|
block.dataset.imgInserted = '1';
|
||||||
|
};
|
||||||
|
|
||||||
|
if (imgCache.has(sku)) {
|
||||||
|
placeImage(imgCache.get(sku));
|
||||||
|
} else {
|
||||||
|
getProductData(sku, domain)
|
||||||
|
.then(url => {
|
||||||
|
if (url) imgCache.set(sku, url);
|
||||||
|
placeImage(url);
|
||||||
|
})
|
||||||
|
.catch(() => { });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
observer.observe(table.querySelector('tbody'), { childList: true });
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setImageToProduct(img = '') {
|
function detectDomainFromCell(td) {
|
||||||
let dataTables_scrollBody = document.getElementsByClassName('dataTables_scrollBody');
|
const text = (td.textContent || '').toLowerCase();
|
||||||
if (dataTables_scrollBody.length > 0) {
|
if (text.includes('marianek.pl')) return 'marianek.pl';
|
||||||
let dataTables_tbody = dataTables_scrollBody[0].getElementsByTagName('tbody')[0];
|
if (text.includes('pomysloweprezenty.pl')) return 'pomysloweprezenty.pl';
|
||||||
let rows = dataTables_tbody.getElementsByTagName('tr');
|
return null;
|
||||||
|
|
||||||
for (let i = 0; i < rows.length; i++) {
|
|
||||||
let cells = rows[i].getElementsByTagName('td');
|
|
||||||
|
|
||||||
if (cells.length > 1) {
|
|
||||||
let secondCellText = cells[1].textContent.trim();
|
|
||||||
let domain;
|
|
||||||
|
|
||||||
if (secondCellText.includes('marianek.pl')) {
|
|
||||||
domain = 'marianek.pl';
|
|
||||||
} else if (secondCellText.includes('pomysloweprezenty.pl')) {
|
|
||||||
domain = 'pomysloweprezenty.pl';
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cells.length >= 5) {
|
|
||||||
let fifthCell = cells[4];
|
|
||||||
let divsInFifthCell = fifthCell.children;
|
|
||||||
|
|
||||||
for (let i = 0; i < divsInFifthCell.length; i++) {
|
|
||||||
let currentDiv = divsInFifthCell[i];
|
|
||||||
let imgDiv = currentDiv.getElementsByTagName('div')[0];
|
|
||||||
let dataDiv = currentDiv.getElementsByTagName('div')[1];
|
|
||||||
|
|
||||||
if (dataDiv) {
|
|
||||||
let skuText = dataDiv.innerHTML.match(/SKU:\s*([A-Za-z0-9-]+)/);
|
|
||||||
|
|
||||||
if (skuText && skuText[1]) {
|
|
||||||
getProductData(skuText[1], domain).then(data => {
|
|
||||||
if (!data) {
|
|
||||||
console.log('Product not found:', skuText[1]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Product found:', skuText[1]);
|
|
||||||
imgDiv.innerHTML = '';
|
|
||||||
const imgElement = makeImg(data);
|
|
||||||
imgDiv.appendChild(imgElement);
|
|
||||||
|
|
||||||
imgElement.addEventListener('mouseover', function() {
|
|
||||||
showLargeImage(data, imgElement);
|
|
||||||
});
|
|
||||||
|
|
||||||
imgElement.addEventListener('mouseout', function() {
|
|
||||||
hideLargeImage();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeImg(src = 'https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png') {
|
function makeImg(src) {
|
||||||
const img = document.createElement('img');
|
const img = document.createElement('img');
|
||||||
img.src = src;
|
img.src = src;
|
||||||
img.alt = 'image';
|
img.alt = 'product';
|
||||||
img.className = 'img-fluid center-block';
|
img.className = 'img-fluid center-block';
|
||||||
img.style.maxWidth = '48px';
|
img.style.maxWidth = '48px';
|
||||||
img.style.maxHeight = '48px';
|
img.style.maxHeight = '48px';
|
||||||
|
img.style.objectFit = 'contain';
|
||||||
|
img.style.cursor = 'zoom-in';
|
||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
|
|
||||||
function showLargeImage(src, imgElement) {
|
// --- 5) Podgląd dużego obrazka ---
|
||||||
const largeImg = document.createElement('img');
|
function setupPreview(imgElement, src) {
|
||||||
largeImg.src = src;
|
let largeImg = null;
|
||||||
largeImg.style.position = 'absolute';
|
|
||||||
largeImg.style.maxWidth = '400px';
|
|
||||||
largeImg.style.maxHeight = '400px';
|
|
||||||
largeImg.style.border = '1px solid #ccc';
|
|
||||||
largeImg.style.background = '#fff';
|
|
||||||
largeImg.style.zIndex = '1000';
|
|
||||||
largeImg.style.top = imgElement.getBoundingClientRect().top + window.scrollY + 'px';
|
|
||||||
largeImg.style.left = imgElement.getBoundingClientRect().left + imgElement.offsetWidth + 10 + 'px';
|
|
||||||
largeImg.id = 'largeImagePreview';
|
|
||||||
|
|
||||||
document.body.appendChild(largeImg);
|
const onMove = (ev) => {
|
||||||
}
|
if (!largeImg) return;
|
||||||
|
const pad = 10;
|
||||||
function hideLargeImage() {
|
largeImg.style.top = (ev.pageY - largeImg.height / 2) + 'px';
|
||||||
const largeImg = document.getElementById('largeImagePreview');
|
largeImg.style.left = (ev.pageX + pad) + 'px';
|
||||||
if (largeImg) {
|
};
|
||||||
largeImg.remove();
|
|
||||||
}
|
const onOver = (ev) => {
|
||||||
|
if (largeImg) return;
|
||||||
|
largeImg = document.createElement('img');
|
||||||
|
largeImg.id = 'largeImagePreview';
|
||||||
|
largeImg.src = src;
|
||||||
|
largeImg.style.position = 'absolute';
|
||||||
|
largeImg.style.maxWidth = '400px';
|
||||||
|
largeImg.style.maxHeight = '400px';
|
||||||
|
largeImg.style.border = '1px solid #ccc';
|
||||||
|
largeImg.style.background = '#fff';
|
||||||
|
largeImg.style.zIndex = '10000';
|
||||||
|
largeImg.style.pointerEvents = 'none';
|
||||||
|
document.body.appendChild(largeImg);
|
||||||
|
onMove(ev);
|
||||||
|
document.addEventListener('mousemove', onMove);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onOut = () => {
|
||||||
|
if (largeImg) {
|
||||||
|
document.removeEventListener('mousemove', onMove);
|
||||||
|
largeImg.remove();
|
||||||
|
largeImg = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
imgElement.addEventListener('mouseover', onOver);
|
||||||
|
imgElement.addEventListener('mouseout', onOut);
|
||||||
|
imgElement.addEventListener('mouseleave', onOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- 6) API: pobranie URL obrazka po SKU i domenie ---
|
||||||
async function getProductData(sku, domain) {
|
async function getProductData(sku, domain) {
|
||||||
let url;
|
let url = null;
|
||||||
if (domain === 'marianek.pl') {
|
if (domain === 'marianek.pl') {
|
||||||
url = `https://marianek.pl/api/v1/product.php?sku=${sku}`;
|
url = `https://marianek.pl/api/v1/product.php?sku=${encodeURIComponent(sku)}`;
|
||||||
} else if (domain === 'pomysloweprezenty.pl') {
|
} else if (domain === 'pomysloweprezenty.pl') {
|
||||||
url = `https://pomysloweprezenty.pl/api/v1/product.php?sku=${sku}`;
|
url = `https://pomysloweprezenty.pl/api/v1/product.php?sku=${encodeURIComponent(sku)}`;
|
||||||
} else {
|
} else {
|
||||||
console.error('Unsupported domain:', domain);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(url);
|
const resp = await fetch(url, { credentials: 'omit' });
|
||||||
if (!response.ok) {
|
if (!resp.ok) {
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error(`HTTP error! status: ${resp.status}`);
|
||||||
}
|
}
|
||||||
|
const data = await resp.json();
|
||||||
const data = await response.json(); console.log(data);
|
// zakładam, że API zwraca { img: "https://..." }
|
||||||
return data.img;
|
return data?.img || null;
|
||||||
} catch (error) {
|
} catch (err) {
|
||||||
console.error('Error fetching product data: ' + url, error);
|
console.error('Error fetching product data:', url, err);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -223,7 +267,7 @@ async function handleShipment(method, dropoffPoint = null) {
|
|||||||
if (dropoffPoint) {
|
if (dropoffPoint) {
|
||||||
await setDropoffPoint(dropoffPoint);
|
await setDropoffPoint(dropoffPoint);
|
||||||
}
|
}
|
||||||
await setContent( method );
|
await setContent(method);
|
||||||
await setParcelWeight('1');
|
await setParcelWeight('1');
|
||||||
await submitShipment();
|
await submitShipment();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -252,8 +296,8 @@ function retryUntilSuccess(fn, interval = 1000, retries = 10) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function setContent( method ) {
|
function setContent(method) {
|
||||||
if ( method == 'D2D.apaczka' || method == 'D2P.apaczka' || method == 'P2P.apaczka' || method == 'P2P.orlen' ) {
|
if (method == 'D2D.apaczka' || method == 'D2P.apaczka' || method == 'P2P.apaczka' || method == 'P2P.orlen') {
|
||||||
return retryUntilSuccess(() => {
|
return retryUntilSuccess(() => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const selectElement = document.getElementById('warehousebundle_shipment_preferences_content');
|
const selectElement = document.getElementById('warehousebundle_shipment_preferences_content');
|
||||||
@@ -271,7 +315,7 @@ function selectPackageType(method) {
|
|||||||
return retryUntilSuccess(() => {
|
return retryUntilSuccess(() => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
if ( method == 'P2P.orlen' ) {
|
if (method == 'P2P.orlen') {
|
||||||
|
|
||||||
//warehousebundle_shipment_carrierAccount
|
//warehousebundle_shipment_carrierAccount
|
||||||
const selectElement = document.getElementById('warehousebundle_shipment_carrierAccount');
|
const selectElement = document.getElementById('warehousebundle_shipment_carrierAccount');
|
||||||
@@ -300,7 +344,7 @@ function selectPackageType(method) {
|
|||||||
}, 1000);
|
}, 1000);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
} else if ( method == 'D2P.apaczka' || method == 'P2P.apaczka' ) {
|
} else if (method == 'D2P.apaczka' || method == 'P2P.apaczka') {
|
||||||
|
|
||||||
//warehousebundle_shipment_carrierAccount
|
//warehousebundle_shipment_carrierAccount
|
||||||
const selectElement = document.getElementById('warehousebundle_shipment_carrierAccount');
|
const selectElement = document.getElementById('warehousebundle_shipment_carrierAccount');
|
||||||
@@ -330,7 +374,7 @@ function selectPackageType(method) {
|
|||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
|
|
||||||
} else if ( method == 'D2D.apaczka' ) {
|
} else if (method == 'D2D.apaczka') {
|
||||||
|
|
||||||
const selectElement = document.getElementById('warehousebundle_shipment_carrierAccount');
|
const selectElement = document.getElementById('warehousebundle_shipment_carrierAccount');
|
||||||
selectElement.value = 17;
|
selectElement.value = 17;
|
||||||
@@ -375,7 +419,7 @@ function selectPackageType(method) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setShipmentMethod(method) {
|
function setShipmentMethod(method) {
|
||||||
if ( method == 'D2D.apaczka' || method == 'D2P.apaczka' || method == 'P2P.apaczka' || method == 'P2P.orlen' ) {
|
if (method == 'D2D.apaczka' || method == 'D2P.apaczka' || method == 'P2P.apaczka' || method == 'P2P.orlen') {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user