From 8f2b4739280a2a68f8b9cbb6bab2a8f3b95aa8df Mon Sep 17 00:00:00 2001 From: gorhill Date: Thu, 7 May 2015 11:39:21 -0400 Subject: [PATCH] filtering in logger + various small fixes --- src/_locales/en/messages.json | 5 + src/css/common.css | 21 ++-- src/css/logger-ui.css | 20 ++-- src/css/popup.css | 5 - src/js/i18n.js | 10 ++ src/js/logger-ui.js | 196 +++++++++++++++++++++++++++------- src/js/popup.js | 2 + src/lib/publicsuffixlist.js | 20 ++-- src/logger-ui.html | 4 +- src/popup.html | 2 +- 10 files changed, 211 insertions(+), 74 deletions(-) diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index 053cba0..6e52992 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -583,6 +583,11 @@ "description": "Message asking user to confirm reset" }, + "loggerFilterInputPlaceholder" : { + "message": "filter expression(s)", + "description": "Appears in the input filed where filter expressions are entered" + }, + "mainBlockedPrompt1": { "message": "uMatrix has prevented the following page from loading:", "description": "English: uMatrix has prevented the following page from loading:" diff --git a/src/css/common.css b/src/css/common.css index c6bc18c..018a0d3 100644 --- a/src/css/common.css +++ b/src/css/common.css @@ -43,19 +43,19 @@ display: inline-block; } -html { +body[dir="ltr"] { direction: ltr; } -html.rtl { +body[dir="rtl"] { direction: rtl; } /* http://stackoverflow.com/questions/2011142/how-to-change-the-style-of-title-attribute-inside-the-anchor-tag?answertab=votes */ -*[data-tip] { +*[data-i18n-tip] { position: relative; cursor: pointer; } -*[data-tip]:hover:after { +*[data-i18n-tip]:hover:after { background-color: #fffffa; border: 1px solid gray; border-radius: 3px; @@ -63,7 +63,6 @@ html.rtl { color: black; content: attr(data-tip); font: 12px sans-serif; - left: -100%; line-height: 140%; min-width: 25vw; padding: 4px 6px; @@ -73,11 +72,11 @@ html.rtl { white-space: pre-line; z-index: 20; } -html.ltr .tip-anchor-left[data-tip]:hover:after, -html.rtl .tip-anchor-right[data-tip]:hover:after { - left: -5vw; +body[dir="ltr"] .tip-anchor-left[data-i18n-tip]:hover:after, +body[dir="rtl"] .tip-anchor-right[data-i18n-tip]:hover:after { + left: -3vw; } -html.ltr .tip-anchor-right[data-tip]:hover:after, -html.rtl .tip-anchor-left[data-tip]:hover:after { - right: -5vw; +body[dir="ltr"] .tip-anchor-right[data-i18n-tip]:hover:after, +body[dir="rtl"] .tip-anchor-left[data-i18n-tip]:hover:after { + right: -3vw; } diff --git a/src/css/logger-ui.css b/src/css/logger-ui.css index 2d75d84..91b5d28 100644 --- a/src/css/logger-ui.css +++ b/src/css/logger-ui.css @@ -45,10 +45,13 @@ body #compactViewToggler.button:before { body.compactView #compactViewToggler.button:before { content: '\f103'; } -body.filterOff #toolbar #filterButton { +#filterButton { opacity: 0.25; } -#filterExpression.bad { +body.f #filterButton { + opacity: 1; + } +#filterInput.bad { background-color: #fee; } #maxEntries { @@ -74,20 +77,23 @@ input:focus { width: 6em; } #content table > colgroup > col:nth-of-type(2) { - width: 3em; + width: 2.5em; } #content table > colgroup > col:nth-of-type(3) { - width: 3em; + width: 2.5em; } #content table > colgroup > col:nth-of-type(4) { width: 5em; } #content table > colgroup > col:nth-of-type(5) { - width: calc(100% - 20em); + width: calc(100% - 19em); } #content table tr { background-color: #fafafa; } +body.f table tr.f { + display: none; + } #content table tr:nth-of-type(2n+1) { background-color: #eee; } @@ -104,10 +110,6 @@ input:focus { text-align: center; } -body:not(.filterOff) #content table tr.hidden { - display: none; - } - body #content td { border: 1px solid #ccc; border-top: none; diff --git a/src/css/popup.css b/src/css/popup.css index 78c3c66..cba31d0 100644 --- a/src/css/popup.css +++ b/src/css/popup.css @@ -118,11 +118,6 @@ body[dir="rtl"] #mtxSwitches > li:before { font: 110% FontAwesome; padding-right: 0.5em; } -[data-i18n="matrixLoggerMenuEntry"]:before { - content: '\f022'; - font: 110% FontAwesome; - padding-right: 0.5em; - } [data-i18n="matrixDashboardMenuEntry"]:before { content: '\f085'; font: 110% FontAwesome; diff --git a/src/js/i18n.js b/src/js/i18n.js index a83a9f5..a5bbfae 100644 --- a/src/js/i18n.js +++ b/src/js/i18n.js @@ -52,6 +52,16 @@ while ( i-- ) { node.setAttribute('data-tip', vAPI.i18n(node.getAttribute('data-i18n-tip'))); } +nodeList = document.querySelectorAll('input[placeholder]'); +i = nodeList.length; +while ( i-- ) { + node = nodeList[i]; + node.setAttribute( + 'placeholder', + vAPI.i18n(node.getAttribute('placeholder')) || '' + ); +} + /******************************************************************************/ vAPI.i18n.renderElapsedTimeToString = function(tstamp) { diff --git a/src/js/logger-ui.js b/src/js/logger-ui.js index 2b1e63d..13ca2ae 100644 --- a/src/js/logger-ui.js +++ b/src/js/logger-ui.js @@ -17,8 +17,6 @@ along with this program. If not, see {http://www.gnu.org/licenses/}. Home: https://github.com/gorhill/sessbench - - TODO: cleanup/refactor */ /* jshint boss: true */ @@ -33,10 +31,7 @@ /******************************************************************************/ var messager = vAPI.messaging.channel('logger-ui.js'); - -var doc = document; -var body = doc.body; -var tbody = doc.querySelector('#content tbody'); +var tbody = document.querySelector('#content tbody'); var trJunkyard = []; var tdJunkyard = []; var firstVarDataCol = 2; // currently, column 2 (0-based index) @@ -116,7 +111,7 @@ var createCellAt = function(tr, index) { td.removeAttribute('colspan'); td.textContent = ''; } else { - td = doc.createElement('td'); + td = document.createElement('td'); } if ( mustAppend ) { tr.appendChild(td); @@ -131,7 +126,7 @@ var createRow = function(layout) { if ( tr ) { tr.className = ''; } else { - tr = doc.createElement('tr'); + tr = document.createElement('tr'); } for ( var index = 0; index < firstVarDataCol; index++ ) { createCellAt(tr, index); @@ -198,7 +193,7 @@ var renderLogEntry = function(entry) { } if ( entry.d3 ) { tr.classList.add('blocked'); - tr.cells[fvdc].textContent = '---'; + tr.cells[fvdc].textContent = '--'; } else { tr.cells[fvdc].textContent = ''; } @@ -229,6 +224,8 @@ var renderLogEntry = function(entry) { tr.classList.add('cat_' + entry.cat); } + rowFilterer.filterOne(tr); + tbody.insertBefore(tr, tbody.firstChild); }; @@ -268,15 +265,15 @@ var renderLogEntries = function(response) { // Chromium: // body.scrollTop = good value // body.parentNode.scrollTop = 0 - if ( body.scrollTop !== 0 ) { - body.scrollTop += yDelta; + if ( document.body.scrollTop !== 0 ) { + document.body.scrollTop += yDelta; return; } // Firefox: // body.scrollTop = 0 // body.parentNode.scrollTop = good value - var parentNode = body.parentNode; + var parentNode = document.body.parentNode; if ( parentNode && parentNode.scrollTop !== 0 ) { parentNode.scrollTop += yDelta; } @@ -288,6 +285,7 @@ var truncateLog = function(size) { if ( size === 0 ) { size = 5000; } + var tbody = document.querySelector('#content tbody'); size = Math.min(size, 10000); var tr; while ( tbody.childElementCount > size ) { @@ -356,7 +354,155 @@ var readLogBuffer = function() { /******************************************************************************/ +var onMaxEntriesChanged = function() { + var raw = uDom(this).val(); + try { + maxEntries = parseInt(raw, 10); + if ( isNaN(maxEntries) ) { + maxEntries = 0; + } + } catch (e) { + maxEntries = 0; + } + + messager.send({ + what: 'userSettings', + name: 'maxLoggedRequests', + value: maxEntries + }); + + truncateLog(maxEntries); +}; + +/******************************************************************************/ + +var rowFilterer = (function() { + var filters = []; + + var parseInput = function() { + filters = []; + + var rawPart, not, hardBeg, hardEnd, reStr; + var raw = uDom('#filterInput').val().trim(); + var rawParts = raw.split(/\s+/); + var i = rawParts.length; + while ( i-- ) { + rawPart = rawParts[i]; + not = rawPart.charAt(0) === '!'; + if ( not ) { + rawPart = rawPart.slice(1); + } + hardBeg = rawPart.charAt(0) === '['; + if ( hardBeg ) { + rawPart = rawPart.slice(1); + } + hardEnd = rawPart.slice(-1) === ']'; + if ( hardEnd ) { + rawPart = rawPart.slice(0, -1); + } + if ( rawPart === '' ) { + continue; + } + // https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions + reStr = rawPart.replace(/[.+?^${}()|[\]\\]/g, '\\$&') + .replace(/\*/g, '.*'); + if ( hardBeg ) { + reStr = '(?:^|\\s)' + reStr; + } + if ( hardEnd ) { + reStr += '(?:\\s|$)'; + } + filters.push({ + re: new RegExp(reStr, 'i'), + r: !not + }); + } + }; + + var filterOne = function(tr) { + var cl = tr.classList; + // do not filter out doc boundaries, they help separate important + // section of log. + if ( cl.contains('doc') ) { + return; + } + var ff = filters; + var fcount = ff.length; + if ( fcount === 0 ) { + cl.remove('f'); + return; + } + var cc = tr.cells; + var ccount = cc.length; + var hit, j, f; + // each filter expression must hit (implicit and-op) + // if... + // positive filter expression = there must one hit on any field + // negative filter expression = there must be no hit on all fields + for ( var i = 0; i < fcount; i++ ) { + f = ff[i]; + hit = !f.r; + for ( j = 0; j < ccount; j++ ) { + if ( f.re.test(cc[j].innerText) ) { + hit = f.r; + break; + } + } + if ( !hit ) { + cl.add('f'); + return; + } + } + cl.remove('f'); + }; + + var filterAll = function() { + // Special case: no filter + if ( filters.length === 0 ) { + uDom('#content tr').removeClass('f'); + return; + } + var tbody = document.querySelector('#content tbody'); + var rows = tbody.rows; + var i = rows.length; + while ( i-- ) { + filterOne(rows[i]); + } + }; + + var onFilterChangedAsync = (function() { + var timer = null; + var commit = function() { + timer = null; + parseInput(); + filterAll(); + }; + return function() { + if ( timer !== null ) { + clearTimeout(timer); + } + timer = setTimeout(commit, 750); + }; + })(); + + var onFilterButton = function() { + var cl = document.body.classList; + cl.toggle('f', cl.contains('f') === false); + }; + + uDom('#filterButton').on('click', onFilterButton); + uDom('#filterInput').on('input', onFilterChangedAsync); + + return { + filterOne: filterOne, + filterAll: filterAll + }; +})(); + +/******************************************************************************/ + var clearBuffer = function() { + var tbody = document.querySelector('#content tbody'); var tr; while ( tbody.firstChild !== null ) { tr = tbody.lastElementChild; @@ -380,9 +526,9 @@ var cleanBuffer = function() { /******************************************************************************/ var toggleCompactView = function() { - body.classList.toggle( + document.body.classList.toggle( 'compactView', - body.classList.contains('compactView') === false + document.body.classList.contains('compactView') === false ); }; @@ -595,28 +741,6 @@ var popupManager = (function() { /******************************************************************************/ -var onMaxEntriesChanged = function() { - var raw = uDom(this).val(); - try { - maxEntries = parseInt(raw, 10); - if ( isNaN(maxEntries) ) { - maxEntries = 0; - } - } catch (e) { - maxEntries = 0; - } - - messager.send({ - what: 'userSettings', - name: 'maxLoggedRequests', - value: maxEntries - }); - - truncateLog(maxEntries); -}; - -/******************************************************************************/ - uDom.onLoad(function() { readLogBuffer(); diff --git a/src/js/popup.js b/src/js/popup.js index f314e08..6f9bda8 100644 --- a/src/js/popup.js +++ b/src/js/popup.js @@ -1268,6 +1268,8 @@ var matrixSnapshotPoller = (function() { var matches = window.location.search.match(/(?:\?|&)tabId=([^&]+)/); if ( matches !== null ) { tabId = matches[1]; + // No need for logger button when embedded in logger + uDom('[data-extension-url="logger-ui.html"]').remove(); } } diff --git a/src/lib/publicsuffixlist.js b/src/lib/publicsuffixlist.js index a98fbf8..a823188 100644 --- a/src/lib/publicsuffixlist.js +++ b/src/lib/publicsuffixlist.js @@ -45,7 +45,7 @@ var selfieMagic = 'iscjsfsaolnm'; // < this.cutoffLength = indexOf() // >= this.cutoffLength = binary search var cutoffLength = 256; -var mustPunycode = /[^a-z0-9.-]/; +var mustPunycode = /[^\w.*-]/; var onChangedListeners = []; @@ -171,11 +171,6 @@ function parse(text, toAscii) { exceptions = {}; rules = {}; - // http://publicsuffix.org/list/: - // "... all rules must be canonicalized in the normal way - // for hostnames - lower-case, Punycode ..." - text = text.toLowerCase(); - var lineBeg = 0, lineEnd; var textEnd = text.length; var line, store, pos, tld; @@ -207,10 +202,6 @@ function parse(text, toAscii) { continue; } - if ( mustPunycode.test(line) ) { - line = toAscii(line); - } - // Is this an exception rule? if ( line.charAt(0) === '!' ) { store = exceptions; @@ -219,6 +210,15 @@ function parse(text, toAscii) { store = rules; } + if ( mustPunycode.test(line) ) { + line = toAscii(line); + } + + // http://publicsuffix.org/list/: + // "... all rules must be canonicalized in the normal way + // for hostnames - lower-case, Punycode ..." + line = line.toLowerCase(); + // Extract TLD pos = line.lastIndexOf('.'); if ( pos < 0 ) { diff --git a/src/logger-ui.html b/src/logger-ui.html index 8cb8831..07ce19a 100644 --- a/src/logger-ui.html +++ b/src/logger-ui.html @@ -6,13 +6,13 @@ uMatrix log - +
- +
diff --git a/src/popup.html b/src/popup.html index b8adf56..461392a 100644 --- a/src/popup.html +++ b/src/popup.html @@ -48,11 +48,11 @@
+