diff --git a/src/css/devtools.css b/src/css/devtools.css
index c82e1f4a1..cc3d06149 100644
--- a/src/css/devtools.css
+++ b/src/css/devtools.css
@@ -3,6 +3,12 @@ body {
overflow-y: hidden;
padding: 0;
}
+button {
+ opacity: 0.25;
+ }
+button:hover {
+ opacity: 0.75;
+ }
#toolbar {
background-color: #eee;
border: none;
@@ -28,7 +34,7 @@ body {
vertical-align: middle;
}
#pageSelector {
- max-width: 80%;
+ max-width: 70%;
}
#toolbar #refresh {
margin-left: 4px;
@@ -42,14 +48,56 @@ select {
select option {
max-width: 40em;
}
-#popupToggler {
- opacity: 0.25;
+#extras {
+ background-color: transparent;
+ border: 0;
+ margin: 0;
+ padding: 0;
position: absolute;
right: 0;
}
-body.popupEnabled #popupToggler {
+#extras > span {
+ border: 0;
+ margin: 0;
+ padding: 0;
+ position: relative;
+ }
+#extras > span > button {
+ margin-left: 0.2em;
+ }
+#extras > span > div {
+ background-color: white;
+ border: 0;
+ display: none;
+ position: absolute;
+ right: 2px;
+ }
+#extras > span > div > * {
+ border: 1px solid gray;
+ }
+#extras > span > button.enabled {
opacity: 1;
}
+#extras > span > button.enabled + div {
+ display: block;
+ }
+#filterMatcher {
+ border: 0;
+ padding: 0.5em;
+ margin: 0;
+ }
+#filteringResult {
+ background-color: #eee;
+ font-family: monospace;
+ }
+#filteringResult.empty {
+ background-color: transparent;
+ }
+#popup {
+ border: 0;
+ padding: 0;
+ margin: 0;
+ }
#content {
border: 0;
box-sizing: border-box;
@@ -60,13 +108,3 @@ body.popupEnabled #popupToggler {
padding: 0;
width: 100%;
}
-#popup {
- border: 1px solid gray;
- display: none;
- position: fixed;
- right: 2px;
- top: calc(4em + 2px);
- }
-body.popupEnabled #popup[src^="popup.html"] {
- display: initial;
- }
diff --git a/src/devtools.html b/src/devtools.html
index 9f4832c0c..aebbff197 100644
--- a/src/devtools.html
+++ b/src/devtools.html
@@ -14,10 +14,31 @@
-
+
-
diff --git a/src/js/devtools.js b/src/js/devtools.js
index 17a783a55..2e14efe0d 100644
--- a/src/js/devtools.js
+++ b/src/js/devtools.js
@@ -94,18 +94,65 @@ var selectPage = function() {
/******************************************************************************/
-var togglePopup = function() {
- var tabId = uDom('#pageSelector').val() || '';
- var body = uDom('body');
- body.toggleClass('popupEnabled');
- if ( body.hasClass('popupEnabled') === false ) {
- tabId = '';
+var toggleTool = function() {
+ var button = uDom(this);
+ button.toggleClass('enabled', !button.hasClass('enabled'));
+
+ // Special case: we want the frame of the popup to be filled-in if and
+ // only if the popup is visible.
+ if ( this.id === 'popupToggler' ) {
+ var tabId = uDom('#pageSelector').val() || '';
+ var body = uDom('body');
+ body.toggleClass('popupEnabled');
+ if ( body.hasClass('popupEnabled') === false ) {
+ tabId = '';
+ }
+ uDom('#popup').attr(
+ 'src',
+ button.hasClass('enabled') && tabId ? 'popup.html?tabId=' + tabId : ''
+ );
}
- uDom('#popup').attr('src', tabId ? 'popup.html?tabId=' + tabId : '');
};
/******************************************************************************/
+var evaluateStaticFiltering = (function() {
+ var onResultReceived = function(response) {
+ var result = response && response.result.slice(3);
+ uDom('#filteringResult')
+ .text(result || '\u00A0')
+ .toggleClass('empty', result === '');
+
+ var input = uDom('#filterMatcher input').at(0);
+ if ( input.val().trim() === '' ) {
+ input.val(response && response.contextURL || '');
+ }
+ };
+
+ var timer = null;
+ var onTimerElapsed = function() {
+ timer = null;
+
+ var inputs = uDom('#filterMatcher input');
+
+ messager.send({
+ what: 'evaluateStaticFiltering',
+ tabId: uDom('#pageSelector').val() || '',
+ contextURL: inputs.at(0).val().trim(),
+ requestURL: inputs.at(1).val().trim(),
+ requestType: inputs.at(2).val().trim(),
+ }, onResultReceived);
+ };
+
+ return function() {
+ if ( timer === null ) {
+ setTimeout(onTimerElapsed, 750);
+ }
+ };
+})();
+
+/******************************************************************************/
+
var resizePopup = function() {
var popup = document.getElementById('popup');
popup.style.width = popup.contentWindow.document.body.clientWidth + 'px';
@@ -160,13 +207,14 @@ uDom.onLoad(function() {
tabId = matches[1];
}
- uDom('#popupToggler').on('click', togglePopup);
+ uDom('.toolToggler').on('click', toggleTool);
uDom('#popup').on('load', onPopupLoaded);
renderPageSelector(tabId);
uDom('#pageSelector').on('change', pageSelectorChanged);
- uDom('#refresh').on('click', function() { renderPageSelector(); } );
+ uDom('#refresh').on('click', function() { renderPageSelector(); });
+ uDom('#filterMatcher input').on('input', evaluateStaticFiltering);
});
/******************************************************************************/
diff --git a/src/js/messaging.js b/src/js/messaging.js
index 37ce13e0a..44b1a271f 100644
--- a/src/js/messaging.js
+++ b/src/js/messaging.js
@@ -1067,23 +1067,58 @@ var getPageDetails = function(callback) {
/******************************************************************************/
+var evaluateStaticFiltering = function(details) {
+ // URL of context not provided, try to use the one for the given tab id.
+ var contextURL = details.contextURL;
+ if ( contextURL === '' ) {
+ var tabContext = µb.tabContextManager.lookup(details.tabId || 0);
+ if ( tabContext ) {
+ contextURL = tabContext.rawURL;
+ }
+ }
+
+ var pageHostname = µb.URI.hostnameFromURI(contextURL);
+ var pageDomain = µb.URI.domainFromHostname(pageHostname);
+
+ var context = {
+ rootHostname: pageHostname,
+ rootDomain: pageDomain,
+ pageHostname: pageHostname,
+ pageDomain: pageDomain,
+ requestURL: details.requestURL,
+ requestHostname: µb.URI.hostnameFromURI(details.requestURL),
+ requestType: details.requestType
+ };
+
+ return {
+ contextURL: contextURL,
+ result: µb.staticNetFilteringEngine.matchString(context)
+ };
+};
+
+/******************************************************************************/
+
var onMessage = function(request, sender, callback) {
// Async
switch ( request.what ) {
- case 'getPageDetails':
- getPageDetails(callback);
- return;
+ case 'getPageDetails':
+ getPageDetails(callback);
+ return;
- default:
- break;
+ default:
+ break;
}
// Sync
var response;
switch ( request.what ) {
- default:
- return vAPI.messaging.UNHANDLED;
+ case 'evaluateStaticFiltering':
+ response = evaluateStaticFiltering(request);
+ break;
+
+ default:
+ return vAPI.messaging.UNHANDLED;
}
callback(response);