aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorgorhill <rhill@raymondhill.net>2015-05-16 10:15:02 -0400
committergorhill <rhill@raymondhill.net>2015-05-16 10:15:02 -0400
commite0284b89086caa3bc851e59fc14455e33e503ff2 (patch)
tree26bdb4795463f68da989e5e4d0c88c7e51a95f2d /src
parent20f5794b3788f3fe9146009402c8054969155691 (diff)
downloaduBlock-e0284b89086caa3bc851e59fc14455e33e503ff2.zip
uBlock-e0284b89086caa3bc851e59fc14455e33e503ff2.tar.gz
uBlock-e0284b89086caa3bc851e59fc14455e33e503ff2.tar.bz2
this fixes #193
Diffstat (limited to 'src')
-rw-r--r--src/_locales/en/messages.json4
-rw-r--r--src/css/logger-ui.css21
-rw-r--r--src/js/logger-ui.js171
-rw-r--r--src/js/messaging.js12
-rw-r--r--src/js/pagestore.js6
-rw-r--r--src/js/tab.js64
-rw-r--r--src/logger-ui.html23
7 files changed, 256 insertions, 45 deletions
diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json
index a849599..c4fb03f 100644
--- a/src/_locales/en/messages.json
+++ b/src/_locales/en/messages.json
@@ -403,6 +403,10 @@
"message":"No non-blocked requests logged for this page",
"description":"English: No non-blocked requests logged for this page"
},
+ "logAll":{
+ "message":"All",
+ "description":"Appears in the logger's tab selector"
+ },
"logBehindTheScene":{
"message":"Behind the scene",
"description":"Pretty name for behind-the-scene network requests"
diff --git a/src/css/logger-ui.css b/src/css/logger-ui.css
index 13de2dc..00b8f9b 100644
--- a/src/css/logger-ui.css
+++ b/src/css/logger-ui.css
@@ -7,7 +7,6 @@ body {
margin: 0;
overflow-x: hidden;
padding: 0;
- white-space: nowrap;
width: 100%;
}
#toolbar {
@@ -16,7 +15,7 @@ body {
box-sizing: border-box;
left: 0;
margin: 0;
- padding: 0 1em;
+ padding: 0.5em 1em;
position: fixed;
top: 0;
width: 100%;
@@ -28,7 +27,7 @@ body {
box-sizing: border-box;
cursor: pointer;
display: inline-block;
- font-size: 20px;
+ font-size: 150%;
margin: 0;
padding: 8px;
}
@@ -39,6 +38,19 @@ body {
#toolbar .button:hover {
background-color: #eee;
}
+#toolbar > div {
+ white-space: nowrap;
+ }
+#toolbar > div:first-of-type {
+ font-size: 120%;
+ }
+#toolbar > div > * {
+ vertical-align: middle;
+ }
+#pageSelector {
+ width: 28em;
+ padding: 0.2em 0;
+ }
body #compactViewToggler.button:before {
content: '\f102';
}
@@ -55,14 +67,13 @@ body.f #filterButton {
background-color: #fee;
}
#maxEntries {
- margin-left: 3em;
+ margin: 0 2em;
}
input:focus {
background-color: #ffe;
}
#content {
font: 13px sans-serif;
- margin-top: 3.5em;
width: 100%;
}
diff --git a/src/js/logger-ui.js b/src/js/logger-ui.js
index 84e6c50..2690762 100644
--- a/src/js/logger-ui.js
+++ b/src/js/logger-ui.js
@@ -30,6 +30,15 @@
/******************************************************************************/
+// Adjust top padding of content table, to match that of toolbar height.
+
+document.getElementById('content').style.setProperty(
+ 'margin-top',
+ document.getElementById('toolbar').offsetHeight + 'px'
+);
+
+/******************************************************************************/
+
var messager = vAPI.messaging.channel('logger-ui.js');
var tbody = document.querySelector('#content tbody');
var trJunkyard = [];
@@ -40,6 +49,8 @@ var maxEntries = 5000;
var noTabId = '';
var allTabIds = {};
+var hiddenTemplate = document.querySelector('#hiddenTemplate > span');
+
var prettyRequestTypes = {
'main_frame': 'doc',
'stylesheet': 'css',
@@ -61,6 +72,18 @@ var dateOptions = {
/******************************************************************************/
+var classNameFromTabId = function(tabId) {
+ if ( tabId === noTabId ) {
+ return 'tab_bts';
+ }
+ if ( tabId !== '' ) {
+ return 'tab_' + tabId;
+ }
+ return '';
+};
+
+/******************************************************************************/
+
// Emphasize hostname in URL, as this is what matters in uMatrix's rules.
var nodeFromURL = function(url, filter) {
@@ -165,6 +188,14 @@ var createRow = function(layout) {
/******************************************************************************/
+var createHiddenTextNode = function(text) {
+ var node = hiddenTemplate.cloneNode(true);
+ node.textContent = text;
+ return node;
+};
+
+/******************************************************************************/
+
var createGap = function(tabId, url) {
var tr = createRow('1');
tr.classList.add('tab');
@@ -246,11 +277,9 @@ var renderLogEntry = function(entry) {
tr.cells[0].title = time.toLocaleDateString('fullwide', dateOptions);
if ( entry.tab ) {
- tr.classList.add('tab');
+ tr.classList.add('tab', classNameFromTabId(entry.tab));
if ( entry.tab === noTabId ) {
- tr.classList.add('tab_bts');
- } else if ( entry.tab !== '' ) {
- tr.classList.add('tab_' + entry.tab);
+ tr.cells[1].appendChild(createHiddenTextNode('bts'));
}
}
if ( entry.cat !== '' ) {
@@ -316,6 +345,78 @@ var renderLogEntries = function(response) {
/******************************************************************************/
+var synchronizeTabIds = function(newTabIds) {
+ var oldTabIds = allTabIds;
+
+ // Neuter rows for which a tab does not exist anymore
+ // TODO: sort to avoid using indexOf
+
+ var autoDeleteVoidRows = !!vAPI.localStorage.getItem('loggerAutoDeleteVoidRows');
+ var rowVoided = false;
+ var trs;
+ for ( var tabId in oldTabIds ) {
+ if ( oldTabIds.hasOwnProperty(tabId) === false ) {
+ continue;
+ }
+ if ( newTabIds.hasOwnProperty(tabId) ) {
+ continue;
+ }
+ // Mark or remove voided rows
+ trs = uDom('.tab_' + tabId);
+ if ( autoDeleteVoidRows ) {
+ toJunkyard(trs);
+ } else {
+ trs.removeClass('canMtx');
+ rowVoided = true;
+ }
+ // Remove popup if it is currently bound to a removed tab.
+ if ( tabId === popupManager.tabId ) {
+ popupManager.toggleOff();
+ }
+ }
+
+ var select = document.getElementById('pageSelector');
+ var selectValue = select.value;
+ var tabIds = Object.keys(newTabIds).sort(function(a, b) {
+ return newTabIds[a].localeCompare(newTabIds[b]);
+ });
+ var option;
+ for ( var i = 0, j = 2; i < tabIds.length; i++ ) {
+ tabId = tabIds[i];
+ if ( tabId === noTabId ) {
+ continue;
+ }
+ option = select.options[j];
+ j += 1;
+ if ( !option ) {
+ option = document.createElement('option');
+ select.appendChild(option);
+ }
+ option.textContent = newTabIds[tabId];
+ option.value = classNameFromTabId(tabId);
+ if ( option.value === selectValue ) {
+ option.setAttribute('selected', '');
+ } else {
+ option.removeAttribute('selected');
+ }
+ }
+ while ( j < select.options.length ) {
+ select.removeChild(select.options[j]);
+ }
+ if ( select.value !== selectValue ) {
+ select.selectedIndex = 0;
+ select.value = '';
+ select.options[0].setAttribute('selected', '');
+ pageSelectorChanged();
+ }
+
+ allTabIds = newTabIds;
+
+ return rowVoided;
+};
+
+/******************************************************************************/
+
var truncateLog = function(size) {
if ( size === 0 ) {
size = 5000;
@@ -343,28 +444,7 @@ var onLogBufferRead = function(response) {
// Neuter rows for which a tab does not exist anymore
// TODO: sort to avoid using indexOf
- var autoDeleteVoidRows = vAPI.localStorage.getItem('loggerAutoDeleteVoidRows');
- var rowVoided = false, trs;
- for ( var tabId in allTabIds ) {
- if ( allTabIds.hasOwnProperty(tabId) === false ) {
- continue;
- }
- if ( response.tabIds.hasOwnProperty(tabId) ) {
- continue;
- }
- trs = uDom('.tab_' + tabId);
- if ( autoDeleteVoidRows ) {
- toJunkyard(trs);
- } else {
- trs.removeClass('canMtx');
- rowVoided = true;
- }
- if ( tabId === popupManager.tabId ) {
- popupManager.toggleOff();
- }
- }
- allTabIds = response.tabIds;
-
+ var rowVoided = synchronizeTabIds(response.tabIds);
renderLogEntries(response);
if ( rowVoided ) {
@@ -395,6 +475,41 @@ var readLogBuffer = function() {
/******************************************************************************/
+var pageSelectorChanged = function() {
+ var style = document.getElementById('tabFilterer');
+ var tabClass = document.getElementById('pageSelector').value;
+ var sheet = style.sheet;
+ while ( sheet.cssRules.length !== 0 ) {
+ sheet.deleteRule(0);
+ }
+ if ( tabClass !== '' ) {
+ sheet.insertRule(
+ '#content table tr:not(.' + tabClass + ') { display: none; }',
+ 0
+ );
+ }
+ uDom('#refresh').toggleClass(
+ 'disabled',
+ tabClass === '' || tabClass === 'tab_bts'
+ );
+};
+
+/******************************************************************************/
+
+var reloadTab = function() {
+ var tabClass = document.getElementById('pageSelector').value;
+ var matches = tabClass.match(/^tab_(.+)$/);
+ if ( matches === null ) {
+ return;
+ }
+ if ( matches[1] === 'bts' ) {
+ return;
+ }
+ messager.send({ what: 'reloadTab', tabId: matches[1] });
+};
+
+/******************************************************************************/
+
var onMaxEntriesChanged = function() {
var raw = uDom(this).val();
try {
@@ -649,7 +764,7 @@ var popupManager = (function() {
popupObserver = new MutationObserver(resizePopup);
container.appendChild(popup);
- style = document.querySelector('#content > style');
+ style = document.getElementById('popupFilterer');
style.textContent = styleTemplate.replace('{{tabId}}', localTabId);
document.body.classList.add('popupOn');
@@ -701,6 +816,8 @@ var popupManager = (function() {
uDom.onLoad(function() {
readLogBuffer();
+ uDom('#pageSelector').on('change', pageSelectorChanged);
+ uDom('#refresh').on('click', reloadTab);
uDom('#compactViewToggler').on('click', toggleCompactView);
uDom('#clean').on('click', cleanBuffer);
uDom('#clear').on('click', clearBuffer);
diff --git a/src/js/messaging.js b/src/js/messaging.js
index c5d0fc1..8749809 100644
--- a/src/js/messaging.js
+++ b/src/js/messaging.js
@@ -1193,11 +1193,17 @@ var onMessage = function(request, sender, callback) {
switch ( request.what ) {
case 'readAll':
- var tabIds = {};
+ var tabIds = {}, pageStore;
+ var loggerURL = vAPI.getURL('logger-ui.html');
for ( var tabId in µb.pageStores ) {
- if ( µb.pageStores.hasOwnProperty(tabId) ) {
- tabIds[tabId] = true;
+ pageStore = µb.pageStoreFromTabId(tabId);
+ if ( pageStore === null ) {
+ continue;
}
+ if ( pageStore.rawURL.lastIndexOf(loggerURL, 0) === 0 ) {
+ continue;
+ }
+ tabIds[tabId] = pageStore.title;
}
response = {
colorBlind: µb.userSettings.colorBlindFriendly,
diff --git a/src/js/pagestore.js b/src/js/pagestore.js
index 5a7d64b..a2378e3 100644
--- a/src/js/pagestore.js
+++ b/src/js/pagestore.js
@@ -295,6 +295,8 @@ PageStore.prototype.init = function(tabId) {
var tabContext = µb.tabContextManager.lookup(tabId);
this.tabId = tabId;
this.tabHostname = tabContext.rootHostname;
+ this.title = tabContext.rawURL;
+ this.rawURL = tabContext.rawURL;
this.hostnameToCountMap = {};
this.contentLastModified = 0;
this.frames = {};
@@ -334,6 +336,7 @@ PageStore.prototype.reuse = function(context) {
if ( context === 'tabUpdated' ) {
// As part of https://github.com/chrisaljoudi/uBlock/issues/405
// URL changed, force a re-evaluation of filtering switch
+ this.rawURL = tabContext.rawURL;
this.netFilteringReadTime = 0;
return this;
}
@@ -354,6 +357,9 @@ PageStore.prototype.dispose = function() {
// need to release the memory taken by these, which can amount to
// sizeable enough chunks (especially requests, through the request URL
// used as a key).
+ this.tabHostname = '';
+ this.title = '';
+ this.rawURL = '';
this.hostnameToCountMap = null;
this.disposeFrameStores();
this.netFilteringCache = this.netFilteringCache.dispose();
diff --git a/src/js/tab.js b/src/js/tab.js
index 010cfae..c07ac05 100644
--- a/src/js/tab.js
+++ b/src/js/tab.js
@@ -510,9 +510,7 @@ vAPI.tabs.registerListeners();
// Create an entry for the tab if it doesn't exist.
µb.bindTabToPageStats = function(tabId, context) {
- if ( vAPI.isBehindTheSceneTabId(tabId) === false ) {
- this.updateBadgeAsync(tabId);
- }
+ this.updateBadgeAsync(tabId);
// Do not create a page store for URLs which are of no interests
if ( µb.tabContextManager.exists(tabId) === false ) {
@@ -540,6 +538,8 @@ vAPI.tabs.registerListeners();
return pageStore;
}
+ this.updateTitle(tabId);
+
// Rebind according to context. We rebind even if the URL did not change,
// as maybe the tab was force-reloaded, in which case the page stats must
// be all reset.
@@ -570,8 +570,65 @@ vAPI.tabs.registerListeners();
// Permanent page store for behind-the-scene requests. Must never be removed.
µb.pageStores[vAPI.noTabId] = µb.PageStore.factory(vAPI.noTabId);
+µb.pageStores[vAPI.noTabId].title = vAPI.i18n('logBehindTheScene');
/******************************************************************************/
+
+µb.updateTitle = (function() {
+ var tabIdToTimer = Object.create(null);
+ var tabIdToTryCount = Object.create(null);
+ var delay = 499;
+
+ var tryNoMore = function(tabId) {
+ delete tabIdToTryCount[tabId];
+ };
+
+ var tryAgain = function(tabId) {
+ var count = tabIdToTryCount[tabId];
+ if ( count === undefined ) {
+ return false;
+ }
+ if ( count === 1 ) {
+ delete tabIdToTryCount[tabId];
+ return false;
+ }
+ tabIdToTryCount[tabId] = count - 1;
+ tabIdToTimer[tabId] = setTimeout(updateTitle.bind(µb, tabId), delay);
+ return true;
+ };
+
+ var onTabReady = function(tabId, tab) {
+ if ( !tab ) {
+ return tryNoMore(tabId);
+ }
+ var pageStore = this.pageStoreFromTabId(tabId);
+ if ( pageStore === null ) {
+ return tryNoMore(tabId);
+ }
+ if ( !tab.title && tryAgain(tabId) ) {
+ return;
+ }
+ tryNoMore(tabId);
+ pageStore.title = tab.title || tab.url || '';
+ };
+
+ var updateTitle = function(tabId) {
+ delete tabIdToTimer[tabId];
+ vAPI.tabs.get(tabId, onTabReady.bind(this, tabId));
+ };
+
+ return function(tabId) {
+ if ( vAPI.isBehindTheSceneTabId(tabId) ) {
+ return;
+ }
+ if ( tabIdToTimer[tabId] ) {
+ clearTimeout(tabIdToTimer[tabId]);
+ }
+ tabIdToTimer[tabId] = setTimeout(updateTitle.bind(this, tabId), delay);
+ tabIdToTryCount[tabId] = 5;
+ };
+})();
+
/******************************************************************************/
// Stale page store entries janitor
@@ -613,7 +670,6 @@ var pageStoreJanitor = function() {
setTimeout(pageStoreJanitor, pageStoreJanitorPeriod);
/******************************************************************************/
-/******************************************************************************/
})();
diff --git a/src/logger-ui.html b/src/logger-ui.html
index 2e59050..8ac913c 100644
--- a/src/logger-ui.html
+++ b/src/logger-ui.html
@@ -9,15 +9,25 @@
<body class="compactView f">
<div id="toolbar">
- <span id="compactViewToggler" class="button fa"></span>
- <span id="clean" class="button fa disabled">&#xf00d;</span>
- <span id="clear" class="button fa disabled">&#xf12d;</span>
- <span id="filterButton" class="button fa">&#xf0b0;</span><input id="filterInput" type="text" placeholder="logFilterPrompt">
- <input id="maxEntries" type="text" size="5" title="logMaxEntriesTip">
+ <div>
+ <select id="pageSelector">
+ <option value="" data-i18n="logAll">
+ <option value="tab_bts" data-i18n="logBehindTheScene">
+ </select>
+ <span id="refresh" class="button disabled fa">&#xf021;</span>
+ </div>
+ <div>
+ <span id="compactViewToggler" class="button fa"></span>
+ <span id="clean" class="button fa disabled">&#xf00d;</span>
+ <span id="clear" class="button fa disabled">&#xf12d;</span>
+ <span id="filterButton" class="button fa">&#xf0b0;</span><input id="filterInput" type="text" placeholder="logFilterPrompt">
+ <input id="maxEntries" type="text" size="5" title="logMaxEntriesTip">
+ </div>
</div>
<div id="content">
- <style></style>
+ <style id="tabFilterer"></style>
+ <style id="popupFilterer"></style>
<table>
<colgroup><col><col><col><col><col></colgroup>
<tbody></tbody>
@@ -30,6 +40,7 @@
<div style="display: none;">
<div id="renderedURLTemplate"><span><span></span><b></b><span></span></span></div>
+ <div id="hiddenTemplate"><span style="display:none;"></span></div>
</div>
<script src="js/vapi-common.js"></script>