1
0
Fork 0
mirror of https://github.com/gorhill/uMatrix.git synced 2024-06-02 02:14:52 +12:00
uMatrix/src/js/popup.js

1360 lines
43 KiB
JavaScript
Raw Normal View History

2014-10-18 08:01:09 +13:00
/*******************************************************************************
µMatrix - a Chromium browser extension to black/white list requests.
Copyright (C) 2014 Raymond Hill
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 this program. If not, see {http://www.gnu.org/licenses/}.
Home: https://github.com/gorhill/uMatrix
*/
2015-04-12 09:15:57 +12:00
/* global punycode, vAPI, uDom */
2014-10-20 17:53:13 +13:00
/* jshint esnext: true, bitwise: false */
2014-10-18 08:01:09 +13:00
/******************************************************************************/
/******************************************************************************/
(function() {
2015-04-12 09:15:57 +12:00
'use strict';
2014-10-18 08:01:09 +13:00
/******************************************************************************/
/******************************************************************************/
2014-10-20 17:53:13 +13:00
// Must be consistent with definitions in matrix.js
2015-05-13 11:50:48 +12:00
var Pale = 0x00;
var Dark = 0x80;
var Transparent = 0;
var Red = 1;
var Green = 2;
var Gray = 3;
var DarkRed = Dark | Red;
var PaleRed = Pale | Red;
var DarkGreen = Dark | Green;
var PaleGreen = Pale | Green;
var DarkGray = Dark | Gray;
var PaleGray = Pale | Gray;
2014-10-18 08:01:09 +13:00
var matrixSnapshot = {};
var groupsSnapshot = [];
var allHostnamesSnapshot = 'do not leave this initial string empty';
var matrixCellHotspots = null;
var matrixHeaderPrettyNames = {
'all': '',
'cookie': '',
'css': '',
'image': '',
'plugin': '',
'script': '',
'xhr': '',
'frame': '',
'other': ''
};
2014-11-04 08:27:59 +13:00
var firstPartyLabel = '';
var blacklistedHostnamesLabel = '';
var messager = vAPI.messaging.channel('popup.js');
2014-10-18 08:01:09 +13:00
/******************************************************************************/
/******************************************************************************/
function getUserSetting(setting) {
return matrixSnapshot.userSettings[setting];
2014-10-18 08:01:09 +13:00
}
function setUserSetting(setting, value) {
matrixSnapshot.userSettings[setting] = value;
2015-04-12 09:15:57 +12:00
messager.send({
2014-10-18 08:01:09 +13:00
what: 'userSettings',
name: setting,
value: value
});
}
/******************************************************************************/
function getUISetting(setting) {
var r = vAPI.localStorage.getItem(setting);
if ( typeof r !== 'string' ) {
return undefined;
}
return JSON.parse(r);
}
function setUISetting(setting, value) {
vAPI.localStorage.setItem(
setting,
JSON.stringify(value)
);
}
/******************************************************************************/
function updateMatrixSnapshot() {
2015-05-07 10:59:07 +12:00
matrixSnapshotPoller.pollNow();
2014-10-18 08:01:09 +13:00
}
/******************************************************************************/
// For display purpose, create four distinct groups of rows:
// 0th: literal "1st-party" row
2014-10-18 08:01:09 +13:00
// 1st: page domain's related
// 2nd: whitelisted
// 3rd: graylisted
// 4th: blacklisted
function getGroupStats() {
// Try to not reshuffle groups around while popup is opened if
// no new hostname added.
2014-10-20 17:53:13 +13:00
var latestDomainListSnapshot = Object.keys(matrixSnapshot.rows).sort().join();
if ( latestDomainListSnapshot === allHostnamesSnapshot ) {
return groupsSnapshot;
2014-10-18 08:01:09 +13:00
}
allHostnamesSnapshot = latestDomainListSnapshot;
2014-10-18 08:01:09 +13:00
// First, group according to whether at least one node in the domain
// hierarchy is white or blacklisted
var pageDomain = matrixSnapshot.domain;
2014-10-20 17:53:13 +13:00
var rows = matrixSnapshot.rows;
var columnOffsets = matrixSnapshot.headers;
var anyTypeOffset = columnOffsets['*'];
var hostname, domain;
2014-10-26 13:03:22 +13:00
var row, color, count, groupIndex;
2014-10-20 17:53:13 +13:00
var domainToGroupMap = {};
2014-10-26 13:03:22 +13:00
// These have hard-coded position which cannot be overriden
domainToGroupMap['1st-party'] = 0;
domainToGroupMap[pageDomain] = 1;
// 1st pass: domain wins if it has an explicit rule or a count
2014-10-20 17:53:13 +13:00
for ( hostname in rows ) {
if ( rows.hasOwnProperty(hostname) === false ) {
continue;
}
2014-10-26 13:03:22 +13:00
if ( hostname === '*' || hostname === '1st-party' ) {
2014-10-18 08:01:09 +13:00
continue;
}
2014-10-26 13:03:22 +13:00
domain = rows[hostname].domain;
if ( domain === pageDomain || hostname !== domain ) {
2014-10-18 08:01:09 +13:00
continue;
}
2014-10-26 13:03:22 +13:00
row = rows[domain];
color = row.temporary[anyTypeOffset];
if ( color === DarkGreen ) {
domainToGroupMap[domain] = 2;
continue;
}
if ( color === DarkRed ) {
domainToGroupMap[domain] = 4;
continue;
}
count = row.counts[anyTypeOffset];
if ( count !== 0 ) {
domainToGroupMap[domain] = 3;
continue;
}
}
// 2nd pass: green wins
for ( hostname in rows ) {
if ( rows.hasOwnProperty(hostname) === false ) {
continue;
}
row = rows[hostname];
domain = row.domain;
if ( domainToGroupMap.hasOwnProperty(domain) ) {
continue;
}
2014-10-20 17:53:13 +13:00
color = row.temporary[anyTypeOffset];
if ( color === DarkGreen ) {
domainToGroupMap[domain] = 2;
2014-10-26 13:03:22 +13:00
}
}
// 3rd pass: gray with count wins
for ( hostname in rows ) {
if ( rows.hasOwnProperty(hostname) === false ) {
2014-10-20 17:53:13 +13:00
continue;
}
2014-10-26 13:03:22 +13:00
row = rows[hostname];
domain = row.domain;
if ( domainToGroupMap.hasOwnProperty(domain) ) {
continue;
}
color = row.temporary[anyTypeOffset];
count = row.counts[anyTypeOffset];
if ( color !== DarkRed && count !== 0 ) {
domainToGroupMap[domain] = 3;
}
}
// 4th pass: red wins whatever is left
for ( hostname in rows ) {
if ( rows.hasOwnProperty(hostname) === false ) {
continue;
}
row = rows[hostname];
domain = row.domain;
if ( domainToGroupMap.hasOwnProperty(domain) ) {
continue;
}
color = row.temporary[anyTypeOffset];
2014-10-20 17:53:13 +13:00
if ( color === DarkRed ) {
2014-10-26 13:03:22 +13:00
domainToGroupMap[domain] = 4;
}
}
// 5th pass: gray wins whatever is left
for ( hostname in rows ) {
if ( rows.hasOwnProperty(hostname) === false ) {
2014-10-20 17:53:13 +13:00
continue;
2014-10-18 08:01:09 +13:00
}
2014-10-26 13:03:22 +13:00
domain = rows[hostname].domain;
if ( domainToGroupMap.hasOwnProperty(domain) ) {
2014-10-20 17:53:13 +13:00
continue;
2014-10-18 08:01:09 +13:00
}
domainToGroupMap[domain] = 3;
2014-10-20 17:53:13 +13:00
}
2014-10-26 13:03:22 +13:00
// Last pass: put each domain in a group
var groups = [ {}, {}, {}, {}, {} ];
2014-10-20 17:53:13 +13:00
var group;
for ( hostname in rows ) {
if ( rows.hasOwnProperty(hostname) === false ) {
continue;
2014-10-18 08:01:09 +13:00
}
2014-10-20 17:53:13 +13:00
if ( hostname === '*' ) {
continue;
2014-10-18 08:01:09 +13:00
}
2014-10-26 13:03:22 +13:00
domain = rows[hostname].domain;
2014-10-20 17:53:13 +13:00
groupIndex = domainToGroupMap[domain];
group = groups[groupIndex];
if ( group.hasOwnProperty(domain) === false ) {
group[domain] = {};
2014-10-18 08:01:09 +13:00
}
2014-10-20 17:53:13 +13:00
group[domain][hostname] = true;
2014-10-18 08:01:09 +13:00
}
groupsSnapshot = groups;
2014-10-18 08:01:09 +13:00
return groups;
}
/******************************************************************************/
// helpers
function getTemporaryColor(hostname, type) {
2014-10-20 17:53:13 +13:00
return matrixSnapshot.rows[hostname].temporary[matrixSnapshot.headers[type]];
2014-10-18 08:01:09 +13:00
}
function getPermanentColor(hostname, type) {
2014-10-20 17:53:13 +13:00
return matrixSnapshot.rows[hostname].permanent[matrixSnapshot.headers[type]];
2014-10-18 08:01:09 +13:00
}
function getCellClass(hostname, type) {
2014-10-20 17:53:13 +13:00
return 't' + getTemporaryColor(hostname, type).toString(16) +
' p' + getPermanentColor(hostname, type).toString(16);
2014-10-18 08:01:09 +13:00
}
/******************************************************************************/
// This is required for when we update the matrix while it is open:
// the user might have collapsed/expanded one or more domains, and we don't
// want to lose all his hardwork.
function getCollapseState(domain) {
var states = getUISetting('popupCollapseSpecificDomains');
if ( typeof states === 'object' && states[domain] !== undefined ) {
2014-10-18 08:01:09 +13:00
return states[domain];
}
2015-05-14 11:11:44 +12:00
return getUISetting('popupCollapseDomains') === true;
2014-10-18 08:01:09 +13:00
}
2014-10-19 09:49:06 +13:00
function toggleCollapseState(elem) {
if ( elem.ancestors('#matHead.collapsible').length > 0 ) {
toggleMainCollapseState(elem);
2014-10-18 08:01:09 +13:00
} else {
2014-10-19 09:49:06 +13:00
toggleSpecificCollapseState(elem);
2014-10-18 08:01:09 +13:00
}
}
2014-10-19 09:49:06 +13:00
function toggleMainCollapseState(uelem) {
var matHead = uelem.ancestors('#matHead.collapsible').toggleClass('collapsed');
2014-11-08 03:05:05 +13:00
var collapsed = matHead.hasClass('collapsed');
2014-10-18 18:09:09 +13:00
uDom('#matList .matSection.collapsible').toggleClass('collapsed', collapsed);
setUISetting('popupCollapseDomains', collapsed);
2014-10-18 08:01:09 +13:00
var specificCollapseStates = getUISetting('popupCollapseSpecificDomains') || {};
2014-10-18 08:01:09 +13:00
var domains = Object.keys(specificCollapseStates);
var i = domains.length;
var domain;
while ( i-- ) {
domain = domains[i];
if ( specificCollapseStates[domain] === collapsed ) {
delete specificCollapseStates[domain];
}
}
setUISetting('popupCollapseSpecificDomains', specificCollapseStates);
2014-10-18 08:01:09 +13:00
}
2014-10-19 09:49:06 +13:00
function toggleSpecificCollapseState(uelem) {
2014-10-18 08:01:09 +13:00
// Remember collapse state forever, but only if it is different
// from main collapse switch.
2014-10-19 09:49:06 +13:00
var section = uelem.ancestors('.matSection.collapsible').toggleClass('collapsed');
2014-10-18 08:01:09 +13:00
var domain = section.prop('domain');
2014-11-08 03:05:05 +13:00
var collapsed = section.hasClass('collapsed');
2015-05-14 11:14:00 +12:00
var mainCollapseState = getUISetting('popupCollapseDomains') === true;
var specificCollapseStates = getUISetting('popupCollapseSpecificDomains') || {};
2014-10-18 08:01:09 +13:00
if ( collapsed !== mainCollapseState ) {
specificCollapseStates[domain] = collapsed;
setUISetting('popupCollapseSpecificDomains', specificCollapseStates);
2014-10-18 08:01:09 +13:00
} else if ( specificCollapseStates[domain] !== undefined ) {
delete specificCollapseStates[domain];
setUISetting('popupCollapseSpecificDomains', specificCollapseStates);
2014-10-18 08:01:09 +13:00
}
}
/******************************************************************************/
// Update count value of matrix cells(s)
function updateMatrixCounts() {
var matCells = uDom('.matrix .matRow.rw > .matCell');
var i = matCells.length;
var matRow, matCell, count, counts;
var headers = matrixSnapshot.headers;
var rows = matrixSnapshot.rows;
while ( i-- ) {
matCell = matCells.nodeAt(i);
if ( matCell.hostname === '*' ) {
continue;
}
if ( matCell.reqType === '*' ) {
continue;
}
matRow = matCell.parentNode;
counts = matRow.classList.contains('meta') ? 'totals' : 'counts';
count = rows[matCell.hostname][counts][headers[matCell.reqType]];
if ( count === matCell.count) {
continue;
}
matCell.count = count;
matCell.textContent = count ? count : '\u00A0';
}
}
/******************************************************************************/
2014-10-18 08:01:09 +13:00
// Update color of matrix cells(s)
// Color changes when rules change
function updateMatrixColors() {
2014-10-19 09:49:06 +13:00
var cells = uDom('.matrix .matRow.rw > .matCell').removeClass();
2014-10-18 08:01:09 +13:00
var i = cells.length;
var cell;
while ( i-- ) {
2014-10-19 10:11:10 +13:00
cell = cells.nodeAt(i);
2014-10-19 09:49:06 +13:00
cell.className = 'matCell ' + getCellClass(cell.hostname, cell.reqType);
2014-10-18 08:01:09 +13:00
}
}
/******************************************************************************/
// Update behavior of matrix:
// - Whether a section is collapsible or not. It is collapsible if:
// - It has at least one subdomain AND
// - There is no explicit rule anywhere in the subdomain cells AND
// - It is not part of group 3 (blacklisted hostnames)
function updateMatrixBehavior() {
2014-10-19 09:49:06 +13:00
matrixList = matrixList || uDom('#matList');
var sections = matrixList.descendants('.matSection');
2014-10-18 08:01:09 +13:00
var i = sections.length;
var section, subdomainRows, j, subdomainRow;
while ( i-- ) {
2014-10-19 10:11:10 +13:00
section = sections.at(i);
subdomainRows = section.descendants('.l2:not(.g4)');
2014-10-18 08:01:09 +13:00
j = subdomainRows.length;
while ( j-- ) {
2014-10-19 10:11:10 +13:00
subdomainRow = subdomainRows.at(j);
2014-10-26 09:41:08 +13:00
subdomainRow.toggleClass('collapsible', subdomainRow.descendants('.t81,.t82').length === 0);
2014-10-18 08:01:09 +13:00
}
section.toggleClass('collapsible', subdomainRows.filter('.collapsible').length > 0);
}
}
/******************************************************************************/
// handle user interaction with filters
function getCellAction(hostname, type, leaning) {
var temporaryColor = getTemporaryColor(hostname, type);
var hue = temporaryColor & 0x03;
// Special case: root toggle only between two states
if ( type === '*' && hostname === '*' ) {
return hue === Green ? 'blacklistMatrixCell' : 'whitelistMatrixCell';
}
// When explicitly blocked/allowed, can only graylist
var saturation = temporaryColor & 0x80;
if ( saturation === Dark ) {
return 'graylistMatrixCell';
}
return leaning === 'whitelisting' ? 'whitelistMatrixCell' : 'blacklistMatrixCell';
}
2014-10-18 08:01:09 +13:00
function handleFilter(button, leaning) {
// our parent cell knows who we are
2014-10-19 09:49:06 +13:00
var cell = button.ancestors('div.matCell');
2014-10-18 08:01:09 +13:00
var type = cell.prop('reqType');
var desHostname = cell.prop('hostname');
2014-10-30 02:27:11 +13:00
// https://github.com/gorhill/uMatrix/issues/24
// No hostname can happen -- like with blacklist meta row
if ( desHostname === '' ) {
return;
}
var request = {
what: getCellAction(desHostname, type, leaning),
srcHostname: matrixSnapshot.scope,
desHostname: desHostname,
type: type
};
2015-04-12 09:15:57 +12:00
messager.send(request, updateMatrixSnapshot);
2014-10-18 08:01:09 +13:00
}
function handleWhitelistFilter(button) {
handleFilter(button, 'whitelisting');
}
function handleBlacklistFilter(button) {
handleFilter(button, 'blacklisting');
}
/******************************************************************************/
var matrixRowPool = [];
var matrixSectionPool = [];
var matrixGroupPool = [];
var matrixRowTemplate = null;
var matrixList = null;
var startMatrixUpdate = function() {
2014-10-19 09:49:06 +13:00
matrixList = matrixList || uDom('#matList');
2014-10-18 08:01:09 +13:00
matrixList.detach();
2014-10-19 09:49:06 +13:00
var rows = matrixList.descendants('.matRow');
2014-10-18 08:01:09 +13:00
rows.detach();
matrixRowPool = matrixRowPool.concat(rows.toArray());
2014-10-19 09:49:06 +13:00
var sections = matrixList.descendants('.matSection');
2014-10-18 08:01:09 +13:00
sections.detach();
matrixSectionPool = matrixSectionPool.concat(sections.toArray());
2014-10-19 09:49:06 +13:00
var groups = matrixList.descendants('.matGroup');
2014-10-18 08:01:09 +13:00
groups.detach();
matrixGroupPool = matrixGroupPool.concat(groups.toArray());
};
var endMatrixUpdate = function() {
// https://github.com/gorhill/httpswitchboard/issues/246
// If the matrix has no rows, we need to insert a dummy one, invisible,
// to ensure the extension pop-up is properly sized. This is needed because
// the header pane's `position` property is `fixed`, which means it doesn't
// affect layout size, hence the matrix header row will be truncated.
2014-10-20 17:53:13 +13:00
if ( matrixSnapshot.rowCount <= 1 ) {
2014-10-18 08:01:09 +13:00
matrixList.append(createMatrixRow().css('visibility', 'hidden'));
}
updateMatrixBehavior();
matrixList.css('display', '');
2014-10-19 09:49:06 +13:00
matrixList.appendTo('.paneContent');
2014-10-18 08:01:09 +13:00
};
var createMatrixGroup = function() {
var group = matrixGroupPool.pop();
if ( group ) {
2014-10-19 09:49:06 +13:00
return uDom(group).removeClass().addClass('matGroup');
2014-10-18 08:01:09 +13:00
}
2014-10-19 09:49:06 +13:00
return uDom('<div>').addClass('matGroup');
2014-10-18 08:01:09 +13:00
};
var createMatrixSection = function() {
var section = matrixSectionPool.pop();
if ( section ) {
2014-10-19 09:49:06 +13:00
return uDom(section).removeClass().addClass('matSection');
2014-10-18 08:01:09 +13:00
}
2014-10-19 09:49:06 +13:00
return uDom('<div>').addClass('matSection');
2014-10-18 08:01:09 +13:00
};
var createMatrixRow = function() {
var row = matrixRowPool.pop();
if ( row ) {
row.style.visibility = '';
2014-10-19 09:49:06 +13:00
row = uDom(row);
row.descendants('.matCell').removeClass().addClass('matCell');
2014-10-18 08:01:09 +13:00
row.removeClass().addClass('matRow');
return row;
}
if ( matrixRowTemplate === null ) {
2014-10-19 09:49:06 +13:00
matrixRowTemplate = uDom('#templates .matRow');
2014-10-18 08:01:09 +13:00
}
return matrixRowTemplate.clone();
};
/******************************************************************************/
function renderMatrixHeaderRow() {
2014-10-18 18:09:09 +13:00
var matHead = uDom('#matHead.collapsible');
2015-05-14 11:14:00 +12:00
matHead.toggleClass('collapsed', getUISetting('popupCollapseDomains') === true);
2014-10-19 09:49:06 +13:00
var cells = matHead.descendants('.matCell');
2014-10-19 10:11:10 +13:00
cells.at(0)
2014-10-18 18:09:09 +13:00
.prop('reqType', '*')
.prop('hostname', '*')
.addClass(getCellClass('*', '*'));
2014-10-19 10:11:10 +13:00
cells.at(1)
2014-10-18 18:09:09 +13:00
.prop('reqType', 'cookie')
.prop('hostname', '*')
.addClass(getCellClass('*', 'cookie'));
2014-10-19 10:11:10 +13:00
cells.at(2)
2014-10-18 18:09:09 +13:00
.prop('reqType', 'css')
.prop('hostname', '*')
.addClass(getCellClass('*', 'css'));
2014-10-19 10:11:10 +13:00
cells.at(3)
2014-10-18 18:09:09 +13:00
.prop('reqType', 'image')
.prop('hostname', '*')
.addClass(getCellClass('*', 'image'));
2014-10-19 10:11:10 +13:00
cells.at(4)
2014-10-18 18:09:09 +13:00
.prop('reqType', 'plugin')
.prop('hostname', '*')
.addClass(getCellClass('*', 'plugin'));
2014-10-19 10:11:10 +13:00
cells.at(5)
2014-10-18 18:09:09 +13:00
.prop('reqType', 'script')
.prop('hostname', '*')
.addClass(getCellClass('*', 'script'));
2014-10-19 10:11:10 +13:00
cells.at(6)
2014-10-18 18:09:09 +13:00
.prop('reqType', 'xhr')
.prop('hostname', '*')
.addClass(getCellClass('*', 'xhr'));
2014-10-19 10:11:10 +13:00
cells.at(7)
2014-10-18 18:09:09 +13:00
.prop('reqType', 'frame')
.prop('hostname', '*')
.addClass(getCellClass('*', 'frame'));
2014-10-19 10:11:10 +13:00
cells.at(8)
2014-10-18 18:09:09 +13:00
.prop('reqType', 'other')
.prop('hostname', '*')
.addClass(getCellClass('*', 'other'));
uDom('#matHead .matRow').css('display', '');
2014-10-18 08:01:09 +13:00
}
/******************************************************************************/
function renderMatrixCellDomain(cell, domain) {
2014-10-19 10:11:10 +13:00
var contents = cell.prop('reqType', '*')
2014-10-18 18:09:09 +13:00
.prop('hostname', domain)
2014-10-18 08:01:09 +13:00
.addClass(getCellClass(domain, '*'))
.contents();
contents.nodeAt(0).textContent = domain === '1st-party' ?
firstPartyLabel :
punycode.toUnicode(domain);
2014-10-19 10:11:10 +13:00
contents.nodeAt(1).textContent = ' ';
2014-10-18 08:01:09 +13:00
}
function renderMatrixCellSubdomain(cell, domain, subomain) {
2014-10-19 10:11:10 +13:00
var contents = cell.prop('reqType', '*')
2014-10-18 18:09:09 +13:00
.prop('hostname', subomain)
2014-10-18 08:01:09 +13:00
.addClass(getCellClass(subomain, '*'))
.contents();
2014-11-04 08:27:59 +13:00
contents.nodeAt(0).textContent = punycode.toUnicode(subomain.slice(0, subomain.lastIndexOf(domain)-1)) + '.';
2014-10-19 10:11:10 +13:00
contents.nodeAt(1).textContent = punycode.toUnicode(domain);
2014-10-18 08:01:09 +13:00
}
function renderMatrixMetaCellDomain(cell, domain) {
2014-10-19 10:11:10 +13:00
var contents = cell.prop('reqType', '*')
2014-10-18 18:09:09 +13:00
.prop('hostname', domain)
2014-10-18 08:01:09 +13:00
.addClass(getCellClass(domain, '*'))
.contents();
2014-11-04 08:27:59 +13:00
contents.nodeAt(0).textContent = '\u2217.' + punycode.toUnicode(domain);
2014-10-19 10:11:10 +13:00
contents.nodeAt(1).textContent = ' ';
2014-10-18 08:01:09 +13:00
}
2014-10-20 17:53:13 +13:00
function renderMatrixCellType(cell, hostname, type, count) {
2014-10-19 10:11:10 +13:00
cell.prop('reqType', type)
2014-10-18 18:09:09 +13:00
.prop('hostname', hostname)
2014-10-20 17:53:13 +13:00
.prop('count', count)
2014-10-18 08:01:09 +13:00
.addClass(getCellClass(hostname, type));
2014-10-20 17:53:13 +13:00
if ( count ) {
cell.text(count);
2014-10-18 08:01:09 +13:00
} else {
2014-10-19 10:11:10 +13:00
cell.text('\u00A0');
2014-10-18 08:01:09 +13:00
}
}
2014-10-20 17:53:13 +13:00
function renderMatrixCellTypes(cells, hostname, countName) {
var counts = matrixSnapshot.rows[hostname][countName];
var countIndices = matrixSnapshot.headers;
renderMatrixCellType(cells.at(1), hostname, 'cookie', counts[countIndices.cookie]);
renderMatrixCellType(cells.at(2), hostname, 'css', counts[countIndices.css]);
renderMatrixCellType(cells.at(3), hostname, 'image', counts[countIndices.image]);
renderMatrixCellType(cells.at(4), hostname, 'plugin', counts[countIndices.plugin]);
renderMatrixCellType(cells.at(5), hostname, 'script', counts[countIndices.script]);
renderMatrixCellType(cells.at(6), hostname, 'xhr', counts[countIndices.xhr]);
renderMatrixCellType(cells.at(7), hostname, 'frame', counts[countIndices.frame]);
renderMatrixCellType(cells.at(8), hostname, 'other', counts[countIndices.other]);
2014-10-18 08:01:09 +13:00
}
/******************************************************************************/
function makeMatrixRowDomain(domain) {
var matrixRow = createMatrixRow().addClass('rw');
2014-10-19 09:49:06 +13:00
var cells = matrixRow.descendants('.matCell');
2014-10-19 10:11:10 +13:00
renderMatrixCellDomain(cells.at(0), domain);
2014-10-20 17:53:13 +13:00
renderMatrixCellTypes(cells, domain, 'counts');
2014-10-18 08:01:09 +13:00
return matrixRow;
}
function makeMatrixRowSubdomain(domain, subdomain) {
var matrixRow = createMatrixRow().addClass('rw');
2014-10-19 09:49:06 +13:00
var cells = matrixRow.descendants('.matCell');
2014-10-19 10:11:10 +13:00
renderMatrixCellSubdomain(cells.at(0), domain, subdomain);
2014-10-20 17:53:13 +13:00
renderMatrixCellTypes(cells, subdomain, 'counts');
2014-10-18 08:01:09 +13:00
return matrixRow;
}
2014-10-20 17:53:13 +13:00
function makeMatrixMetaRowDomain(domain) {
2014-10-18 08:01:09 +13:00
var matrixRow = createMatrixRow().addClass('rw');
2014-10-19 09:49:06 +13:00
var cells = matrixRow.descendants('.matCell');
2014-10-19 10:11:10 +13:00
renderMatrixMetaCellDomain(cells.at(0), domain);
2014-10-20 17:53:13 +13:00
renderMatrixCellTypes(cells, domain, 'totals');
2014-10-18 08:01:09 +13:00
return matrixRow;
}
/******************************************************************************/
function renderMatrixMetaCellType(cell, count) {
2014-10-30 02:27:11 +13:00
// https://github.com/gorhill/uMatrix/issues/24
// Don't forget to reset cell properties
cell.addClass('t1')
.prop('reqType', '')
.prop('hostname', '')
.prop('count', count);
2014-10-18 08:01:09 +13:00
if ( count ) {
2014-10-19 10:11:10 +13:00
cell.text(count);
2014-10-30 03:10:07 +13:00
} else {
cell.text('\u00A0');
2014-10-18 08:01:09 +13:00
}
}
2014-10-20 17:53:13 +13:00
function makeMatrixMetaRow(totals) {
var typeOffsets = matrixSnapshot.headers;
2014-10-19 10:11:10 +13:00
var matrixRow = createMatrixRow().at(0).addClass('ro');
2014-10-19 09:49:06 +13:00
var cells = matrixRow.descendants('.matCell');
2014-10-20 17:53:13 +13:00
var contents = cells.at(0).addClass('t81').contents();
2014-10-30 02:59:02 +13:00
cells.at(0).prop('reqType', '*').prop('hostname', '');
2014-10-19 10:11:10 +13:00
contents.nodeAt(0).textContent = ' ';
contents.nodeAt(1).textContent = blacklistedHostnamesLabel.replace('{{count}}', totals[typeOffsets['*']]);
2014-10-20 17:53:13 +13:00
renderMatrixMetaCellType(cells.at(1), totals[typeOffsets.cookie]);
renderMatrixMetaCellType(cells.at(2), totals[typeOffsets.css]);
renderMatrixMetaCellType(cells.at(3), totals[typeOffsets.image]);
renderMatrixMetaCellType(cells.at(4), totals[typeOffsets.plugin]);
renderMatrixMetaCellType(cells.at(5), totals[typeOffsets.script]);
renderMatrixMetaCellType(cells.at(6), totals[typeOffsets.xhr]);
renderMatrixMetaCellType(cells.at(7), totals[typeOffsets.frame]);
renderMatrixMetaCellType(cells.at(8), totals[typeOffsets.other]);
2014-10-19 09:49:06 +13:00
return matrixRow;
2014-10-18 08:01:09 +13:00
}
/******************************************************************************/
function computeMatrixGroupMetaStats(group) {
var headers = matrixSnapshot.headers;
2015-04-11 02:45:40 +12:00
var n = Object.keys(headers).length;
var totals = new Array(n);
var i = n;
2014-10-18 08:01:09 +13:00
while ( i-- ) {
2014-10-20 17:53:13 +13:00
totals[i] = 0;
}
var rows = matrixSnapshot.rows, row;
for ( var hostname in rows ) {
if ( rows.hasOwnProperty(hostname) === false ) {
continue;
2014-10-18 08:01:09 +13:00
}
row = rows[hostname];
if ( group.hasOwnProperty(row.domain) === false ) {
continue;
}
if ( row.counts[headers['*']] === 0 ) {
continue;
}
totals[0] += 1;
for ( i = 1; i < n; i++ ) {
totals[i] += row.counts[i];
}
2014-10-18 08:01:09 +13:00
}
2014-10-20 17:53:13 +13:00
return totals;
2014-10-18 08:01:09 +13:00
}
/******************************************************************************/
// Compare hostname helper, to order hostname in a logical manner:
// top-most < bottom-most, take into account whether IP address or
// named hostname
function hostnameCompare(a,b) {
// Normalize: most significant parts first
if ( !a.match(/^\d+(\.\d+){1,3}$/) ) {
var aa = a.split('.');
a = aa.slice(-2).concat(aa.slice(0,-2).reverse()).join('.');
}
if ( !b.match(/^\d+(\.\d+){1,3}$/) ) {
var bb = b.split('.');
b = bb.slice(-2).concat(bb.slice(0,-2).reverse()).join('.');
}
return a.localeCompare(b);
}
/******************************************************************************/
function makeMatrixGroup0SectionDomain() {
return makeMatrixRowDomain('1st-party').addClass('g0 l1');
2014-10-18 08:01:09 +13:00
}
2014-10-26 13:03:22 +13:00
function makeMatrixGroup0Section() {
var domainDiv = createMatrixSection().prop('domain', '1st-party');
makeMatrixGroup0SectionDomain().appendTo(domainDiv);
2014-10-18 08:01:09 +13:00
return domainDiv;
}
2014-10-26 13:03:22 +13:00
function makeMatrixGroup0() {
// Show literal "1st-party" row only if there is
// at least one 1st-party hostname
if ( Object.keys(groupsSnapshot[1]).length === 0 ) {
return;
}
var groupDiv = createMatrixGroup().addClass('g0');
makeMatrixGroup0Section().appendTo(groupDiv);
groupDiv.appendTo(matrixList);
2014-10-18 08:01:09 +13:00
}
/******************************************************************************/
function makeMatrixGroup1SectionDomain(domain) {
return makeMatrixRowDomain(domain)
.addClass('g1 l1');
}
function makeMatrixGroup1SectionSubomain(domain, subdomain) {
return makeMatrixRowSubdomain(domain, subdomain)
.addClass('g1 l2');
}
2014-10-20 17:53:13 +13:00
function makeMatrixGroup1SectionMetaDomain(domain) {
return makeMatrixMetaRowDomain(domain).addClass('g1 l1 meta');
2014-10-18 08:01:09 +13:00
}
function makeMatrixGroup1Section(hostnames) {
var domain = hostnames[0];
var domainDiv = createMatrixSection()
.toggleClass('collapsed', getCollapseState(domain))
.prop('domain', domain);
if ( hostnames.length > 1 ) {
makeMatrixGroup1SectionMetaDomain(domain)
.appendTo(domainDiv);
2014-10-18 08:01:09 +13:00
}
makeMatrixGroup1SectionDomain(domain)
.appendTo(domainDiv);
for ( var i = 1; i < hostnames.length; i++ ) {
makeMatrixGroup1SectionSubomain(domain, hostnames[i])
.appendTo(domainDiv);
}
return domainDiv;
}
function makeMatrixGroup1(group) {
var domains = Object.keys(group).sort(hostnameCompare);
if ( domains.length ) {
var groupDiv = createMatrixGroup().addClass('g1');
2014-10-20 17:53:13 +13:00
makeMatrixGroup1Section(Object.keys(group[domains[0]]).sort(hostnameCompare))
2014-10-18 08:01:09 +13:00
.appendTo(groupDiv);
for ( var i = 1; i < domains.length; i++ ) {
2014-10-20 17:53:13 +13:00
makeMatrixGroup1Section(Object.keys(group[domains[i]]).sort(hostnameCompare))
2014-10-18 08:01:09 +13:00
.appendTo(groupDiv);
}
groupDiv.appendTo(matrixList);
}
}
/******************************************************************************/
function makeMatrixGroup2SectionDomain(domain) {
return makeMatrixRowDomain(domain)
.addClass('g2 l1');
}
function makeMatrixGroup2SectionSubomain(domain, subdomain) {
return makeMatrixRowSubdomain(domain, subdomain)
.addClass('g2 l2');
}
2014-10-20 17:53:13 +13:00
function makeMatrixGroup2SectionMetaDomain(domain) {
return makeMatrixMetaRowDomain(domain).addClass('g2 l1 meta');
2014-10-18 08:01:09 +13:00
}
function makeMatrixGroup2Section(hostnames) {
var domain = hostnames[0];
var domainDiv = createMatrixSection()
.toggleClass('collapsed', getCollapseState(domain))
.prop('domain', domain);
if ( hostnames.length > 1 ) {
2014-10-20 17:53:13 +13:00
makeMatrixGroup2SectionMetaDomain(domain).appendTo(domainDiv);
2014-10-18 08:01:09 +13:00
}
makeMatrixGroup2SectionDomain(domain)
.appendTo(domainDiv);
for ( var i = 1; i < hostnames.length; i++ ) {
makeMatrixGroup2SectionSubomain(domain, hostnames[i])
.appendTo(domainDiv);
}
return domainDiv;
}
function makeMatrixGroup2(group) {
var domains = Object.keys(group).sort(hostnameCompare);
if ( domains.length) {
var groupDiv = createMatrixGroup()
.addClass('g2');
2014-10-20 17:53:13 +13:00
makeMatrixGroup2Section(Object.keys(group[domains[0]]).sort(hostnameCompare))
2014-10-18 08:01:09 +13:00
.appendTo(groupDiv);
for ( var i = 1; i < domains.length; i++ ) {
2014-10-20 17:53:13 +13:00
makeMatrixGroup2Section(Object.keys(group[domains[i]]).sort(hostnameCompare))
2014-10-18 08:01:09 +13:00
.appendTo(groupDiv);
}
groupDiv.appendTo(matrixList);
}
}
/******************************************************************************/
function makeMatrixGroup3SectionDomain(domain) {
return makeMatrixRowDomain(domain)
.addClass('g3 l1');
}
function makeMatrixGroup3SectionSubomain(domain, subdomain) {
return makeMatrixRowSubdomain(domain, subdomain)
.addClass('g3 l2');
}
function makeMatrixGroup3SectionMetaDomain(domain) {
return makeMatrixMetaRowDomain(domain).addClass('g3 l1 meta');
}
2014-10-18 08:01:09 +13:00
function makeMatrixGroup3Section(hostnames) {
var domain = hostnames[0];
var domainDiv = createMatrixSection()
.toggleClass('collapsed', getCollapseState(domain))
2014-10-18 08:01:09 +13:00
.prop('domain', domain);
if ( hostnames.length > 1 ) {
makeMatrixGroup3SectionMetaDomain(domain).appendTo(domainDiv);
}
2014-10-18 08:01:09 +13:00
makeMatrixGroup3SectionDomain(domain)
.appendTo(domainDiv);
for ( var i = 1; i < hostnames.length; i++ ) {
makeMatrixGroup3SectionSubomain(domain, hostnames[i])
.appendTo(domainDiv);
}
return domainDiv;
}
function makeMatrixGroup3(group) {
var domains = Object.keys(group).sort(hostnameCompare);
if ( domains.length) {
var groupDiv = createMatrixGroup()
.addClass('g3');
makeMatrixGroup3Section(Object.keys(group[domains[0]]).sort(hostnameCompare))
.appendTo(groupDiv);
for ( var i = 1; i < domains.length; i++ ) {
makeMatrixGroup3Section(Object.keys(group[domains[i]]).sort(hostnameCompare))
.appendTo(groupDiv);
}
groupDiv.appendTo(matrixList);
}
}
/******************************************************************************/
function makeMatrixGroup4SectionDomain(domain) {
return makeMatrixRowDomain(domain)
.addClass('g4 l1');
}
function makeMatrixGroup4SectionSubomain(domain, subdomain) {
return makeMatrixRowSubdomain(domain, subdomain)
.addClass('g4 l2');
}
function makeMatrixGroup4Section(hostnames) {
var domain = hostnames[0];
var domainDiv = createMatrixSection()
.prop('domain', domain);
makeMatrixGroup4SectionDomain(domain)
.appendTo(domainDiv);
for ( var i = 1; i < hostnames.length; i++ ) {
makeMatrixGroup4SectionSubomain(domain, hostnames[i])
.appendTo(domainDiv);
}
return domainDiv;
}
function makeMatrixGroup4(group) {
2014-10-18 08:01:09 +13:00
var domains = Object.keys(group).sort(hostnameCompare);
if ( domains.length === 0 ) {
return;
}
var groupDiv = createMatrixGroup().addClass('g4');
2014-10-18 08:01:09 +13:00
createMatrixSection()
.addClass('g4Meta')
.toggleClass('g4Collapsed', !!getUISetting('popupHideBlacklisted'))
2014-10-18 08:01:09 +13:00
.appendTo(groupDiv);
makeMatrixMetaRow(computeMatrixGroupMetaStats(group), 'g4')
2014-10-18 08:01:09 +13:00
.appendTo(groupDiv);
makeMatrixGroup4Section(Object.keys(group[domains[0]]).sort(hostnameCompare))
2014-10-18 08:01:09 +13:00
.appendTo(groupDiv);
for ( var i = 1; i < domains.length; i++ ) {
makeMatrixGroup4Section(Object.keys(group[domains[i]]).sort(hostnameCompare))
2014-10-18 08:01:09 +13:00
.appendTo(groupDiv);
}
groupDiv.appendTo(matrixList);
}
/******************************************************************************/
2014-10-20 17:53:13 +13:00
var makeMenu = function() {
2014-10-18 08:01:09 +13:00
var groupStats = getGroupStats();
if ( Object.keys(groupStats).length === 0 ) {
return;
}
// https://github.com/gorhill/httpswitchboard/issues/31
if ( matrixCellHotspots ) {
matrixCellHotspots.detach();
}
renderMatrixHeaderRow();
startMatrixUpdate();
makeMatrixGroup0(groupStats[0]);
makeMatrixGroup1(groupStats[1]);
makeMatrixGroup2(groupStats[2]);
makeMatrixGroup3(groupStats[3]);
makeMatrixGroup4(groupStats[4]);
2014-10-18 08:01:09 +13:00
endMatrixUpdate();
initScopeCell();
updateMatrixButtons();
2014-10-20 17:53:13 +13:00
};
2014-10-18 08:01:09 +13:00
/******************************************************************************/
// Do all the stuff that needs to be done before building menu et al.
function initMenuEnvironment() {
uDom('body').css('font-size', getUserSetting('displayTextSize'));
uDom('body').toggleClass('colorblind', getUserSetting('colorBlindFriendly') === true);
var prettyNames = matrixHeaderPrettyNames;
2014-10-18 08:01:09 +13:00
var keys = Object.keys(prettyNames);
var i = keys.length;
var cell, key, text;
while ( i-- ) {
key = keys[i];
2014-11-02 05:52:02 +13:00
cell = uDom('#matHead .matCell[data-req-type="'+ key +'"]');
2015-04-12 09:15:57 +12:00
text = vAPI.i18n(key + 'PrettyName');
2014-10-18 08:01:09 +13:00
cell.text(text);
prettyNames[key] = text;
}
2014-11-04 08:27:59 +13:00
firstPartyLabel = uDom('[data-i18n="matrix1stPartyLabel"]').text();
blacklistedHostnamesLabel = uDom('[data-i18n="matrixBlacklistedHostnames"]').text();
2014-10-18 08:01:09 +13:00
}
/******************************************************************************/
// Create page scopes for the web page
function selectGlobalScope() {
setUserSetting('popupScopeLevel', '*');
matrixSnapshot.tMatrixModifiedTime = undefined;
2014-10-20 17:53:13 +13:00
updateMatrixSnapshot();
2014-10-18 08:01:09 +13:00
dropDownMenuHide();
}
function selectDomainScope() {
setUserSetting('popupScopeLevel', 'domain');
matrixSnapshot.tMatrixModifiedTime = undefined;
2014-10-20 17:53:13 +13:00
updateMatrixSnapshot();
2014-10-18 08:01:09 +13:00
dropDownMenuHide();
}
function selectSiteScope() {
setUserSetting('popupScopeLevel', 'site');
matrixSnapshot.tMatrixModifiedTime = undefined;
2014-10-20 17:53:13 +13:00
updateMatrixSnapshot();
2014-10-18 08:01:09 +13:00
dropDownMenuHide();
}
function getClassFromScope() {
if ( matrixSnapshot.scope === '*' ) {
2014-10-19 09:49:06 +13:00
return 'tScopeGlobal';
2014-10-18 08:01:09 +13:00
}
if ( matrixSnapshot.scope === matrixSnapshot.domain ) {
return 'tScopeDomain';
2014-10-19 09:49:06 +13:00
}
return 'tScopeSite';
2014-10-18 08:01:09 +13:00
}
function initScopeCell() {
// It's possible there is no page URL at this point: some pages cannot
// be filtered by µMatrix.
if ( matrixSnapshot.url === '' ) {
2014-10-18 08:01:09 +13:00
return;
}
// Fill in the scope menu entries
if ( matrixSnapshot.hostname === matrixSnapshot.domain ) {
uDom('#scopeKeySite').css('display', 'none');
2014-10-19 14:42:06 +13:00
} else {
2015-05-12 03:53:02 +12:00
uDom('#scopeKeySite').text(punycode.toUnicode(matrixSnapshot.hostname));
2014-10-19 14:42:06 +13:00
}
2015-05-12 03:53:02 +12:00
uDom('#scopeKeyDomain').text(punycode.toUnicode(matrixSnapshot.domain));
2014-10-18 08:01:09 +13:00
updateScopeCell();
}
function updateScopeCell() {
2014-10-18 18:09:09 +13:00
uDom('body')
.removeClass('tScopeGlobal tScopeDomain tScopeSite')
.addClass(getClassFromScope());
2015-05-12 03:53:02 +12:00
uDom('#scopeCell').text(
punycode.toUnicode(matrixSnapshot.scope).replace('*', '\u2217')
);
2014-10-18 08:01:09 +13:00
}
/******************************************************************************/
2014-11-19 15:18:57 +13:00
function updateMatrixSwitches() {
var switches = matrixSnapshot.tSwitches;
for ( var switchName in switches ) {
if ( switches.hasOwnProperty(switchName) === false ) {
continue;
}
uDom('#mtxSwitch_' + switchName).toggleClass('switchTrue', switches[switchName]);
}
var count = matrixSnapshot.blockedCount;
2014-11-19 15:18:57 +13:00
var button = uDom('#mtxSwitch_matrix-off');
button.descendants('span.badge').text(count.toLocaleString());
2014-10-19 09:49:06 +13:00
button.attr('data-tip', button.attr('data-tip').replace('{{count}}', count));
2014-11-19 15:18:57 +13:00
uDom('body').toggleClass('powerOff', switches['matrix-off']);
2014-10-18 08:01:09 +13:00
}
function toggleMatrixSwitch(ev) {
var elem = ev.currentTarget;
var pos = elem.id.indexOf('_');
2014-11-19 15:18:57 +13:00
if ( pos === -1 ) {
return;
}
var switchName = elem.id.slice(pos + 1);
var request = {
what: 'toggleMatrixSwitch',
2014-11-19 15:18:57 +13:00
switchName: switchName,
srcHostname: matrixSnapshot.scope
};
2015-04-12 09:15:57 +12:00
messager.send(request, updateMatrixSnapshot);
2014-10-18 08:01:09 +13:00
}
/******************************************************************************/
function updatePersistButton() {
var diffCount = matrixSnapshot.diff.length;
2014-10-19 09:49:06 +13:00
var button = uDom('#buttonPersist');
2014-10-18 08:01:09 +13:00
button.contents()
.filter(function(){return this.nodeType===3;})
2014-10-19 09:49:06 +13:00
.first()
.text(diffCount > 0 ? '\uf13e' : '\uf023');
button.descendants('span.badge').text(diffCount > 0 ? diffCount : '');
var disabled = diffCount === 0;
2014-10-18 08:01:09 +13:00
button.toggleClass('disabled', disabled);
2014-10-18 18:09:09 +13:00
uDom('#buttonRevertScope').toggleClass('disabled', disabled);
2014-10-18 08:01:09 +13:00
}
/******************************************************************************/
function persistMatrix() {
var request = {
what: 'applyDiffToPermanentMatrix',
diff: matrixSnapshot.diff
};
2015-04-12 09:15:57 +12:00
messager.send(request, updateMatrixSnapshot);
2014-10-18 08:01:09 +13:00
}
/******************************************************************************/
// rhill 2014-03-12: revert completely ALL changes related to the
// current page, including scopes.
function revertMatrix() {
var request = {
what: 'applyDiffToTemporaryMatrix',
diff: matrixSnapshot.diff
};
2015-04-12 09:15:57 +12:00
messager.send(request, updateMatrixSnapshot);
2014-10-18 08:01:09 +13:00
}
/******************************************************************************/
// Buttons which are affected by any changes in the matrix
function updateMatrixButtons() {
updateScopeCell();
2014-11-19 15:18:57 +13:00
updateMatrixSwitches();
2014-10-18 08:01:09 +13:00
updatePersistButton();
}
/******************************************************************************/
function revertAll() {
var request = {
what: 'revertTemporaryMatrix'
};
2015-04-12 09:15:57 +12:00
messager.send(request, updateMatrixSnapshot);
2015-05-05 12:26:45 +12:00
dropDownMenuHide();
2014-10-18 08:01:09 +13:00
}
/******************************************************************************/
function buttonReloadHandler() {
2015-04-12 09:15:57 +12:00
messager.send({
2014-10-18 08:01:09 +13:00
what: 'forceReloadTab',
2015-04-14 07:01:12 +12:00
tabId: matrixSnapshot.tabId
2014-10-18 08:01:09 +13:00
});
}
/******************************************************************************/
function mouseenterMatrixCellHandler(ev) {
matrixCellHotspots.appendTo(ev.target);
2014-10-18 08:01:09 +13:00
}
function mouseleaveMatrixCellHandler() {
matrixCellHotspots.detach();
}
/******************************************************************************/
function gotoExtensionURL(ev) {
var url = uDom(ev.currentTarget).attr('data-extension-url');
2014-10-18 08:01:09 +13:00
if ( url ) {
2015-04-12 09:15:57 +12:00
messager.send({ what: 'gotoExtensionURL', url: url });
2014-10-18 08:01:09 +13:00
}
dropDownMenuHide();
2015-05-03 05:43:50 +12:00
vAPI.closePopup();
2014-10-18 08:01:09 +13:00
}
/******************************************************************************/
function dropDownMenuShow(ev) {
var button = ev.target;
var menu = button.nextElementSibling;
var butnRect = button.getBoundingClientRect();
var viewRect = document.body.getBoundingClientRect();
var butnNormalLeft = butnRect.left / (viewRect.width - butnRect.width);
menu.classList.add('show');
var menuRect = menu.getBoundingClientRect();
var menuLeft = butnNormalLeft * (viewRect.width - menuRect.width);
menu.style.left = menuLeft.toFixed(0) + 'px';
2014-10-18 08:01:09 +13:00
}
function dropDownMenuHide() {
2014-10-18 18:09:09 +13:00
uDom('.dropdown-menu').removeClass('show');
2014-10-18 08:01:09 +13:00
}
/******************************************************************************/
2014-10-20 17:53:13 +13:00
var onMatrixSnapshotReady = function(response) {
2014-10-18 08:01:09 +13:00
// Now that tabId and pageURL are set, we can build our menu
initMenuEnvironment();
makeMenu();
// After popup menu is built, check whether there is a non-empty matrix
if ( matrixSnapshot.url === '' ) {
2014-10-19 09:49:06 +13:00
uDom('#matHead').remove();
uDom('#toolbarLeft').remove();
2014-10-18 08:01:09 +13:00
// https://github.com/gorhill/httpswitchboard/issues/191
2015-04-12 09:15:57 +12:00
uDom('#noNetTrafficPrompt').text(vAPI.i18n('matrixNoNetTrafficPrompt'));
2014-10-18 18:09:09 +13:00
uDom('#noNetTrafficPrompt').css('display', '');
2014-10-18 08:01:09 +13:00
}
// Create a hash to find out whether the reload button needs to be
// highlighted.
// TODO:
2014-10-18 08:01:09 +13:00
};
2014-10-20 17:53:13 +13:00
/******************************************************************************/
var matrixSnapshotPoller = (function() {
var timer = null;
2015-05-07 10:59:07 +12:00
var processPollResult = function(response) {
if ( typeof response !== 'object' ) {
return;
}
if (
response.mtxContentModified === false &&
response.mtxCountModified === false &&
response.pMatrixModified === false &&
response.tMatrixModified === false
2015-05-07 10:59:07 +12:00
) {
return;
}
matrixSnapshot = response;
if ( response.mtxContentModified ) {
makeMenu();
return;
}
if ( response.mtxCountModified ) {
updateMatrixCounts();
}
if (
response.pMatrixModified ||
response.tMatrixModified ||
response.scopeModified
) {
2015-05-07 10:59:07 +12:00
updateMatrixColors();
updateMatrixBehavior();
updateMatrixButtons();
}
};
2015-05-07 10:59:07 +12:00
var onPolled = function(response) {
processPollResult(response);
pollAsync();
};
var pollNow = function() {
unpollAsync();
messager.send({
what: 'matrixSnapshot',
tabId: matrixSnapshot.tabId,
mtxContentModifiedTime: matrixSnapshot.mtxContentModifiedTime,
mtxCountModifiedTime: matrixSnapshot.mtxCountModifiedTime,
mtxDiffCount: matrixSnapshot.diff.length,
pMatrixModifiedTime: matrixSnapshot.pMatrixModifiedTime,
tMatrixModifiedTime: matrixSnapshot.tMatrixModifiedTime,
}, onPolled);
};
var poll = function() {
timer = null;
2015-05-07 10:59:07 +12:00
pollNow();
};
var pollAsync = function() {
if ( timer !== null ) {
return;
}
timer = vAPI.setTimeout(poll, 1414);
2014-10-28 17:38:02 +13:00
};
var unpollAsync = function() {
if ( timer !== null ) {
clearTimeout(timer);
timer = null;
}
};
(function() {
var tabId = matrixSnapshot.tabId;
// If no tab id yet, see if there is one specified in our URL
if ( tabId === undefined ) {
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();
}
}
var snapshotFetched = function(response) {
if ( typeof response === 'object' ) {
matrixSnapshot = response;
}
onMatrixSnapshotReady();
pollAsync();
};
messager.send({
what: 'matrixSnapshot',
tabId: tabId
}, snapshotFetched);
})();
2015-05-07 10:59:07 +12:00
return {
pollNow: pollNow
};
})();
2014-10-20 17:53:13 +13:00
2014-10-18 08:01:09 +13:00
/******************************************************************************/
// Below is UI stuff which is not key to make the menu, so this can
// be done without having to wait for a tab to be bound to the menu.
// We reuse for all cells the one and only cell hotspots.
uDom('#whitelist').on('click', function() {
handleWhitelistFilter(uDom(this));
return false;
});
uDom('#blacklist').on('click', function() {
handleBlacklistFilter(uDom(this));
return false;
});
uDom('#domainOnly').on('click', function() {
toggleCollapseState(uDom(this));
return false;
2014-10-18 08:01:09 +13:00
});
matrixCellHotspots = uDom('#cellHotspots').detach();
uDom('body')
.on('mouseenter', '.matCell', mouseenterMatrixCellHandler)
.on('mouseleave', '.matCell', mouseleaveMatrixCellHandler);
uDom('#scopeKeyGlobal').on('click', selectGlobalScope);
uDom('#scopeKeyDomain').on('click', selectDomainScope);
uDom('#scopeKeySite').on('click', selectSiteScope);
uDom('[id^="mtxSwitch_"]').on('click', toggleMatrixSwitch);
uDom('#buttonPersist').on('click', persistMatrix);
uDom('#buttonRevertScope').on('click', revertMatrix);
uDom('#buttonRevertAll').on('click', revertAll);
uDom('#buttonReload').on('click', buttonReloadHandler);
uDom('.extensionURL').on('click', gotoExtensionURL);
uDom('body').on('click', '.dropdown-menu-button', dropDownMenuShow);
uDom('body').on('click', '.dropdown-menu-capture', dropDownMenuHide);
uDom('#matList').on('click', '.g4Meta', function() {
var collapsed = uDom(this)
.toggleClass('g4Collapsed')
.hasClass('g4Collapsed');
setUISetting('popupHideBlacklisted', collapsed);
2014-10-18 08:01:09 +13:00
});
/******************************************************************************/
})();