diff --git a/apilo.js b/apilo.js
index e8eefe3..8cf9e80 100644
--- a/apilo.js
+++ b/apilo.js
@@ -4,163 +4,207 @@ const patterns = [
/^https:\/\/projectpro\.apilo\.com\/order\/order\/in-progress\/?$/,
/^https:\/\/projectpro\.apilo\.com\/order\/order\/to-send\/?$/,
/^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();
attachTableReloadListener();
} else {
console.log('Nie pasuje do żadnego wzorca URL');
}
+// --- 2) Czekanie na tabelę i start przetwarzania ---
function waitForTableAndSetImage() {
+ const start = Date.now();
+ const maxWait = 10000; // 10s
const intervalId = setInterval(() => {
- let dataTables_scrollBody = document.getElementsByClassName('dataTables_scrollBody');
- if (dataTables_scrollBody.length > 0) {
- let dataTables_tbody = dataTables_scrollBody[0].getElementsByTagName('tbody')[0];
- let rows = dataTables_tbody.getElementsByTagName('tr');
-
- if (rows.length > 0) {
- clearInterval(intervalId);
- setImageToProduct();
- }
+ const tbody = document.querySelector('#DataTables_Table_0 tbody');
+ if (tbody && tbody.querySelector('tr')) {
+ clearInterval(intervalId);
+ setImageToProduct();
+ } else if (Date.now() - start > maxWait) {
+ clearInterval(intervalId);
}
- }, 100);
+ }, 120);
}
+// --- 3) Obserwator zmian w tabeli (przeładowanie/paginacja) ---
function attachTableReloadListener() {
- const table = document.querySelector('.dataTables_scrollBody table');
- if (table) {
- const observer = new MutationObserver((mutationsList, observer) => {
- for (const mutation of mutationsList) {
- if (mutation.type === 'childList') {
- waitForTableAndSetImage();
- break;
- }
+ const tbody = document.querySelector('#DataTables_Table_0 tbody');
+ if (!tbody) return;
+ const observer = new MutationObserver(mutations => {
+ for (const m of mutations) {
+ if (m.type === 'childList') {
+ setImageToProduct();
+ 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:
+ 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]; //
+ const dataHolder = flex.children?.[1]; // z nazwą, SKU, EAN, ceną
+ if (!imgHolder || !dataHolder) return;
+
+ // Jeśli już jest
![]()
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 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 = '') {
- let dataTables_scrollBody = document.getElementsByClassName('dataTables_scrollBody');
- if (dataTables_scrollBody.length > 0) {
- let dataTables_tbody = dataTables_scrollBody[0].getElementsByTagName('tbody')[0];
- let rows = dataTables_tbody.getElementsByTagName('tr');
-
- 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 detectDomainFromCell(td) {
+ const text = (td.textContent || '').toLowerCase();
+ if (text.includes('marianek.pl')) return 'marianek.pl';
+ if (text.includes('pomysloweprezenty.pl')) return 'pomysloweprezenty.pl';
+ return null;
}
-function makeImg(src = 'https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png') {
+function makeImg(src) {
const img = document.createElement('img');
img.src = src;
- img.alt = 'image';
+ img.alt = 'product';
img.className = 'img-fluid center-block';
img.style.maxWidth = '48px';
img.style.maxHeight = '48px';
-
+ img.style.objectFit = 'contain';
+ img.style.cursor = 'zoom-in';
return img;
}
-function showLargeImage(src, imgElement) {
- const largeImg = document.createElement('img');
- 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 = '1000';
- largeImg.style.top = imgElement.getBoundingClientRect().top + window.scrollY + 'px';
- largeImg.style.left = imgElement.getBoundingClientRect().left + imgElement.offsetWidth + 10 + 'px';
- largeImg.id = 'largeImagePreview';
+// --- 5) Podgląd dużego obrazka ---
+function setupPreview(imgElement, src) {
+ let largeImg = null;
- document.body.appendChild(largeImg);
-}
-
-function hideLargeImage() {
- const largeImg = document.getElementById('largeImagePreview');
- if (largeImg) {
- largeImg.remove();
- }
+ const onMove = (ev) => {
+ if (!largeImg) return;
+ const pad = 10;
+ largeImg.style.top = (ev.pageY - largeImg.height / 2) + 'px';
+ largeImg.style.left = (ev.pageX + pad) + 'px';
+ };
+
+ 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) {
- let url;
+ let url = null;
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') {
- url = `https://pomysloweprezenty.pl/api/v1/product.php?sku=${sku}`;
+ url = `https://pomysloweprezenty.pl/api/v1/product.php?sku=${encodeURIComponent(sku)}`;
} else {
- console.error('Unsupported domain:', domain);
return null;
}
try {
- const response = await fetch(url);
- if (!response.ok) {
- throw new Error(`HTTP error! status: ${response.status}`);
+ const resp = await fetch(url, { credentials: 'omit' });
+ if (!resp.ok) {
+ throw new Error(`HTTP error! status: ${resp.status}`);
}
-
- const data = await response.json(); console.log(data);
- return data.img;
- } catch (error) {
- console.error('Error fetching product data: ' + url, error);
+ const data = await resp.json();
+ // zakładam, że API zwraca { img: "https://..." }
+ return data?.img || null;
+ } catch (err) {
+ console.error('Error fetching product data:', url, err);
return null;
}
}
@@ -223,7 +267,7 @@ async function handleShipment(method, dropoffPoint = null) {
if (dropoffPoint) {
await setDropoffPoint(dropoffPoint);
}
- await setContent( method );
+ await setContent(method);
await setParcelWeight('1');
await submitShipment();
} catch (error) {
@@ -252,8 +296,8 @@ function retryUntilSuccess(fn, interval = 1000, retries = 10) {
});
}
-function setContent( method ) {
- if ( method == 'D2D.apaczka' || method == 'D2P.apaczka' || method == 'P2P.apaczka' || method == 'P2P.orlen' ) {
+function setContent(method) {
+ if (method == 'D2D.apaczka' || method == 'D2P.apaczka' || method == 'P2P.apaczka' || method == 'P2P.orlen') {
return retryUntilSuccess(() => {
return new Promise((resolve, reject) => {
const selectElement = document.getElementById('warehousebundle_shipment_preferences_content');
@@ -271,7 +315,7 @@ function selectPackageType(method) {
return retryUntilSuccess(() => {
return new Promise((resolve, reject) => {
- if ( method == 'P2P.orlen' ) {
+ if (method == 'P2P.orlen') {
//warehousebundle_shipment_carrierAccount
const selectElement = document.getElementById('warehousebundle_shipment_carrierAccount');
@@ -300,7 +344,7 @@ function selectPackageType(method) {
}, 1000);
}, 1000);
- } else if ( method == 'D2P.apaczka' || method == 'P2P.apaczka' ) {
+ } else if (method == 'D2P.apaczka' || method == 'P2P.apaczka') {
//warehousebundle_shipment_carrierAccount
const selectElement = document.getElementById('warehousebundle_shipment_carrierAccount');
@@ -330,7 +374,7 @@ function selectPackageType(method) {
}, 1000);
- } else if ( method == 'D2D.apaczka' ) {
+ } else if (method == 'D2D.apaczka') {
const selectElement = document.getElementById('warehousebundle_shipment_carrierAccount');
selectElement.value = 17;
@@ -375,7 +419,7 @@ function selectPackageType(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) => {
resolve();
});