From 66f6a598f4ac4dc64a12c221dd613d996da5619d Mon Sep 17 00:00:00 2001 From: chromoxdor <33860956+chromoxdor@users.noreply.github.com> Date: Tue, 3 Feb 2026 10:43:40 +0100 Subject: [PATCH] [LOG] autoscroll fix, code reduction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fixes a long-existing autoscroll issue where the whole site would scroll instead of just the log content. - reducing the code by simplifying the „browser check" and refining the loop --- src/src/Static/WebStaticData.h | 109 +++++++++---------- static/fetch_and_parse_log.js | 191 +++++++++++++-------------------- 2 files changed, 124 insertions(+), 176 deletions(-) diff --git a/src/src/Static/WebStaticData.h b/src/src/Static/WebStaticData.h index f5ea29d48..2f5953c8b 100644 --- a/src/src/Static/WebStaticData.h +++ b/src/src/Static/WebStaticData.h @@ -406,68 +406,61 @@ static const char DATA_UPDATE_SENSOR_VALUES_DEVICE_PAGE_JS[] PROGMEM = { #ifdef WEBSERVER_INCLUDE_JS static const char DATA_FETCH_AND_PARSE_LOG_JS[] PROGMEM = { "function elId(e){return document.getElementById(e)}" -"function getBrowser(){var e,t=navigator.userAgent,o=t.match(/(opera|chrome|safari|firefox|msie|trident(?=\\/))\\/?\\s*(\\d+)/i)||[];" -"return/trident/i.test(o[1])?{name:'IE',version:(e=/\\brv[ :]+(\\d+)/g.exec(t)||[])[1]||''}:" -"'Chrome'===o[1]&&null!=(e=t.match(/\\bOPR|Edge\\/(\\d+)/))?" -"{name:'Opera',version:e[1]}:" -"(o=o[2]?[o[1],o[2]]:[navigator.appName,navigator.appVersion,'-?']," -"null!=(e=t.match(/version\\/(\\d+)/i))&&o.splice(1,1,e[1]),{name:o[0],version:o[1]})}" -"var browser=getBrowser(),currentBrowser=browser.name+browser.version;" -"textToDisplay=(browser.name=browser.version<12)?" -"'Error: '+currentBrowser+' is not supported! Please try a modern web browser.':" -"'Fetching log entries...';" -"elId('copyText_1').innerHTML=textToDisplay;" -"loopDeLoop(1000,0);" -"var logLevel=['Unused','Error','Info','Debug','Debug More','Undefined','Undefined','Undefined','Undefined','Debug Dev'];" -"function loopDeLoop(e,t){let o='copyText_1';" -"isNaN(t)&&(t=1),null==e&&(e=1000),scrolling_type=e<=500?'auto':'smooth';" -"var r,n,i='',l=0,s=setInterval(function(){" -"if(l>0){clearInterval(s);return}" -"++t>1?l=1:fetch('/logjson').then(function(t){" -"if(200!==t.status){console.log('Looks like there was a problem. Status Code: '+t.status);return}" -"t.json().then(function(t){var l;" -"for(null==n&&(n=''),r=0;r'+t.Log.Entries[r].timestamp+': '+" -"t.Log.Entries[r].text+'')}" -"e=t.Log.TTL," -"''!==n&&('Fetching log entries...'==elId(o).innerHTML&&(elId(o).innerHTML='')," -"elId(o).innerHTML+=n)," -"n='';" -"!0==(autoscroll_on=elId('autoscroll').checked)&&''!==i&&elId(i).scrollIntoView({behavior:scrolling_type});" +"document.getElementById('logfilter')||(document.querySelector('section').innerHTML+=" +"'');" +"const ct1=elId('copyText_1');" +"window.fetch?ct1.textContent='Fetching log entries...':" +"ct1.textContent='Error: This browser is not supported. Please use a modern browser.';" +"const logLevel={0:'Unused',1:'Error',2:'Info',3:'Debug',4:'Debug More',9:'Debug Dev'};" +"function loopDeLoop(e=1000){setTimeout(function(){fetch('/logjson')" +".then(e=>{if(!e.ok)throw Error(e.status);return e.json()})" +".then(t=>{let o='';" +"for(let l=0;l" +"${i.timestamp}: ${i.text}`)}" +"e=t.Log.TTL||e;" +"o&&(ct1.textContent==='Fetching log entries...'&&(ct1.innerHTML=''),ct1.innerHTML+=o);" "applyLogFilter();" -"elId('current_loglevel').innerHTML='Logging: '+logLevel[t.Log.SettingsWebLogLevel]+' ('+t.Log.SettingsWebLogLevel+')';" -"clearInterval(s);loopDeLoop(e,0)" -"})}).catch(function(t){" -"elId(o).innerHTML+='
>> '+t.message+' <<
';" -"autoscroll_on=elId('autoscroll').checked;" -"elId(o).scrollTop=elId(o).scrollHeight;" -"e=5000;clearInterval(s);loopDeLoop(e,0)" -"}),l=1},e)}" -"function applyLogFilter(){let e=elId('logfilter').value.split(';').map(e=>e.trim()).filter(Boolean)," +"elId('autoscroll')?.checked&&ct1.scrollTo({top:ct1.scrollHeight,behavior:e<=500?'auto':'smooth'});" +"let n=t.Log.SettingsWebLogLevel,r=logLevel[n]??'Undefined';" +"elId('current_loglevel').textContent=`Logging: ${r} (${n})`;" +"loopDeLoop(e)})" +".catch(e=>{ct1.innerHTML+=`
>> ${e.message} <<
`;" +"ct1.scrollTop=ct1.scrollHeight;loopDeLoop(5000)})},e)}" +"function applyLogFilter(){" +"let e=elId('logfilter').value.split(';').map(e=>e.trim()).filter(Boolean)," "t=document.querySelectorAll('#copyText_1 > div')," "o=e.some(e=>!e.startsWith('!'));" -"for(let r of t){r.dataset.originalHtml||(r.dataset.originalHtml=r.innerHTML);" -"let n=r.dataset.originalHtml,i=r.textContent.toLowerCase(),l=[],s=!1,a=!o;" -"for(let d of e){" -"if(d.startsWith('!')){let c=d.slice(1);" -"if(!c.includes('&')||c.startsWith('&')||c.endsWith('&')){" -"if(c&&i.includes(c.toLowerCase())){s=!0;break}}else{" -"let g=c.split('&').map(e=>e.trim()).filter(Boolean),f=-1,u=!0;" -"for(let p of g){let L=i.indexOf(p.toLowerCase(),f+1);if(-1===L){u=!1;break}f=L}if(u){s=!0;break}}continue}" -"if(d.includes('&')&&!d.startsWith('&')&&!d.endsWith('&')){" -"let h=d.split('&').map(e=>e.trim()).filter(Boolean);" -"if(h.length>=2){let m=-1,$=!0;for(let _ of h){let b=i.indexOf(_.toLowerCase(),m+1);if(-1===b){$=!1;break}m=b}if($){l.push(...h),a=!0;break}}continue}" -"if(i.includes(d.toLowerCase())){l.push(d),a=!0;break}}" -"if(s||!a){r.style.display='none';continue}r.style.display='';r.innerHTML=highlightOutsideTags(n,l)}}" +"for(let l of t){" +"l.dataset.originalHtml||(l.dataset.originalHtml=l.innerHTML);" +"let i=l.dataset.originalHtml,n=l.textContent.toLowerCase(),r=[],s=!1,a=!o;" +"for(let c of e){" +"if(c.startsWith('!')){let g=c.slice(1);" +"if(!g.includes('&')||g.startsWith('&')||g.endsWith('&')){" +"if(g&&n.includes(g.toLowerCase())){s=!0;break}}" +"else{let f=g.split('&').map(e=>e.trim()).filter(Boolean),u=-1,d=!0;" +"for(let p of f){let h=n.indexOf(p.toLowerCase(),u+1);if(h===-1){d=!1;break}u=h}" +"if(d){s=!0;break}}continue}" +"if(c.includes('&')&&!c.startsWith('&')&&!c.endsWith('&')){" +"let L=c.split('&').map(e=>e.trim()).filter(Boolean);" +"if(L.length>=2){let _=-1,$=!0;" +"for(let b of L){let m=n.indexOf(b.toLowerCase(),_+1);if(m===-1){$=!1;break}_=m}" +"if($){r.push(...L),a=!0;break}}continue}" +"if(n.includes(c.toLowerCase())){r.push(c),a=!0;break}}" +"if(s||!a){l.style.display='none';continue}" +"l.style.display='';l.innerHTML=highlightOutsideTags(i,r)}}" "function highlightOutsideTags(e,t){if(!t.length)return e;" -"let o='',r=!1,n=0;" -"for(;n'===i){r=!1;o+=i;n++;continue}" -"if(!r){let l=!1;for(let s of t){let a=e.slice(n,n+s.length);" -"if(a.toLowerCase()===s.toLowerCase()){o+=`${a}`;n+=s.length;l=!0;break}}if(l)continue}o+=i;n++}return o}" +"let o='',l=!1,i=0;" +"for(;i'===n){l=!1;o+=n;i++;continue}" +"if(!l){let r=!1;" +"for(let s of t){let a=e.slice(i,i+s.length);" +"if(a.toLowerCase()===s.toLowerCase()){" +"o+=`${a}`;" +"i+=s.length;r=!0;break}}" +"if(r)continue}" +"o+=n;i++}return o}" +"loopDeLoop(1000);" "const input=document.getElementById('logfilter');" "input&&(input.placeholder='\"!\"=exclude \";\"=or \"&\"=and (e.g. !act)');" }; diff --git a/static/fetch_and_parse_log.js b/static/fetch_and_parse_log.js index 6aec69cbf..30241a962 100644 --- a/static/fetch_and_parse_log.js +++ b/static/fetch_and_parse_log.js @@ -1,132 +1,87 @@ //---------------no need to be included into WebStaticData.h--------------------------------------------- // if no filter input exists, create it document.getElementById("logfilter") || - (document.querySelector("section").innerHTML += - ''); + (document.querySelector("section").innerHTML += + ''); //------------------------------------------------------------ function elId(e) { return document.getElementById(e); } -function getBrowser() { - var ua = navigator.userAgent, - tem, M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || []; - if (/trident/i.test(M[1])) { - tem = /\brv[ :]+(\d+)/g.exec(ua) || []; - return { - name: 'IE', - version: (tem[1] || '') - }; - } - if (M[1] === 'Chrome') { - tem = ua.match(/\bOPR|Edge\/(\d+)/); - if (tem != null) { - return { - name: 'Opera', - version: tem[1] - }; - } - } - M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, '-?']; - if ((tem = ua.match(/version\/(\d+)/i)) != null) { - M.splice(1, 1, tem[1]); - } - return { - name: M[0], - version: M[1] - }; -} -var browser = getBrowser(); -var currentBrowser = browser.name + browser.version; -if (browser.name = 'IE' && browser.version < 12) { - textToDisplay = 'Error: ' + currentBrowser + ' is not supported! Please try a modern web browser.' -} else { - textToDisplay = 'Fetching log entries...'; -} -elId('copyText_1').innerHTML = textToDisplay; -loopDeLoop(1000, 0); -var logLevel = new Array('Unused', 'Error', 'Info', 'Debug', 'Debug More', 'Undefined', 'Undefined', 'Undefined', 'Undefined', 'Debug Dev'); -function loopDeLoop(timeForNext, activeRequests) { - var maximumRequests = 1; +const ct1 = elId('copyText_1'); + +if (!window.fetch) { + ct1.textContent = 'Error: This browser is not supported. Please use a modern browser.'; +} else { + ct1.textContent = 'Fetching log entries...'; +} + +const logLevel = { + 0: 'Unused', + 1: 'Error', + 2: 'Info', + 3: 'Debug', + 4: 'Debug More', + 9: 'Debug Dev' +}; + +loopDeLoop(1000); + +function loopDeLoop(timeForNext = 1000) { const url = '/logjson'; - const ct1 = 'copyText_1'; - if (isNaN(activeRequests)) { - activeRequests = maximumRequests; - } - if (timeForNext == null) { - timeForNext = 1000; - } - if (timeForNext <= 500) { - scrolling_type = 'auto'; - } else { - scrolling_type = 'smooth'; - } - var c; - var logEntriesChunk; - var currentIDtoScrollTo = ''; - var check = 0; - var i = setInterval(function() { - if (check > 0) { - clearInterval(i); - return; - } - ++activeRequests; - if (activeRequests > maximumRequests) { - check = 1; - } else { - fetch(url).then(function(response) { - if (response.status !== 200) { - console.log('Looks like there was a problem. Status Code: ' + response.status); - return; + + setTimeout(function () { + fetch(url) + .then(response => { + if (!response.ok) { + throw new Error(response.status); } - response.json().then(function(data) { - var logEntry; - if (logEntriesChunk == null) { - logEntriesChunk = ''; - } - for (c = 0; c < data.Log.nrEntries; ++c) { - try { - logEntry = data.Log.Entries[c].timestamp; - } catch (err) { - logEntry = err.name; - } finally { - if (logEntry !== "TypeError") { - currentIDtoScrollTo = data.Log.Entries[c].timestamp; - logEntriesChunk += '
' + data.Log.Entries[c].timestamp + ': ' + data.Log.Entries[c].text + '
'; - } - } - } - timeForNext = data.Log.TTL; - if (logEntriesChunk !== '') { - if (elId(ct1).innerHTML == 'Fetching log entries...') { - elId(ct1).innerHTML = ''; - } - elId(ct1).innerHTML += logEntriesChunk; - } - logEntriesChunk = ''; - autoscroll_on = elId('autoscroll').checked; - if (autoscroll_on == true && currentIDtoScrollTo !== '') { - elId(currentIDtoScrollTo).scrollIntoView({ - behavior: scrolling_type - }); - } - applyLogFilter(); - elId('current_loglevel').innerHTML = 'Logging: ' + logLevel[data.Log.SettingsWebLogLevel] + ' (' + data.Log.SettingsWebLogLevel + ')'; - clearInterval(i); - loopDeLoop(timeForNext, 0); - return; - }) - }).catch(function(err) { - elId(ct1).innerHTML += '
>> ' + err.message + ' <<
'; - autoscroll_on = elId('autoscroll').checked; - elId(ct1).scrollTop = elId(ct1).scrollHeight; - timeForNext = 5000; - clearInterval(i); - loopDeLoop(timeForNext, 0); - return; + return response.json(); }) - }; - check = 1; + .then(data => { + let logEntriesChunk = ''; + + for (let c = 0; c < data.Log.nrEntries; c++) { + const entry = data.Log.Entries[c]; + if (!entry || !entry.timestamp) continue; + + logEntriesChunk += + `
+ ${entry.timestamp}: ${entry.text} +
`; + } + + timeForNext = data.Log.TTL || timeForNext; + + if (logEntriesChunk) { + if (ct1.textContent === 'Fetching log entries...') { + ct1.innerHTML = ''; + } + ct1.innerHTML += logEntriesChunk; + } + + applyLogFilter(); + + if (elId('autoscroll')?.checked) { + ct1.scrollTo({ + top: ct1.scrollHeight, + behavior: timeForNext <= 500 ? 'auto' : 'smooth' + }); + } + + const level = data.Log.SettingsWebLogLevel; + const levelName = logLevel[level] ?? 'Undefined'; + + elId('current_loglevel').textContent = + `Logging: ${levelName} (${level})`; + + loopDeLoop(timeForNext); + }) + .catch(err => { + ct1.innerHTML += `
>> ${err.message} <<
`; + ct1.scrollTop = ct1.scrollHeight; + loopDeLoop(5000); + }); }, timeForNext); }