// ==UserScript== // @name IDEAERP - Listy przewozowe // @namespace http://tampermonkey.net/ // @version 1.0 // @description Kopiowanie elementów na stronach zamówień wysyłkowych - kliknij aby skopiować // @match https://emma.ideaerp.pl/web* // @icon https://emma.ideaerp.pl/web/image/res.company/1/favicon/ // @downloadURL https://n8n.emma.net.pl/webhook/order-shipping // @updateURL https://n8n.emma.net.pl/webhook/order-shipping // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @grant GM_deleteValue // @grant GM_registerMenuCommand // ==/UserScript== /* ========================OPIS============================== WERSJA 1.0 - Kopiowanie elementów zamówień wysyłkowych DZIAŁANIE SKRYPTU: - Kopiowanie nazwy zamówienia - kliknij na nazwę zamówienia (h1) aby skopiować - Kopiowanie numeru listu przewozowego - kliknij na element span[name="waybill"] aby skopiować - Kopiowanie NIP faktury - kliknij na element span[name="invoice_vat"] aby skopiować - Kopiowanie notatek - kliknij na element span[name="note"] aby skopiować - Obsługa błędów w funkcjach kopiowania zgodnie z zasadami .rules - Spójny styl wizualny ikon kopiowania (pomarańczowy kolor #ff9800) AUTOMATYCZNE AKTUALIZACJE: - Tampermonkey automatycznie sprawdza dostępność nowych wersji - Jednoklikowa aktualizacja bez konieczności ręcznego pobierania - Zachowanie ustawień użytkownika podczas aktualizacji - Kompatybilność z systemem n8n do zarządzania wersjami CHANGELOG: v1.0 (2024) - PIERWSZA WERSJA SKRYPTU WYSYŁKOWEGO - Utworzono dedykowany skrypt dla zamówień wysyłkowych (shipping.order) - Dodano kopiowanie nazwy zamówienia (h1) z ikoną ⧉ - Dodano kopiowanie numeru listu przewozowego (span[name="waybill"]) z ikoną ⧉ - Dodano kopiowanie NIP faktury (span[name="invoice_vat"]) z ikoną ⧉ - Dodano kopiowanie notatek (span[name="note"]) z ikoną ⧉ - Dodano style CSS dla elementów span z ikonami kopiowania - Dodano funkcję makeSpanCopyable() dla uniwersalnego kopiowania span - Obsługa błędów w funkcjach kopiowania zgodnie z zasadami .rules - Spójny styl wizualny ikon kopiowania (pomarańczowy kolor #ff9800) - Podwyższenie numeru wersji do 1.0 AUTOR: Adam Grodecki DATA: 2024 LICENCJA: Własność EMMA SPÓŁKA Z OGRANICZONĄ ODPOWIEDZIALNOŚCIĄ ================================================================ */ (function() { 'use strict'; // ——— Stałe ——— const STATE_KEY = 'tm_shipping_price_unit_visible'; const INIT_FLAG = 'tm_shipping_init_flag'; const COPY_MODE_KEY = 'tm_shipping_copy_mode'; const WIDTHS_KEY = 'tm_shipping_widths'; // ——— Style CSS ——— GM_addStyle(` /* Kopiowanie nazwy zamówienia – ikona dla h1 */ h1.tm-copyable { cursor: copy; } h1.tm-copyable::after { content: '⧉'; /* symbol kopiowania */ display: inline-block; /* w tej samej linii co tekst */ margin-left: 8px; /* odstęp od tekstu */ font-size: 14px; /* większy rozmiar dla h1 */ line-height: 1; color: #ff9800; /* pomarańczowy */ opacity: .75; /* widoczna także bez hovera */ vertical-align: baseline; pointer-events: none; transition: opacity .15s ease; } h1.tm-copyable:hover::after { opacity: 1; } h1.tm-copyable.tm-copied { outline: 2px solid #ff9800; background-image: linear-gradient(90deg, rgba(255,152,0,.12), rgba(255,152,0,0)); } /* Kopiowanie dla elementów span z określonymi name */ span.tm-copyable { cursor: copy; } span.tm-copyable::after { content: '⧉'; /* symbol kopiowania */ display: inline-block; /* w tej samej linii co tekst */ margin-left: 6px; /* odstęp od tekstu */ font-size: 12px; /* rozmiar jak dla komórek tabeli */ line-height: 1; color: #ff9800; /* pomarańczowy */ opacity: .75; /* widoczna także bez hovera */ vertical-align: baseline; pointer-events: none; transition: opacity .15s ease; } span.tm-copyable:hover::after { opacity: 1; } span.tm-copyable.tm-copied { outline: 2px solid #ff9800; background-image: linear-gradient(90deg, rgba(255,152,0,.12), rgba(255,152,0,0)); } `); // ——— Pomocnicze ——— function isShippingOrderForm() { const params = new URLSearchParams((location.hash || '').replace(/^#/, '')); const model = params.get('model'); const viewType = params.get('view_type'); return model === 'shipping.order' && viewType === 'form'; } async function tmCopyToClipboard(text) { try { await navigator.clipboard.writeText(text); } catch { const ta = document.createElement('textarea'); ta.value = text; document.body.appendChild(ta); ta.select(); document.execCommand('copy'); document.body.removeChild(ta); } } // ——— Kopiowanie nazwy zamówienia ——— function makeOrderNameCopyable(h1Element) { if (!h1Element || h1Element.dataset.tmOrderNameCopyable) return; h1Element.dataset.tmOrderNameCopyable = '1'; h1Element.classList.add('tm-copyable'); h1Element.style.cursor = 'pointer'; h1Element.title = 'Kliknij aby skopiować nazwę zamówienia'; h1Element.addEventListener('click', async (e) => { e.stopPropagation(); const orderName = (h1Element.textContent || '').trim(); if (!orderName) return; try { await tmCopyToClipboard(orderName); const old = h1Element.title; h1Element.title = `Skopiowano nazwę zamówienia: ${orderName}`; h1Element.classList.add('tm-copied'); setTimeout(() => { h1Element.title = old || 'Kliknij aby skopiować nazwę zamówienia'; h1Element.classList.remove('tm-copied'); }, 1200); } catch (error) { console.error('[Tampermonkey] Błąd podczas kopiowania nazwy zamówienia:', error); h1Element.title = 'Błąd podczas kopiowania'; } }, true); // capture=true } // ——— Kopiowanie elementów span z określonymi name ——— function makeSpanCopyable(spanElement, fieldName) { if (!spanElement || spanElement.dataset.tmSpanCopyable) return; spanElement.dataset.tmSpanCopyable = '1'; spanElement.classList.add('tm-copyable'); spanElement.style.cursor = 'pointer'; spanElement.title = `Kliknij aby skopiować ${fieldName}`; spanElement.addEventListener('click', async (e) => { e.stopPropagation(); const text = (spanElement.textContent || '').trim(); if (!text) return; try { await tmCopyToClipboard(text); const old = spanElement.title; spanElement.title = `Skopiowano ${fieldName}: ${text}`; spanElement.classList.add('tm-copied'); setTimeout(() => { spanElement.title = old || `Kliknij aby skopiować ${fieldName}`; spanElement.classList.remove('tm-copied'); }, 1200); } catch (error) { console.error(`[Tampermonkey] Błąd podczas kopiowania ${fieldName}:`, error); spanElement.title = 'Błąd podczas kopiowania'; } }, true); // capture=true } // ——— Główna procedura ——— function processOnce() { if (!isShippingOrderForm()) return; if (!GM_getValue(INIT_FLAG)) { GM_setValue(INIT_FLAG, true); } // Dodaj kopiowanie nazwy zamówienia const orderNameSpan = document.querySelector('h1 span[name="name"]'); if (orderNameSpan) { const orderNameH1 = orderNameSpan.closest('h1'); if (orderNameH1) { makeOrderNameCopyable(orderNameH1); } } // Dodaj kopiowanie dla elementów span z określonymi name const waybillSpan = document.querySelector('span[name="waybill"]'); if (waybillSpan) { makeSpanCopyable(waybillSpan, 'numer listu przewozowego'); } const invoiceVatSpan = document.querySelector('span[name="invoice_vat"]'); if (invoiceVatSpan) { makeSpanCopyable(invoiceVatSpan, 'NIP faktury'); } const noteSpan = document.querySelector('span[name="note"]'); if (noteSpan) { makeSpanCopyable(noteSpan, 'notatkę'); } } // ——— Start + reagowanie na zmiany ——— let deb = null; const debounce = (fn, ms = 150) => { clearTimeout(deb); deb = setTimeout(fn, ms); }; window.addEventListener('load', () => debounce(processOnce, 150)); window.addEventListener('hashchange', () => debounce(processOnce, 250)); new MutationObserver(() => debounce(processOnce, 150)).observe(document.documentElement, { childList: true, subtree: true }); })();