Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: lib/devtools.js

Issue 6393086494113792: Issue 154 - Added devtools panel showing blocked and blockable items (Closed)
Patch Set: Rebased and fixed documentation mistakenly indicating arguments as optional Created Feb. 28, 2015, 5:52 p.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « include.preload.js ('k') | metadata.chrome » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/devtools.js
===================================================================
new file mode 100644
--- /dev/null
+++ b/lib/devtools.js
@@ -0,0 +1,267 @@
+/*
+ * This file is part of Adblock Plus <https://adblockplus.org/>,
+ * Copyright (C) 2006-2015 Eyeo GmbH
+ *
+ * Adblock Plus is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * Adblock Plus is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+let info = require("info");
+if (info.platform == "chromium")
+{
+ let {WhitelistFilter, ElemHideFilter} = require("filterClasses");
+ let {SpecialSubscription} = require("subscriptionClasses");
+ let {FilterStorage} = require("filterStorage");
+ let {defaultMatcher} = require("matcher");
+ let {FilterNotifier} = require("filterNotifier");
+ let {stringifyURL, isThirdParty} = require("url");
+
+ // Mapping of inspected tabs to their devpanel page
+ // and recorded items. We can't use a PageMap here,
+ // because data must persist after navigation/reload.
+ let panels = Object.create(null);
+
+ function getRequestInfo(request)
+ {
+ return {
+ url: request.url && stringifyURL(request.url),
+ type: request.type,
+ docDomain: request.docDomain
+ };
+ }
+
+ function getFilterInfo(filter)
+ {
+ if (!filter)
+ return null;
+
+ let userDefined = false;
+ let subscriptionTitle = null;
+
+ for (let subscription of filter.subscriptions)
+ {
+ if (!subscription.disabled)
+ {
+ if (subscription instanceof SpecialSubscription)
+ userDefined = true;
+ else
+ subscriptionTitle = subscription.title;
+ }
+ }
+
+ return {
+ text: filter.text,
+ whitelisted: filter instanceof WhitelistFilter,
+ userDefined: userDefined,
+ subscription: subscriptionTitle
+ };
+ }
+
+ function addRecord(panel, request, filter)
+ {
+ panel.page.sendMessage({
+ type: "add-record",
+ request: getRequestInfo(request),
+ filter: getFilterInfo(filter)
+ });
+
+ panel.records.push({
+ request: request,
+ filter: filter
+ });
+ }
+
+ function matchRequest(request)
+ {
+ return defaultMatcher.matchesAny(
+ stringifyURL(request.url),
+ request.type,
+ request.docDomain,
+ isThirdParty(request.url, request.docDomain),
+ request.sitekey
+ );
+ }
+
+ /**
+ * Logs a request in the devtools panel.
+ *
+ * @param {Page} page The page the request occured on
+ * @param {URL] url The URL of the request
+ * @param {string} type The request type
+ * @param {string} docDomain The IDN-decoded hostname of the document
+ * @param {string} [sitekey] The active sitekey if there is any
+ * @param {filter} [filter] The matched filter or null if there is no match
+ */
+ function logRequest(page, url, type, docDomain, sitekey, filter)
+ {
+ let panel = panels[page._id];
+ if (panel)
+ {
+ let request = {
+ url: url,
+ type: type,
+ docDomain: docDomain,
+ sitekey: sitekey
+ };
+
+ addRecord(panel, request, filter);
+ }
+ }
+ exports.logRequest = logRequest;
+
+ /**
+ * Logs active element hiding filters in the devtools panel.
+ *
+ * @param {Page} page The page the elements were hidden on
+ * @param {string[]} selectors The CSS selectors of active elemhide filters
+ * @param {string} docDomain The IDN-decoded hostname of the document
+ */
+ function logHiddenElements(page, selectors, docDomain)
+ {
+ let panel = panels[page._id];
+ if (panel)
+ {
+ for (let subscription of FilterStorage.subscriptions)
+ {
+ if (subscription.disabled)
+ continue;
+
+ for (let filter of subscription.filters)
+ {
+ if (!(filter instanceof ElemHideFilter))
+ continue;
+ if (selectors.indexOf(filter.selector) == -1)
+ continue;
+ if (!filter.isActiveOnDomain(docDomain))
+ continue;
+ if (panel.records.some(record => record.request.type == "ELEMHIDE" &&
+ record.request.docDomain == docDomain &&
+ record.filter.selector == filter.selector))
+ continue;
+
+ addRecord(panel, {type: "ELEMHIDE", docDomain: docDomain}, filter);
+ }
+ }
+ }
+ };
+ exports.logHiddenElements = logHiddenElements;
+
+ /**
+ * Starts to record items and shows them in the devtools panel.
+ *
+ * @param {Page} panelPage The page of the the devtools panel
+ * @param {number} inpectedTabId The ID of the tab to record item from
+ */
+ function initDevToolsPanel(panelPage, inpectedTabId)
+ {
+ panels[inpectedTabId] = {page: panelPage, records: []};
+
+ // Forget about this devtools panel and the items recorded there
+ // so far, when the panel (not the tab it is inspecting) is closed.
+ function onRemoved(tabId)
+ {
+ if (tabId == panelPage._id)
+ {
+ delete panels[inpectedTabId];
+ chrome.tabs.onRemoved.removeListener(onRemoved);
+ }
+ }
+ chrome.tabs.onRemoved.addListener(onRemoved);
+ }
+ exports.initDevToolsPanel = initDevToolsPanel;
+
+ /**
+ * Checks whether a page is inspected by the devtools panel.
+ *
+ * @param {Page} page
+ * @return {Boolean}
+ */
+ function hasDevToolsPanel(page)
+ {
+ return page._id in panels;
+ }
+ exports.hasDevToolsPanel = hasDevToolsPanel;
+
+ chrome.webNavigation.onBeforeNavigate.addListener(function(details)
+ {
+ let panel = panels[details.tabId];
+ if (panel && details.frameId == 0)
+ {
+ // We have to flush the in-memory cache on page load.
+ // Otherwise requests answered from the in-memory cache
+ // will not be shown in the devtools panel.
+ chrome.webRequest.handlerBehaviorChanged();
+
+ panel.records = [];
+ panel.page.sendMessage({type: "reset"});
+ }
+ });
+
+ FilterNotifier.addListener(function(action, filter)
+ {
+ if (action != "filter.added" && action != "filter.removed")
+ return;
+
+ for (let tabId in panels)
+ {
+ let panel = panels[tabId];
+
+ for (let i = 0; i < panel.records.length; i++)
+ {
+ let record = panel.records[i];
+
+ if (action == "filter.added")
+ {
+ if (record.request.type == "ELEMHIDE")
+ continue;
+
+ if (matchRequest(record.request) != filter)
+ continue;
+
+ record.filter = filter;
+ }
+
+ if (action == "filter.removed")
+ {
+ if (record.filter != filter)
+ continue;
+
+ if (record.request.type == "ELEMHIDE")
+ {
+ panel.page.sendMessage({
+ type: "remove-record",
+ index: i
+ });
+ panel.records.splice(i--, 1);
+ continue;
+ }
+
+ record.filter = matchRequest(record.request);
+ }
+
+ panel.page.sendMessage({
+ type: "update-record",
+ index: i,
+ request: getRequestInfo(record.request),
+ filter: getFilterInfo(record.filter)
+ });
+ }
+ }
+ });
+}
+else
+{
+ exports.logRequest = () => {};
+ exports.logHiddenElements = () => {};
+ exports.initDevToolsPanel = () => {};
+ exports.hasDevToolsPanel = () => false;
+}
« no previous file with comments | « include.preload.js ('k') | metadata.chrome » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld