// Bug Report System - JavaScript rész (function() { const logs = []; const origLog = console.log; const origError = console.error; const origWarn = console.warn; console.log = function(...args) { logs.push('[LOG] ' + args.join(' ')); origLog.apply(console, args); }; console.error = function(...args) { logs.push('[ERROR] ' + args.join(' ')); origError.apply(console, args); }; console.warn = function(...args) { logs.push('[WARN] ' + args.join(' ')); origWarn.apply(console, args); }; const origXHROpen = XMLHttpRequest.prototype.open; const origXHRSend = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.open = function(method, url, async, user, password) { this._method = method; this._url = url; return origXHROpen.apply(this, arguments); }; XMLHttpRequest.prototype.send = function(data) { const startTime = Date.now(); this._sendData = data; this.addEventListener('load', function() { const duration = Date.now() - startTime; logs.push(`[NETWORK] ${this._method} ${this._url} - Status: ${this.status} (${duration}ms)`); }); this.addEventListener('error', function() { const duration = Date.now() - startTime; let errorLog = `[NET ERROR] ${this._method} ${this._url} - Failed (${duration}ms)`; if (this._sendData && (this._method === 'POST' || this._method === 'PUT' || this._method === 'PATCH')) { let postData = 'Unknown'; try { if (typeof this._sendData === 'string') { postData = this._sendData; } else if (this._sendData instanceof FormData) { postData = 'FormData'; const formDataEntries = []; for (let [key, value] of this._sendData.entries()) { formDataEntries.push(`${key}=${value}`); } if (formDataEntries.length > 0) { postData = formDataEntries.join('&'); } } else { postData = JSON.stringify(this._sendData); } } catch (e) { postData = '[Cannot serialize data]'; } errorLog += ` - POST Data: ${postData}`; } logs.push(errorLog); }); this.addEventListener('timeout', function() { const duration = Date.now() - startTime; let timeoutLog = `[NET ERROR] ${this._method} ${this._url} - Timeout (${duration}ms)`; if (this._sendData && (this._method === 'POST' || this._method === 'PUT' || this._method === 'PATCH')) { let postData = 'Unknown'; try { if (typeof this._sendData === 'string') { postData = this._sendData; } else if (this._sendData instanceof FormData) { postData = 'FormData'; const formDataEntries = []; for (let [key, value] of this._sendData.entries()) { formDataEntries.push(`${key}=${value}`); } if (formDataEntries.length > 0) { postData = formDataEntries.join('&'); } } else { postData = JSON.stringify(this._sendData); } } catch (e) { postData = '[Cannot serialize data]'; } timeoutLog += ` - POST Data: ${postData}`; } logs.push(timeoutLog); }); return origXHRSend.apply(this, arguments); }; window.addEventListener('unhandledrejection', event => { logs.push('[UNHANDLED PROMISE REJECTION] ' + (event.reason?.message || event.reason)); }); window.onerror = function(message, source, lineno, colno, error) { logs.push(`[GLOBAL ERROR] ${message} at ${source}:${lineno}:${colno}`); }; window.addEventListener('error', event => { if (event.target && (event.target.src || event.target.href)) { logs.push(`[RESOURCE LOAD ERROR] ${event.target.tagName} on ${event.target.src || event.target.href}`); } }, true); window.addEventListener('online', () => { logs.push('[NETWORK STATUS] Back online'); }); window.addEventListener('offline', () => { logs.push('[NETWORK STATUS] Offline'); }); const origFetch = window.fetch; window.fetch = function(input, init) { const startTime = Date.now(); const url = typeof input === 'string' ? input : input.url; const method = (init && init.method) || 'GET'; const requestBody = init && init.body; return origFetch.apply(this, arguments) .then(response => { const duration = Date.now() - startTime; logs.push(`[NETWORK] ${method} ${url} - Status: ${response.status} (${duration}ms)`); return response; }) .catch(error => { const duration = Date.now() - startTime; let errorLog = `[NET ERROR] ${method} ${url} - ${error.message} (${duration}ms)`; if (requestBody && (method === 'POST' || method === 'PUT' || method === 'PATCH')) { let postData = 'Unknown'; try { if (typeof requestBody === 'string') { postData = requestBody; } else if (requestBody instanceof FormData) { postData = 'FormData'; const formDataEntries = []; for (let [key, value] of requestBody.entries()) { formDataEntries.push(`${key}=${value}`); } if (formDataEntries.length > 0) { postData = formDataEntries.join('&'); } } else { postData = JSON.stringify(requestBody); } } catch (e) { postData = '[Cannot serialize data]'; } errorLog += ` - POST Data: ${postData}`; } logs.push(errorLog); throw error; }); }; const bugBtn = document.createElement('button'); bugBtn.innerHTML = 'Hibabejelentés 🐛'; Object.assign(bugBtn.style, { position: 'fixed', bottom: '30px', left: '-97px', zIndex: '99999', backgroundColor: '#e74c3c', color: 'white', border: 'none', borderRadius: '0px 8px 8px 0px', cursor: 'pointer', fontSize: '12px', fontWeight: 'bold', transition: 'all 0.3s ease', width: '130px', padding: '5px 10px', overflow: 'hidden', opacity: '1' }); bugBtn.onmouseenter = () => { bugBtn.style.left = '0px'; }; bugBtn.onmouseleave = () => { bugBtn.style.left = '-97px'; }; document.body.appendChild(bugBtn); bugBtn.onclick = async () => { bugBtn.textContent = 'Küldés...'; bugBtn.disabled = true; try { let screenshotData = null; let screenshotDataFull = null; if (typeof html2canvas !== 'undefined') { try { const links = document.querySelectorAll('link[rel="stylesheet"]'); const filterPromises = Array.from(links).map(link => { const href = link.href; return fetch(href) .then(r => r.text()) .then(css => { css = css.replace(/color\s*\([^)]*\)/gi, '#000000'); css = css.replace(/color-mix\s*\([^()]*(?:\([^()]*\)[^()]*)*\)/gi, '#808080'); return css; }) .catch(() => null); }); const cssArrays = await Promise.all(filterPromises); const combinedCss = cssArrays.filter(c => c).join('\n'); const filterUnsupported = (clonedDoc) => { const clonedLinks = clonedDoc.querySelectorAll('link[rel="stylesheet"]'); clonedLinks.forEach(link => link.remove()); if (combinedCss) { const style = clonedDoc.createElement('style'); style.textContent = combinedCss; clonedDoc.head.appendChild(style); } clonedDoc.querySelectorAll('[style]').forEach(el => { const style = el.getAttribute('style'); let newStyle = style; newStyle = newStyle.replace(/color\s*\([^)]*\)/gi, '#000000'); newStyle = newStyle.replace(/color-mix\s*\([^()]*(?:\([^()]*\)[^()]*)*\)/gi, '#808080'); el.setAttribute('style', newStyle); }); clonedDoc.querySelectorAll('style').forEach(styleEl => { let css = styleEl.textContent; css = css.replace(/color\s*\([^)]*\)/gi, '#000000'); css = css.replace(/color-mix\s*\([^()]*(?:\([^()]*\)[^()]*)*\)/gi, '#808080'); styleEl.textContent = css; }); }; const canvas = await html2canvas(document.body, { scale: window.devicePixelRatio || 1, onclone: filterUnsupported }); const canvasFull = await html2canvas(document.body, { scrollX: 0, scrollY: 0, width: document.documentElement.scrollWidth, height: document.documentElement.scrollHeight, scale: window.devicePixelRatio || 1, onclone: filterUnsupported }); screenshotData = canvas.toDataURL('image/png'); screenshotDataFull = canvasFull.toDataURL('image/png'); } catch (e) { console.error('Screenshot hiba:', e); } } SendReport(screenshotData, screenshotDataFull); } catch (error) { console.error('Bug report küldési hiba:', error); GenerateAlerts('error', 'Hiba történt a bejelentés küldése során.'); } }; let currentImageMode = 'viewport'; let drawMode = 'pen'; let isDrawing = false; let lastX = 0; let lastY = 0; let startX = 0; let startY = 0; let paintCanvas, paintCtx; let baseImageViewport = new Image(); let baseImageFull = new Image(); let currentScreenshotData, currentScreenshotDataFull, currentText; let savedImageData = null; window.switchImage = function() { currentImageMode = document.getElementById('BUGREPORT_imageSelector').value; setupCanvas(); }; window.setDrawMode = function(mode) { drawMode = mode; document.getElementById('BUGREPORT_penBtn').style.background = mode === 'pen' ? '#c0392b' : '#e74c3c'; document.getElementById('BUGREPORT_rectBtn').style.background = mode === 'rect' ? '#2980b9' : '#3498db'; document.getElementById('BUGREPORT_textBtn').style.background = mode === 'text' ? '#d68910' : '#f39c12'; if (mode === 'text') { paintCanvas.style.cursor = 'text'; } else { paintCanvas.style.cursor = 'crosshair'; } }; window.clearCanvas = function() { setupCanvas(); }; window.skipPainting = function() { const alertElement = document.querySelector('.custom-alert'); if (alertElement) { alertElement.remove(); } SendReport(currentScreenshotData, currentScreenshotDataFull, currentText, 'skipped'); }; window.savePaintedImage = function() { const paintedImageData = paintCanvas.toDataURL('image/png'); const alertElement = document.querySelector('.custom-alert'); if (alertElement) { alertElement.remove(); } SendReport(currentScreenshotData, currentScreenshotDataFull, currentText, paintedImageData); }; function setupCanvas() { const img = currentImageMode === 'viewport' ? baseImageViewport : baseImageFull; const maxWidth = window.innerWidth * 0.8; const maxHeight = window.innerHeight * 0.6; let displayWidth = img.naturalWidth; let displayHeight = img.naturalHeight; if (displayWidth > maxWidth) { displayHeight = (displayHeight * maxWidth) / displayWidth; displayWidth = maxWidth; } if (displayHeight > maxHeight) { displayWidth = (displayWidth * maxHeight) / displayHeight; displayHeight = maxHeight; } paintCanvas.width = displayWidth; paintCanvas.height = displayHeight; paintCtx.clearRect(0, 0, paintCanvas.width, paintCanvas.height); paintCtx.drawImage(img, 0, 0, paintCanvas.width, paintCanvas.height); } function GetMouseX(e, canvas) { const rect = paintCanvas.getBoundingClientRect(); return ((e.clientX - rect.left) * canvas.width) / rect.width; } function GetMouseY(e, canvas) { const rect = paintCanvas.getBoundingClientRect(); return ((e.clientY - rect.top) * canvas.height) / rect.height; } function startDraw(e) { if (drawMode === 'text') return; isDrawing = true; lastX = startX = GetMouseX(e, paintCanvas); lastY = startY = GetMouseY(e, paintCanvas); } function draw(e) { if (!isDrawing || drawMode === 'text') return; const currentX = GetMouseX(e, paintCanvas); const currentY = GetMouseY(e, paintCanvas); paintCtx.strokeStyle = '#e74c3c'; paintCtx.lineWidth = 3; paintCtx.lineCap = 'round'; if (drawMode === 'pen') { paintCtx.beginPath(); paintCtx.moveTo(lastX, lastY); paintCtx.lineTo(currentX, currentY); paintCtx.stroke(); lastX = currentX; lastY = currentY; } } function stopDraw(e) { if (!isDrawing) return; isDrawing = false; if (drawMode === 'rect') { const endX = GetMouseX(e, paintCanvas); const endY = GetMouseY(e, paintCanvas); paintCtx.strokeStyle = '#e74c3c'; paintCtx.lineWidth = 3; paintCtx.strokeRect(startX, startY, endX - startX, endY - startY); } } function handleClick(e) { if (drawMode !== 'text') return; const x = GetMouseX(e, paintCanvas); const y = GetMouseY(e, paintCanvas); const text = prompt('Írja be a szöveget:'); if (text) { paintCtx.fillStyle = '#e74c3c'; paintCtx.font = '16px Arial'; paintCtx.fillText(text, x, y); } } function initializePaintCanvas() { paintCanvas = document.getElementById('BUGREPORT_paintCanvas'); paintCtx = paintCanvas.getContext('2d'); paintCanvas.addEventListener('mousedown', startDraw); paintCanvas.addEventListener('mousemove', draw); paintCanvas.addEventListener('mouseup', stopDraw); paintCanvas.addEventListener('click', handleClick); baseImageViewport.onload = () => { setupCanvas(); }; if (baseImageFull.complete || baseImageFull.naturalWidth > 0) { setupCanvas(); } else { baseImageFull.onload = () => { if (currentImageMode === 'full') { setupCanvas(); } }; } } function BrowserData() { const data = []; // Document [ { k: 'URL', v: () => document.URL }, { k: 'referrer', v: () => document.referrer }, { k: 'characterSet', v: () => document.characterSet }, { k: 'contentType', v: () => document.contentType }, { k: 'visibilityState', v: () => document.visibilityState }, { k: 'title', v: () => document.title }, { k: 'domain', v: () => document.domain }, { k: 'lastModified', v: () => document.lastModified }, { k: 'readyState', v: () => document.readyState }, { k: 'compatMode', v: () => document.compatMode }, { k: 'dir', v: () => document.dir }, { k: 'fullscreenEnabled', v: () => document.fullscreenEnabled }, { k: 'hidden', v: () => document.hidden }, { k: 'documentElement.lang', v: () => document.documentElement.lang } ].forEach(o => data.push(`document.${o.k} paraméter értéke: ${o.v()}`)); // Location [ 'href','protocol','host','hostname','port','pathname','search','hash','origin' ].forEach(p => data.push(`location.${p} paraméter értéke: ${location[p]}`)); if (location.ancestorOrigins) data.push(`location.ancestorOrigins paraméter értéke: ${[...location.ancestorOrigins].join(', ')}`); // Navigator alap és kiterjesztett [ 'userAgent','platform','language','languages','onLine','maxTouchPoints','hardwareConcurrency','deviceMemory', 'cookieEnabled','doNotTrack','appCodeName','appName','appVersion','product','productSub','vendor','vendorSub', 'buildID','oscpu','appMinorVersion','pdfViewerEnabled','webdriver' ].forEach(p => { const v = navigator[p]; if (v!==undefined) data.push(`navigator.${p} paraméter értéke: ${Array.isArray(v)?v.join(', '):v}`); }); if (navigator.javaEnabled) data.push(`navigator.javaEnabled() paraméter értéke: ${navigator.javaEnabled()}`); // Navigator.connection if (navigator.connection) { ['type','downlink','rtt','effectiveType','saveData'] .forEach(k => data.push(`connection.${k} paraméter értéke: ${navigator.connection[k]}`)); } // Navigator.userAgentData (Chrome) if (navigator.userAgentData) { data.push(`userAgentData.mobile paraméter értéke: ${navigator.userAgentData.mobile}`); data.push(`userAgentData.brands paraméter értéke: ${navigator.userAgentData.brands.map(b=>b.brand+'('+b.version+')').join(', ')}`); } // Plugins & mimeTypes if (navigator.plugins) data.push(`plugins paraméter értéke: ${Array.from(navigator.plugins).map(p=>p.name).join(', ')}`); if (navigator.mimeTypes) data.push(`mimeTypes paraméter értéke: ${Array.from(navigator.mimeTypes).map(m=>m.type).join(', ')}`); // Window & screen [ 'innerWidth','innerHeight','outerWidth','outerHeight','devicePixelRatio', 'scrollX','scrollY','name','length','screenLeft','screenTop' ].forEach(p => data.push(`window.${p} paraméter értéke: ${window[p]}`)); [ 'width','height','availWidth','availHeight','colorDepth','pixelDepth', 'availLeft','availTop','isExtended' ].forEach(p => data.push(`screen.${p} paraméter értéke: ${screen[p]}`)); if (screen.orientation) { data.push(`screen.orientation.type paraméter értéke: ${screen.orientation.type}`); data.push(`screen.orientation.angle paraméter értéke: ${screen.orientation.angle}`); } // History data.push(`history.length paraméter értéke: ${history.length}`); data.push(`history.state paraméter értéke: ${JSON.stringify(history.state)}`); // Timezone & Intl try { const intl = Intl.DateTimeFormat().resolvedOptions(); data.push(`timezone paraméter értéke: ${intl.timeZone}`); data.push(`Intl.locale paraméter értéke: ${intl.locale}`); data.push(`Intl.calendar paraméter értéke: ${intl.calendar}`); data.push(`Intl.numberingSystem paraméter értéke: ${intl.numberingSystem}`); } catch {} // Performance if (performance) { ['timeOrigin'].forEach(p => data.push(`performance.${p} paraméter értéke: ${performance[p]}`)); if (performance.navigation) ['type','redirectCount'].forEach(p=>data.push(`performance.navigation.${p} paraméter értéke: ${performance.navigation[p]}`)); if (performance.memory) ['totalJSHeapSize','usedJSHeapSize','jsHeapSizeLimit'].forEach(p=>data.push(`performance.memory.${p} paraméter értéke: ${performance.memory[p]}`)); data.push(`performance.getEntries().length paraméter értéke: ${performance.getEntries().length}`); if (performance.timing) { data.push(`performance.timing.loadEventEnd paraméter értéke: ${performance.timing.loadEventEnd}`); data.push(`performance.timing.domContentLoadedEventEnd paraméter értéke: ${performance.timing.domContentLoadedEventEnd}`); } data.push(`performance.now() paraméter értéke: ${performance.now()}`); } // Storage & cookies data.push(`document.cookie.length paraméter értéke: ${document.cookie.length}`); try { data.push(`localStorage.length paraméter értéke: ${localStorage.length}`); } catch {} try { data.push(`sessionStorage.length paraméter értéke: ${sessionStorage.length}`); } catch {} data.push(`indexedDB elérhető: ${'indexedDB' in window}`); data.push(`caches elérhető: ${'caches' in window}`); // Battery if (navigator.getBattery) { navigator.getBattery().then(b=>{ ['charging','level','chargingTime','dischargingTime'] .forEach(p=>data.push(`battery.${p} paraméter értéke: ${b[p]}`)); }); } // Crypto data.push(`crypto elérhető: ${'crypto' in window}`); data.push(`crypto.subtle elérhető: ${!!(crypto && crypto.subtle)}`); data.push(`crypto.randomUUID elérhető: ${typeof crypto.randomUUID === 'function'}`); data.push(`crypto.getRandomValues elérhető: ${typeof crypto.getRandomValues === 'function'}`); // Geolocation, clipboard, permissions, mediaDevices, usb, serial, bluetooth, xr, serviceWorker, sendBeacon, vibrate [ 'geolocation','clipboard','permissions','mediaDevices','usb','serial','bluetooth','xr','serviceWorker','sendBeacon','vibrate','keyboard','mediaCapabilities' ].forEach(api => data.push(`${api} elérhető: ${api in navigator || api in window}`)); // Permissions lekérés (state) if (navigator.permissions) { ['geolocation','notifications','microphone','camera','clipboard-read','clipboard-write'].forEach(name => { navigator.permissions.query({name}).then(res => { data.push(`permissions.${name} paraméter értéke: ${res.state}`); }).catch(()=>{}); }); } // CSS / vizuális adatok try { data.push(`getComputedStyle(document.body).fontFamily paraméter értéke: ${getComputedStyle(document.body).fontFamily}`); } catch {} data.push(`matchMedia("(prefers-color-scheme: dark)").matches paraméter értéke: ${matchMedia("(prefers-color-scheme: dark)").matches}`); // Dátum/idő data.push(`Date.now() paraméter értéke: ${Date.now()}`); data.push(`new Date().getTimezoneOffset() paraméter értéke: ${new Date().getTimezoneOffset()}`); // Feature detect / Events data.push(`draggable támogatás: ${'draggable' in document.createElement('span')}`); data.push(`pointerEvents támogatás: ${'onpointerdown' in window}`); data.push(`touchEvent támogatás: ${'ontouchstart' in window}`); data.push(`fullscreen API: ${'fullscreenEnabled' in document}`); data.push(`visibility API: ${typeof document.hidden !== 'undefined'}`); return data; } function SendReport(screenshotData, screenshotDataFull, text = "%DefaultText%", paintedImage = null) { if (text == "%DefaultText%") { var html = `
Kérjük, írja le a hibát amit tapasztal minél pontosabban.
Kérjük írja le mi történt!
`; CreateAlertBox("Figyelem", html); return; } SendReport(screenshotData, screenshotDataFull, reporttext); CloseAlertBox(overlay); }; document.getElementById('BUGREPORT_AlertBtnNo').onclick = function () { CloseAlertBox(overlay); bugBtn.textContent = 'Hibabejelentés 🐛'; bugBtn.disabled = false; }; } else if (paintedImage === null && screenshotData != null) { currentScreenshotData = screenshotData; currentScreenshotDataFull = screenshotDataFull; currentText = text; baseImageViewport.src = screenshotData; baseImageFull.src = screenshotDataFull; var paintHtml = `Jelölje be a problémás területeket a képernyőn.