mirror of
https://github.com/adelphes/android-dev-ext.git
synced 2025-12-22 17:39:19 +00:00
Improve logcat support
Move html into a separate resource file. Implement regex filtering and logcat clear. Fixes #7
This commit is contained in:
153
src/logcat.js
153
src/logcat.js
@@ -2,6 +2,7 @@
|
|||||||
// vscode stuff
|
// vscode stuff
|
||||||
const { EventEmitter, Uri } = require('vscode');
|
const { EventEmitter, Uri } = require('vscode');
|
||||||
// node and external modules
|
// node and external modules
|
||||||
|
const fs = require('fs');
|
||||||
const os = require('os');
|
const os = require('os');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const WebSocketServer = require('ws').Server;
|
const WebSocketServer = require('ws').Server;
|
||||||
@@ -26,6 +27,7 @@ class LogcatContent {
|
|||||||
this._notifying = 0;
|
this._notifying = 0;
|
||||||
this._refreshRate = 200; // ms
|
this._refreshRate = 200; // ms
|
||||||
this._state = '';
|
this._state = '';
|
||||||
|
this._htmltemplate = '';
|
||||||
this._adbclient = new ADBClient(uri.query);
|
this._adbclient = new ADBClient(uri.query);
|
||||||
this._initwait = new Promise((resolve, reject) => {
|
this._initwait = new Promise((resolve, reject) => {
|
||||||
this._state = 'connecting';
|
this._state = 'connecting';
|
||||||
@@ -44,11 +46,12 @@ class LogcatContent {
|
|||||||
reject(e);
|
reject(e);
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
LogcatContent.byLogcatID[this._logcatid] = this;
|
||||||
}
|
}
|
||||||
get content() {
|
get content() {
|
||||||
if (this._initwait) return this._initwait;
|
if (this._initwait) return this._initwait;
|
||||||
if (this._state !== 'disconnected')
|
if (this._state !== 'disconnected')
|
||||||
return this.htmlBootstrap(true, '');
|
return this.htmlBootstrap({connected:true, status:'',oldlogs:''});
|
||||||
// if we're in the disconnected state, and this.content is called, it means the user has requested
|
// if we're in the disconnected state, and this.content is called, it means the user has requested
|
||||||
// this logcat again - check if the device has reconnected
|
// this logcat again - check if the device has reconnected
|
||||||
return this._initwait = new Promise((resolve, reject) => {
|
return this._initwait = new Promise((resolve, reject) => {
|
||||||
@@ -71,94 +74,65 @@ class LogcatContent {
|
|||||||
this._oldhtmllogs = this._prevlogs._oldhtmllogs;
|
this._oldhtmllogs = this._prevlogs._oldhtmllogs;
|
||||||
this._prevlogs = null;
|
this._prevlogs = null;
|
||||||
this._initwait = null;
|
this._initwait = null;
|
||||||
var cached_content = this.htmlBootstrap(false, 'Device disconnected');
|
var cached_content = this.htmlBootstrap({connected:false, status:'Device disconnected',oldlogs: this._oldhtmllogs.join(os.EOL)});
|
||||||
resolve(cached_content);
|
resolve(cached_content);
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
sendDisconnectMsg() {
|
sendClientMessage(msg) {
|
||||||
var clients = LogcatContent._wss.clients.filter(client => client._logcatid === this._logcatid);
|
var clients = LogcatContent._wss.clients.filter(client => client._logcatid === this._logcatid);
|
||||||
clients.forEach(client => client.send(':disconnect'));
|
clients.forEach(client => client.send(msg+'\n')); // include a newline to try and persuade a buffer write
|
||||||
|
}
|
||||||
|
sendDisconnectMsg() {
|
||||||
|
this.sendClientMessage(':disconnect');
|
||||||
|
}
|
||||||
|
onClientConnect(client) {
|
||||||
|
if (this._oldhtmllogs.length) {
|
||||||
|
var lines = '<div class="logblock">' + this._oldhtmllogs.join(os.EOL) + '</div>';
|
||||||
|
client.send(lines);
|
||||||
|
}
|
||||||
|
// if the window is tabbed away and then returned to, vscode assumes the content
|
||||||
|
// has not changed from the original bootstrap. So it proceeds to load the html page (with no data),
|
||||||
|
// causing a connection to the WSServer as if the connection is still valid (which it was, originally).
|
||||||
|
// If it's not, tell the client (again) that the device has disconnected
|
||||||
|
if (this._state === 'disconnected')
|
||||||
|
this.sendDisconnectMsg();
|
||||||
|
}
|
||||||
|
onClientMessage(client, message) {
|
||||||
|
if (message === 'cmd:clear_logcat') {
|
||||||
|
if (this._state !== 'connected') return;
|
||||||
|
new ADBClient(this._adbclient.deviceid).shell_cmd({command:'logcat -c'})
|
||||||
|
.then(() => {
|
||||||
|
// clear everything and tell the clients
|
||||||
|
this._logs = []; this._htmllogs = []; this._oldhtmllogs = [];
|
||||||
|
this.sendClientMessage(':logcat_cleared');
|
||||||
|
})
|
||||||
|
.fail(e => {
|
||||||
|
D('Clear logcat command failed: ' + e.message);
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
updateLogs() {
|
updateLogs() {
|
||||||
// no point in formatting the data if there are no connected clients
|
// no point in formatting the data if there are no connected clients
|
||||||
var clients = LogcatContent._wss.clients.filter(client => client._logcatid === this._logcatid);
|
var clients = LogcatContent._wss.clients.filter(client => client._logcatid === this._logcatid);
|
||||||
if (clients.length) {
|
if (clients.length) {
|
||||||
var lines = '<div style="display:inline-block">' + this._htmllogs.join('') + '</div>';
|
var lines = '<div class="logblock">' + this._htmllogs.join(os.EOL) + '</div>';
|
||||||
clients.forEach(client => client.send(lines));
|
clients.forEach(client => client.send(lines));
|
||||||
}
|
}
|
||||||
// once we've updated all the clients, discard the info
|
// once we've updated all the clients, discard the info
|
||||||
this._oldhtmllogs = this._htmllogs.concat(this._oldhtmllogs).slice(0, 5000);
|
this._oldhtmllogs = this._htmllogs.concat(this._oldhtmllogs).slice(0, 10000);
|
||||||
this._htmllogs = [], this._logs = [];
|
this._htmllogs = [], this._logs = [];
|
||||||
}
|
}
|
||||||
htmlBootstrap(connected, statusmsg) {
|
htmlBootstrap(vars) {
|
||||||
return `<!DOCTYPE html>
|
if (!this._htmltemplate)
|
||||||
<html><head>
|
this._htmltemplate = fs.readFileSync(path.join(__dirname,'res/logcat.html'), 'utf8');
|
||||||
<style type="text/css">
|
vars = Object.assign({
|
||||||
.V {color:#999}
|
logcatid: this._logcatid,
|
||||||
.D {color:#519B4F}
|
wssport: LogcatContent._wssport,
|
||||||
.I {color:#CCC0D3}
|
}, vars);
|
||||||
.W {color:#BD955C}
|
// simple value replacement using !{name} as the placeholder
|
||||||
.E {color:#f88}
|
var html = this._htmltemplate.replace(/!\{(.*?)\}/g, (match,expr) => ''+(vars[expr.trim()]||''));
|
||||||
.F {color:#f66}
|
return html;
|
||||||
.hide {display:none}
|
|
||||||
.unhide {display:inline-block}
|
|
||||||
</style></head>
|
|
||||||
<body style="color:#fff;font-size:.9em">
|
|
||||||
<div id="status" style="color:#888">${statusmsg}</div>
|
|
||||||
<div id="rows">${this._oldhtmllogs.join(os.EOL)}</div>
|
|
||||||
<script>
|
|
||||||
function start() {
|
|
||||||
var rows = document.getElementById('rows');
|
|
||||||
var last_known_scroll_position=0, selectall=0;
|
|
||||||
var selecttext = (rows) => {
|
|
||||||
if (!rows) return window.getSelection().empty();
|
|
||||||
var range = document.createRange();
|
|
||||||
range.selectNode(rows);
|
|
||||||
window.getSelection().addRange(range);
|
|
||||||
}
|
|
||||||
window.addEventListener('scroll', function(e) {
|
|
||||||
if ((last_known_scroll_position = window.scrollY)===0) {
|
|
||||||
var hidden = document.getElementsByClassName('hide');
|
|
||||||
for (var i=hidden.length-1; i>=0; i--)
|
|
||||||
hidden[i].className='unhide';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
window.addEventListener('keypress', function(e) {
|
|
||||||
if (e.ctrlKey && /[aA]/.test(e.key) && !selectall) {
|
|
||||||
selectall = 1;
|
|
||||||
selecttext(rows);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
window.addEventListener('keyup', function(e) {
|
|
||||||
selectall = 0;
|
|
||||||
/^escape$/i.test(e.key) && selecttext(null);
|
|
||||||
});
|
|
||||||
var setStatus = (x) => { document.getElementById('status').textContent = x; }
|
|
||||||
var connect = () => {
|
|
||||||
try {
|
|
||||||
setStatus('Connecting...');
|
|
||||||
var x = new WebSocket('ws://127.0.0.1:${LogcatContent._wssport}/${this._logcatid}');
|
|
||||||
x.onopen = e => { setStatus('') };x.onclose = e => { };x.onerror = e => { setStatus('Connection error') }
|
|
||||||
x.onmessage = e => {
|
|
||||||
var logs = e.data;
|
|
||||||
if (/^:disconnect$/.test(logs)) {
|
|
||||||
x.close(),setStatus('Device disconnected');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (last_known_scroll_position > 0)
|
|
||||||
logs = '<div class="hide">'+logs+'</div>';
|
|
||||||
rows && rows.insertAdjacentHTML('afterbegin',logs);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
catch(e) { setStatus('Connection exception') }
|
|
||||||
}
|
|
||||||
${connected ? '' : '//'} connect();
|
|
||||||
}
|
|
||||||
setTimeout(start, 100);
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>`;
|
|
||||||
}
|
}
|
||||||
renotify() {
|
renotify() {
|
||||||
if (++this._notifying > 1) return;
|
if (++this._notifying > 1) return;
|
||||||
@@ -172,16 +146,17 @@ class LogcatContent {
|
|||||||
}
|
}
|
||||||
onLogcatContent(e) {
|
onLogcatContent(e) {
|
||||||
if (e.logs.length) {
|
if (e.logs.length) {
|
||||||
var mrfirst = e.logs.slice().reverse();
|
var mrlast = e.logs.slice();
|
||||||
this._logs = mrfirst.concat(this._logs);
|
this._logs = this._logs.concat(mrlast);
|
||||||
mrfirst.forEach(log => {
|
mrlast.forEach(log => {
|
||||||
if (!(log = log.trim())) return;
|
if (!(log = log.trim())) return;
|
||||||
// replace html-interpreted chars
|
// replace html-interpreted chars
|
||||||
var m = log.match(/^\d\d-\d\d\s+?\d\d:\d\d:\d\d\.\d+?\s+?(.)/);
|
var m = log.match(/^\d\d-\d\d\s+?\d\d:\d\d:\d\d\.\d+?\s+?(.)/);
|
||||||
var style = (m && m[1]) || '';
|
var style = (m && m[1]) || '';
|
||||||
log = log.replace(/[&"'<>]/g, c => ({ '&': '&', '"': '"', "'": ''', '<': '<', '>': '>' }[c]));
|
log = log.replace(/[&"'<>]/g, c => ({ '&': '&', '"': '"', "'": ''', '<': '<', '>': '>' }[c]));
|
||||||
this._htmllogs.unshift(`<div class="${style}">${log}</div>`);
|
this._htmllogs.unshift(`<div class="log ${style}">${log}</div>`);
|
||||||
})
|
|
||||||
|
});
|
||||||
this.renotify();
|
this.renotify();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -192,6 +167,9 @@ class LogcatContent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// hashmap of all LogcatContent instances, keyed on device id
|
||||||
|
LogcatContent.byLogcatID = {};
|
||||||
|
|
||||||
LogcatContent.initWebSocketServer = function () {
|
LogcatContent.initWebSocketServer = function () {
|
||||||
if (LogcatContent._wssdone) {
|
if (LogcatContent._wssdone) {
|
||||||
// already inited
|
// already inited
|
||||||
@@ -210,13 +188,18 @@ LogcatContent.initWebSocketServer = function () {
|
|||||||
this.wss.on('connection', client => {
|
this.wss.on('connection', client => {
|
||||||
// the client uses the url path to signify which logcat data it wants
|
// the client uses the url path to signify which logcat data it wants
|
||||||
client._logcatid = client.upgradeReq.url.match(/^\/?(.*)$/)[1];
|
client._logcatid = client.upgradeReq.url.match(/^\/?(.*)$/)[1];
|
||||||
// we're not really interested in anything the client sends
|
var lc = LogcatContent.byLogcatID[client._logcatid];
|
||||||
/*client.on('message', message => {
|
if (lc) lc.onClientConnect(client);
|
||||||
console.log('ws received: %s', message);
|
else client.close();
|
||||||
});
|
client.on('message', function(message) {
|
||||||
client.on('close', e => {
|
var lc = LogcatContent.byLogcatID[this._logcatid];
|
||||||
console.log('ws close');
|
if (lc) lc.onClientMessage(this, message);
|
||||||
|
}.bind(client));
|
||||||
|
/*client.on('close', e => {
|
||||||
|
console.log('client close');
|
||||||
});*/
|
});*/
|
||||||
|
// try and make sure we don't delay writes
|
||||||
|
client._socket && typeof(client._socket.setNoDelay)==='function' && client._socket.setNoDelay(true);
|
||||||
});
|
});
|
||||||
this.wss = null;
|
this.wss = null;
|
||||||
LogcatContent._wssdone.resolveWith(LogcatContent, []);
|
LogcatContent._wssdone.resolveWith(LogcatContent, []);
|
||||||
|
|||||||
186
src/res/logcat.html
Normal file
186
src/res/logcat.html
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf8">
|
||||||
|
<style type="text/css">
|
||||||
|
.V {color:#777} .vscode-light .V {color:#999} .vscode-high-contrast .V {color:#fff}
|
||||||
|
.D {color:#8b8} .vscode-light .D {color:#292} .vscode-high-contrast .D {color:#0a0}
|
||||||
|
.I {color:#99a} .vscode-light .I {color:#557} .vscode-high-contrast .I {color:#aaf}
|
||||||
|
.W {color:#C84} .vscode-light .W {color:#F80} .vscode-high-contrast .W {color:#f80}
|
||||||
|
.E {color:#f88} .vscode-light .E {color:#f55} .vscode-high-contrast .E {color:#f00}
|
||||||
|
.F {color:#f66} .vscode-light .F {color:#f00} .vscode-high-contrast .F {color:#f00}
|
||||||
|
.hide {display:none}
|
||||||
|
.logblock {display:inline-block}
|
||||||
|
.a {display:flex;flex-direction:column;position:absolute;top:0;bottom:0;left:0;right:0;}
|
||||||
|
.b {flex:0 0 auto;border-bottom: 1px solid rgba(128,128,128,.2); padding-bottom: .2em}
|
||||||
|
.vscode-high-contrast .b {border-color: #0cc}
|
||||||
|
.c {flex: 1 1 auto;overflow:auto;padding-top: .2em}
|
||||||
|
.g {margin:.6em .2em 0 .2em;background: none;border: 1px solid #444; color:#888;padding:.3em .8em;font-size: .9em}
|
||||||
|
.g:hover:enabled {color:#ccc;cursor: pointer} .g:focus:enabled,.g:focus:hover:enabled {color:#eee;cursor: pointer}
|
||||||
|
.vscode-light .g:enabled {color: #666;}
|
||||||
|
.vscode-light .g:hover:enabled,.vscode-light .g:focus:enabled,.vscode-light .g:focus:hover:enabled {color: #333;background: #eee;}
|
||||||
|
.vscode-high-contrast .g:enabled {color: #fff;border-color: #0cc;background:none;}
|
||||||
|
.vscode-high-contrast .g:hover:enabled,.vscode-high-contrast .g:focus:enabled {border-color: darkorange;}
|
||||||
|
.h{display: flex;align-items: center;flex-wrap: wrap;}
|
||||||
|
.log { white-space:nowrap }
|
||||||
|
.filter { display:none }
|
||||||
|
body {font-size:.9em}
|
||||||
|
#q {margin:.6em .2em 0 .2em;padding:.3em;width:20em;outline:none;border:solid 1px #444;color: #eee;background:rgba(128,128,128,.05);}
|
||||||
|
#q:hover { border-color: #464; }
|
||||||
|
#q:focus,#q:focus:hover { border-color: #4a4; }
|
||||||
|
.vscode-light #q {color: #333;border-color: #444;background:none;}
|
||||||
|
.vscode-light #q:hover { border-color: #464; }
|
||||||
|
.vscode-light #q:focus,.vscode-light #q:focus:hover { border-color: #4a4; }
|
||||||
|
.vscode-high-contrast #q {color: #fff;border-color: #0cc;background:none;}
|
||||||
|
.vscode-high-contrast #q:hover {border-color: darkorange;}
|
||||||
|
.vscode-high-contrast #q:focus,.vscode-high-contrast #q:focus:hover {border-color: darkorange;}
|
||||||
|
#lcount {font-family:monospace;font-size:1em;margin-top:.4em}
|
||||||
|
.vscode-dark #lcount {color:#484;} .vscode-light #lcount {color:#484;} .vscode-high-contrast #lcount {color:#0d0;}
|
||||||
|
.vscode-dark #status {color:#eee;} .vscode-light #status {color:#333;} .vscode-high-contrast #status {color:#fff;}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="a">
|
||||||
|
<div class="b">
|
||||||
|
<div class="h"><input id="q" placeholder="Filter regex"/><button id="clearlcbtn" class="g" disabled="true">Clear logcat</button></div>
|
||||||
|
<div id="lcount"></div>
|
||||||
|
</div>
|
||||||
|
<div id="rc" class="c">
|
||||||
|
<div id="status">!{status}</div>
|
||||||
|
<div id="rows">!{oldlogs}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
const getId = document.getElementById.bind(document);
|
||||||
|
const setStatus = (x) => { getId('status').textContent = ''+x; }
|
||||||
|
const start = () => {
|
||||||
|
var rows = getId('rows'), filter = getId('q');
|
||||||
|
var last_known_scroll_position=0, selectall=0, logcount=0, currfilter,ws;
|
||||||
|
var selecttext = (rows) => {
|
||||||
|
if (!rows) return window.getSelection().empty();
|
||||||
|
var range = document.createRange();
|
||||||
|
range.selectNode(rows);
|
||||||
|
window.getSelection().addRange(range);
|
||||||
|
};
|
||||||
|
getId('clearlcbtn').onclick = (e) => {
|
||||||
|
ws && ws.send('cmd:clear_logcat');
|
||||||
|
}
|
||||||
|
getId('rc').onscroll = (e) => {
|
||||||
|
if ((last_known_scroll_position = e.target.scrollTop)===0) {
|
||||||
|
var hidden = document.getElementsByClassName('hide');
|
||||||
|
for (var i=hidden.length-1; i>=0; i--)
|
||||||
|
hidden[i].className = hidden[i].className.replace(/\bhide\b/g,'').trim();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
updateLogCountDisplay = () => {
|
||||||
|
var msg = currfilter ? `${currfilter.matchCounts.true}/${logcount}` : logcount
|
||||||
|
getId('lcount').textContent = msg;
|
||||||
|
}
|
||||||
|
showFilterErr = (msg) => {
|
||||||
|
filter.style['border-color'] = 'red';
|
||||||
|
}
|
||||||
|
updateFilter = (new_filter_source) => {
|
||||||
|
if (currfilter && currfilter.source === new_filter_source) return; // nothing's changed
|
||||||
|
var newfilter = null;
|
||||||
|
if (new_filter_source) {
|
||||||
|
try {
|
||||||
|
newfilter = new RegExp(new_filter_source, 'i');
|
||||||
|
newfilter.matchCounts = {true:0,false:0};
|
||||||
|
}
|
||||||
|
catch(err) { return showFilterErr('Invalid regular expression') }
|
||||||
|
}
|
||||||
|
// reset the filtered elements
|
||||||
|
var logs = document.getElementsByClassName('log');
|
||||||
|
for (var i=logs.length-1,m; i>=0; i--) {
|
||||||
|
m = newfilter ? newfilter.test(logs[i].textContent) : 1;
|
||||||
|
logs[i].className = logs[i].className.replace(/\bfilter\b|$/g,m?'':' filter').trim();
|
||||||
|
newfilter && newfilter.matchCounts[!!m]++;
|
||||||
|
}
|
||||||
|
currfilter = newfilter;
|
||||||
|
updateLogCountDisplay();
|
||||||
|
}
|
||||||
|
var filter_pause = 0;
|
||||||
|
filter.oninput = (e) => {
|
||||||
|
if (filter_pause++) return;
|
||||||
|
filter.style['border-color'] = '';
|
||||||
|
({
|
||||||
|
wait() {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (filter_pause === 1)
|
||||||
|
return filter_pause=0,updateFilter(filter.value);
|
||||||
|
filter_pause = 1;
|
||||||
|
this.wait();
|
||||||
|
},250);
|
||||||
|
}
|
||||||
|
}).wait();
|
||||||
|
};
|
||||||
|
filter.onkeyup = (e) => {
|
||||||
|
// when enter/escape is pressed - lose focus
|
||||||
|
/^(escape|enter)$/i.test(e.key) && filter.blur();
|
||||||
|
}
|
||||||
|
window.addEventListener('keypress', function(e) {
|
||||||
|
if (e.ctrlKey && /[aA]/.test(e.key) && !selectall) {
|
||||||
|
selectall = 1;
|
||||||
|
selecttext(rows);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
window.addEventListener('keyup', function(e) {
|
||||||
|
selectall = 0;
|
||||||
|
/^escape$/i.test(e.key) && selecttext(null);
|
||||||
|
});
|
||||||
|
var connect = () => {
|
||||||
|
try {
|
||||||
|
setStatus('Connecting...');
|
||||||
|
var x = new WebSocket('ws://127.0.0.1:!{wssport}/!{logcatid}');
|
||||||
|
x.onopen = e => {
|
||||||
|
setStatus('');getId('clearlcbtn').disabled = false;ws = x;
|
||||||
|
};
|
||||||
|
x.onclose = e => {
|
||||||
|
ws = null;
|
||||||
|
getId('clearlcbtn').disabled = true;
|
||||||
|
};
|
||||||
|
x.onerror = e => { setStatus('Connection error') }
|
||||||
|
x.onmessage = e => {
|
||||||
|
if (!rows) return;
|
||||||
|
var rawlogs = e.data.trim();
|
||||||
|
if (/^:disconnect$/.test(rawlogs)) {
|
||||||
|
x.close(),setStatus('Device disconnected');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (/^:logcat_cleared$/.test(rawlogs)) {
|
||||||
|
rows.innerHTML = '';
|
||||||
|
rows.insertAdjacentHTML('afterbegin','<div>---- log cleared ----</div>');
|
||||||
|
logcount = 0;
|
||||||
|
if (currfilter) currfilter.matchCounts = {true:0,false:0};
|
||||||
|
updateLogCountDisplay();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (last_known_scroll_position > 0)
|
||||||
|
rawlogs = '<div class="hide">'+rawlogs+'</div>';
|
||||||
|
rows.insertAdjacentHTML('afterbegin',rawlogs);
|
||||||
|
var logs = rows.firstElementChild.getElementsByClassName('log');
|
||||||
|
logcount += logs.length;
|
||||||
|
// apply the filter to the newly insert elements
|
||||||
|
if (currfilter) {
|
||||||
|
for (var i=logs.length-1,m; i>=0; i--) {
|
||||||
|
m = currfilter.test(logs[i].textContent);
|
||||||
|
if (!m) logs[i].className += ' filter';
|
||||||
|
currfilter.matchCounts[!!m]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateLogCountDisplay();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch(e) { setStatus('Connection exception') }
|
||||||
|
}
|
||||||
|
!{connected} && connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("load", function(event) {
|
||||||
|
try { start(); } catch(e) {setStatus('start exception: '+e.message);}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user