mirror of
https://github.com/gorhill/uBlock.git
synced 2024-09-30 06:37:10 +02:00
22022f636f
Related issue: - https://github.com/uBlockOrigin/uBlock-issues/issues/1664 The changes are enough to fulfill the related issue. A new platform has been added in order to allow for building a NodeJS package. From the root of the project: ./tools/make-nodejs This will create new uBlock0.nodejs directory in the ./dist/build directory, which is a valid NodeJS package. From the root of the package, you can try: node test This will instantiate a static network filtering engine, populated by easylist and easyprivacy, which can be used to match network requests by filling the appropriate filtering context object. The test.js file contains code which is typical example of usage of the package. Limitations: the NodeJS package can't execute the WASM versions of the code since the WASM module requires the use of fetch(), which is not available in NodeJS. This is a first pass at modularizing the codebase, and while at it a number of opportunistic small rewrites have also been made. This commit requires the minimum supported version for Chromium and Firefox be raised to 61 and 60 respectively.
684 lines
22 KiB
JavaScript
684 lines
22 KiB
JavaScript
/*******************************************************************************
|
|
|
|
uBlock Origin - a browser extension to block requests.
|
|
Copyright (C) 2015-2018 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/uBlock
|
|
*/
|
|
|
|
/* global uDom */
|
|
|
|
'use strict';
|
|
|
|
/******************************************************************************/
|
|
|
|
import globals from './globals.js';
|
|
|
|
/******************************************************************************/
|
|
|
|
(( ) => {
|
|
|
|
/******************************************************************************/
|
|
|
|
const showdomButton = uDom.nodeFromId('showdom');
|
|
|
|
// Don't bother if the browser is not modern enough.
|
|
if (
|
|
typeof Map === 'undefined' ||
|
|
Map.polyfill ||
|
|
typeof WeakMap === 'undefined'
|
|
) {
|
|
showdomButton.classList.add('disabled');
|
|
return;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
|
|
const logger = globals.logger;
|
|
var inspectorConnectionId;
|
|
var inspectedTabId = 0;
|
|
var inspectedURL = '';
|
|
var inspectedHostname = '';
|
|
var inspector = uDom.nodeFromId('domInspector');
|
|
var domTree = uDom.nodeFromId('domTree');
|
|
var uidGenerator = 1;
|
|
var filterToIdMap = new Map();
|
|
|
|
/******************************************************************************/
|
|
|
|
const messaging = vAPI.messaging;
|
|
|
|
vAPI.MessagingConnection.addListener(function(msg) {
|
|
if ( msg.from !== 'domInspector' || msg.to !== 'loggerUI' ) { return; }
|
|
switch ( msg.what ) {
|
|
case 'connectionBroken':
|
|
if ( inspectorConnectionId === msg.id ) {
|
|
filterToIdMap.clear();
|
|
logger.removeAllChildren(domTree);
|
|
inspectorConnectionId = undefined;
|
|
}
|
|
injectInspector();
|
|
break;
|
|
case 'connectionMessage':
|
|
if ( msg.payload.what === 'domLayoutFull' ) {
|
|
inspectedURL = msg.payload.url;
|
|
inspectedHostname = msg.payload.hostname;
|
|
renderDOMFull(msg.payload);
|
|
} else if ( msg.payload.what === 'domLayoutIncremental' ) {
|
|
renderDOMIncremental(msg.payload);
|
|
}
|
|
break;
|
|
case 'connectionRequested':
|
|
if ( msg.tabId === undefined || msg.tabId !== inspectedTabId ) {
|
|
return;
|
|
}
|
|
filterToIdMap.clear();
|
|
logger.removeAllChildren(domTree);
|
|
inspectorConnectionId = msg.id;
|
|
return true;
|
|
}
|
|
});
|
|
|
|
/******************************************************************************/
|
|
|
|
const nodeFromDomEntry = function(entry) {
|
|
var node, value;
|
|
var li = document.createElement('li');
|
|
li.setAttribute('id', entry.nid);
|
|
// expander/collapser
|
|
li.appendChild(document.createElement('span'));
|
|
// selector
|
|
node = document.createElement('code');
|
|
node.textContent = entry.sel;
|
|
li.appendChild(node);
|
|
// descendant count
|
|
value = entry.cnt || 0;
|
|
node = document.createElement('span');
|
|
node.textContent = value !== 0 ? value.toLocaleString() : '';
|
|
node.setAttribute('data-cnt', value);
|
|
li.appendChild(node);
|
|
// cosmetic filter
|
|
if ( entry.filter === undefined ) {
|
|
return li;
|
|
}
|
|
node = document.createElement('code');
|
|
node.classList.add('filter');
|
|
value = filterToIdMap.get(entry.filter);
|
|
if ( value === undefined ) {
|
|
value = uidGenerator.toString();
|
|
filterToIdMap.set(entry.filter, value);
|
|
uidGenerator += 1;
|
|
}
|
|
node.setAttribute('data-filter-id', value);
|
|
node.textContent = entry.filter;
|
|
li.appendChild(node);
|
|
li.classList.add('isCosmeticHide');
|
|
return li;
|
|
};
|
|
|
|
/******************************************************************************/
|
|
|
|
const appendListItem = function(ul, li) {
|
|
ul.appendChild(li);
|
|
// Ancestor nodes of a node which is affected by a cosmetic filter will
|
|
// be marked as "containing cosmetic filters", for user convenience.
|
|
if ( li.classList.contains('isCosmeticHide') === false ) { return; }
|
|
for (;;) {
|
|
li = li.parentElement.parentElement;
|
|
if ( li === null ) { break; }
|
|
li.classList.add('hasCosmeticHide');
|
|
}
|
|
};
|
|
|
|
/******************************************************************************/
|
|
|
|
const renderDOMFull = function(response) {
|
|
var domTreeParent = domTree.parentElement;
|
|
var ul = domTreeParent.removeChild(domTree);
|
|
logger.removeAllChildren(domTree);
|
|
|
|
filterToIdMap.clear();
|
|
|
|
var lvl = 0;
|
|
var entries = response.layout;
|
|
var n = entries.length;
|
|
var li, entry;
|
|
for ( var i = 0; i < n; i++ ) {
|
|
entry = entries[i];
|
|
if ( entry.lvl === lvl ) {
|
|
li = nodeFromDomEntry(entry);
|
|
appendListItem(ul, li);
|
|
continue;
|
|
}
|
|
if ( entry.lvl > lvl ) {
|
|
ul = document.createElement('ul');
|
|
li.appendChild(ul);
|
|
li.classList.add('branch');
|
|
li = nodeFromDomEntry(entry);
|
|
appendListItem(ul, li);
|
|
lvl = entry.lvl;
|
|
continue;
|
|
}
|
|
// entry.lvl < lvl
|
|
while ( entry.lvl < lvl ) {
|
|
ul = li.parentNode;
|
|
li = ul.parentNode;
|
|
ul = li.parentNode;
|
|
lvl -= 1;
|
|
}
|
|
li = nodeFromDomEntry(entry);
|
|
appendListItem(ul, li);
|
|
}
|
|
while ( ul.parentNode !== null ) {
|
|
ul = ul.parentNode;
|
|
}
|
|
ul.firstElementChild.classList.add('show');
|
|
|
|
domTreeParent.appendChild(domTree);
|
|
};
|
|
|
|
// https://www.youtube.com/watch?v=IDGNA83mxDo
|
|
|
|
/******************************************************************************/
|
|
|
|
const patchIncremental = function(from, delta) {
|
|
var span, cnt;
|
|
var li = from.parentElement.parentElement;
|
|
var patchCosmeticHide = delta >= 0 &&
|
|
from.classList.contains('isCosmeticHide') &&
|
|
li.classList.contains('hasCosmeticHide') === false;
|
|
// Include descendants count when removing a node
|
|
if ( delta < 0 ) {
|
|
delta -= countFromNode(from);
|
|
}
|
|
for ( ; li.localName === 'li'; li = li.parentElement.parentElement ) {
|
|
span = li.children[2];
|
|
if ( delta !== 0 ) {
|
|
cnt = countFromNode(li) + delta;
|
|
span.textContent = cnt !== 0 ? cnt.toLocaleString() : '';
|
|
span.setAttribute('data-cnt', cnt);
|
|
}
|
|
if ( patchCosmeticHide ) {
|
|
li.classList.add('hasCosmeticHide');
|
|
}
|
|
}
|
|
};
|
|
|
|
/******************************************************************************/
|
|
|
|
const renderDOMIncremental = function(response) {
|
|
// Process each journal entry:
|
|
// 1 = node added
|
|
// -1 = node removed
|
|
var journal = response.journal;
|
|
var nodes = new Map(response.nodes);
|
|
var entry, previous, li, ul;
|
|
for ( var i = 0, n = journal.length; i < n; i++ ) {
|
|
entry = journal[i];
|
|
// Remove node
|
|
if ( entry.what === -1 ) {
|
|
li = document.getElementById(entry.nid);
|
|
if ( li === null ) { continue; }
|
|
patchIncremental(li, -1);
|
|
li.parentNode.removeChild(li);
|
|
continue;
|
|
}
|
|
// Modify node
|
|
if ( entry.what === 0 ) {
|
|
// TODO: update selector/filter
|
|
continue;
|
|
}
|
|
// Add node as sibling
|
|
if ( entry.what === 1 && entry.l ) {
|
|
previous = document.getElementById(entry.l);
|
|
// This should not happen
|
|
if ( previous === null ) {
|
|
// throw new Error('No left sibling!?');
|
|
continue;
|
|
}
|
|
ul = previous.parentElement;
|
|
li = nodeFromDomEntry(nodes.get(entry.nid));
|
|
ul.insertBefore(li, previous.nextElementSibling);
|
|
patchIncremental(li, 1);
|
|
continue;
|
|
}
|
|
// Add node as child
|
|
if ( entry.what === 1 && entry.u ) {
|
|
li = document.getElementById(entry.u);
|
|
// This should not happen
|
|
if ( li === null ) {
|
|
// throw new Error('No parent!?');
|
|
continue;
|
|
}
|
|
ul = li.querySelector('ul');
|
|
if ( ul === null ) {
|
|
ul = document.createElement('ul');
|
|
li.appendChild(ul);
|
|
li.classList.add('branch');
|
|
}
|
|
li = nodeFromDomEntry(nodes.get(entry.nid));
|
|
ul.appendChild(li);
|
|
patchIncremental(li, 1);
|
|
continue;
|
|
}
|
|
}
|
|
};
|
|
|
|
// https://www.youtube.com/watch?v=6u2KPtJB9h8
|
|
|
|
/******************************************************************************/
|
|
|
|
const countFromNode = function(li) {
|
|
var span = li.children[2];
|
|
var cnt = parseInt(span.getAttribute('data-cnt'), 10);
|
|
return isNaN(cnt) ? 0 : cnt;
|
|
};
|
|
|
|
/******************************************************************************/
|
|
|
|
const selectorFromNode = function(node) {
|
|
var selector = '';
|
|
var code;
|
|
while ( node !== null ) {
|
|
if ( node.localName === 'li' ) {
|
|
code = node.querySelector('code');
|
|
if ( code !== null ) {
|
|
selector = code.textContent + ' > ' + selector;
|
|
if ( selector.indexOf('#') !== -1 ) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
node = node.parentElement;
|
|
}
|
|
return selector.slice(0, -3);
|
|
};
|
|
|
|
/******************************************************************************/
|
|
|
|
const selectorFromFilter = function(node) {
|
|
while ( node !== null ) {
|
|
if ( node.localName === 'li' ) {
|
|
var code = node.querySelector('code:nth-of-type(2)');
|
|
if ( code !== null ) {
|
|
return code.textContent;
|
|
}
|
|
}
|
|
node = node.parentElement;
|
|
}
|
|
return '';
|
|
};
|
|
|
|
/******************************************************************************/
|
|
|
|
const nidFromNode = function(node) {
|
|
var li = node;
|
|
while ( li !== null ) {
|
|
if ( li.localName === 'li' ) {
|
|
return li.id || '';
|
|
}
|
|
li = li.parentElement;
|
|
}
|
|
return '';
|
|
};
|
|
|
|
/******************************************************************************/
|
|
|
|
const startDialog = (function() {
|
|
let dialog;
|
|
let textarea;
|
|
let hideSelectors = [];
|
|
let unhideSelectors = [];
|
|
let inputTimer;
|
|
|
|
const onInputChanged = (function() {
|
|
const parse = function() {
|
|
inputTimer = undefined;
|
|
hideSelectors = [];
|
|
unhideSelectors = [];
|
|
|
|
const re = /^([^#]*)(#@?#)(.+)$/;
|
|
for ( let line of textarea.value.split(/\s*\n\s*/) ) {
|
|
line = line.trim();
|
|
if ( line === '' || line.charAt(0) === '!' ) { continue; }
|
|
const matches = re.exec(line);
|
|
if ( matches === null || matches.length !== 4 ) { continue; }
|
|
if ( inspectedHostname.lastIndexOf(matches[1]) === -1 ) {
|
|
continue;
|
|
}
|
|
if ( matches[2] === '##' ) {
|
|
hideSelectors.push(matches[3]);
|
|
} else {
|
|
unhideSelectors.push(matches[3]);
|
|
}
|
|
}
|
|
|
|
showCommitted();
|
|
};
|
|
|
|
return function parseAsync() {
|
|
if ( inputTimer === undefined ) {
|
|
inputTimer = vAPI.setTimeout(parse, 743);
|
|
}
|
|
};
|
|
})();
|
|
|
|
const onClicked = function(ev) {
|
|
var target = ev.target;
|
|
|
|
ev.stopPropagation();
|
|
|
|
if ( target.id === 'createCosmeticFilters' ) {
|
|
messaging.send('loggerUI', {
|
|
what: 'createUserFilter',
|
|
filters: textarea.value,
|
|
});
|
|
// Force a reload for the new cosmetic filter(s) to take effect
|
|
messaging.send('loggerUI', {
|
|
what: 'reloadTab',
|
|
tabId: inspectedTabId,
|
|
});
|
|
return stop();
|
|
}
|
|
};
|
|
|
|
const showCommitted = function() {
|
|
vAPI.MessagingConnection.sendTo(inspectorConnectionId, {
|
|
what: 'showCommitted',
|
|
hide: hideSelectors.join(',\n'),
|
|
unhide: unhideSelectors.join(',\n')
|
|
});
|
|
};
|
|
|
|
const showInteractive = function() {
|
|
vAPI.MessagingConnection.sendTo(inspectorConnectionId, {
|
|
what: 'showInteractive',
|
|
hide: hideSelectors.join(',\n'),
|
|
unhide: unhideSelectors.join(',\n')
|
|
});
|
|
};
|
|
|
|
const start = function() {
|
|
dialog = logger.modalDialog.create('#cosmeticFilteringDialog', stop);
|
|
textarea = dialog.querySelector('textarea');
|
|
hideSelectors = [];
|
|
for ( const node of domTree.querySelectorAll('code.off') ) {
|
|
if ( node.classList.contains('filter') ) { continue; }
|
|
hideSelectors.push(selectorFromNode(node));
|
|
}
|
|
const taValue = [];
|
|
for ( const selector of hideSelectors ) {
|
|
taValue.push(inspectedHostname + '##' + selector);
|
|
}
|
|
const ids = new Set();
|
|
for ( const node of domTree.querySelectorAll('code.filter.off') ) {
|
|
const id = node.getAttribute('data-filter-id');
|
|
if ( ids.has(id) ) { continue; }
|
|
ids.add(id);
|
|
unhideSelectors.push(node.textContent);
|
|
taValue.push(inspectedHostname + '#@#' + node.textContent);
|
|
}
|
|
textarea.value = taValue.join('\n');
|
|
textarea.addEventListener('input', onInputChanged);
|
|
dialog.addEventListener('click', onClicked, true);
|
|
showCommitted();
|
|
logger.modalDialog.show();
|
|
};
|
|
|
|
const stop = function() {
|
|
if ( inputTimer !== undefined ) {
|
|
clearTimeout(inputTimer);
|
|
inputTimer = undefined;
|
|
}
|
|
showInteractive();
|
|
textarea.removeEventListener('input', onInputChanged);
|
|
dialog.removeEventListener('click', onClicked, true);
|
|
dialog = undefined;
|
|
textarea = undefined;
|
|
hideSelectors = [];
|
|
unhideSelectors = [];
|
|
};
|
|
|
|
return start;
|
|
})();
|
|
|
|
/******************************************************************************/
|
|
|
|
const onClicked = function(ev) {
|
|
ev.stopPropagation();
|
|
|
|
if ( inspectedTabId === 0 ) { return; }
|
|
|
|
var target = ev.target;
|
|
var parent = target.parentElement;
|
|
|
|
// Expand/collapse branch
|
|
if (
|
|
target.localName === 'span' &&
|
|
parent instanceof HTMLLIElement &&
|
|
parent.classList.contains('branch') &&
|
|
target === parent.firstElementChild
|
|
) {
|
|
var state = parent.classList.toggle('show');
|
|
if ( !state ) {
|
|
for ( var node of parent.querySelectorAll('.branch') ) {
|
|
node.classList.remove('show');
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Not a node or filter
|
|
if ( target.localName !== 'code' ) { return; }
|
|
|
|
// Toggle cosmetic filter
|
|
if ( target.classList.contains('filter') ) {
|
|
vAPI.MessagingConnection.sendTo(inspectorConnectionId, {
|
|
what: 'toggleFilter',
|
|
original: false,
|
|
target: target.classList.toggle('off'),
|
|
selector: selectorFromNode(target),
|
|
filter: selectorFromFilter(target),
|
|
nid: nidFromNode(target)
|
|
});
|
|
uDom('[data-filter-id="' + target.getAttribute('data-filter-id') + '"]', inspector).toggleClass(
|
|
'off',
|
|
target.classList.contains('off')
|
|
);
|
|
}
|
|
// Toggle node
|
|
else {
|
|
vAPI.MessagingConnection.sendTo(inspectorConnectionId, {
|
|
what: 'toggleNodes',
|
|
original: true,
|
|
target: target.classList.toggle('off') === false,
|
|
selector: selectorFromNode(target),
|
|
nid: nidFromNode(target)
|
|
});
|
|
}
|
|
|
|
var cantCreate = domTree.querySelector('.off') === null;
|
|
inspector.querySelector('.permatoolbar .revert').classList.toggle('disabled', cantCreate);
|
|
inspector.querySelector('.permatoolbar .commit').classList.toggle('disabled', cantCreate);
|
|
};
|
|
|
|
/******************************************************************************/
|
|
|
|
const onMouseOver = (function() {
|
|
var mouseoverTarget = null;
|
|
var mouseoverTimer = null;
|
|
|
|
var timerHandler = function() {
|
|
mouseoverTimer = null;
|
|
vAPI.MessagingConnection.sendTo(inspectorConnectionId, {
|
|
what: 'highlightOne',
|
|
selector: selectorFromNode(mouseoverTarget),
|
|
nid: nidFromNode(mouseoverTarget),
|
|
scrollTo: true
|
|
});
|
|
};
|
|
|
|
return function(ev) {
|
|
if ( inspectedTabId === 0 ) { return; }
|
|
// Convenience: skip real-time highlighting if shift key is pressed.
|
|
if ( ev.shiftKey ) { return; }
|
|
// Find closest `li`
|
|
var target = ev.target;
|
|
while ( target !== null ) {
|
|
if ( target.localName === 'li' ) { break; }
|
|
target = target.parentElement;
|
|
}
|
|
if ( target === mouseoverTarget ) { return; }
|
|
mouseoverTarget = target;
|
|
if ( mouseoverTimer === null ) {
|
|
mouseoverTimer = vAPI.setTimeout(timerHandler, 50);
|
|
}
|
|
};
|
|
})();
|
|
|
|
/******************************************************************************/
|
|
|
|
const currentTabId = function() {
|
|
if ( showdomButton.classList.contains('active') === false ) { return 0; }
|
|
return logger.tabIdFromPageSelector();
|
|
};
|
|
|
|
/******************************************************************************/
|
|
|
|
const injectInspector = function() {
|
|
const tabId = currentTabId();
|
|
if ( tabId <= 0 ) { return; }
|
|
inspectedTabId = tabId;
|
|
messaging.send('loggerUI', {
|
|
what: 'scriptlet',
|
|
tabId,
|
|
scriptlet: 'dom-inspector',
|
|
});
|
|
};
|
|
|
|
/******************************************************************************/
|
|
|
|
const shutdownInspector = function() {
|
|
if ( inspectorConnectionId !== undefined ) {
|
|
vAPI.MessagingConnection.disconnectFrom(inspectorConnectionId);
|
|
inspectorConnectionId = undefined;
|
|
}
|
|
logger.removeAllChildren(domTree);
|
|
inspector.classList.remove('vExpanded');
|
|
inspectedTabId = 0;
|
|
};
|
|
|
|
/******************************************************************************/
|
|
|
|
const onTabIdChanged = function() {
|
|
const tabId = currentTabId();
|
|
if ( tabId <= 0 ) {
|
|
return toggleOff();
|
|
}
|
|
if ( inspectedTabId !== tabId ) {
|
|
shutdownInspector();
|
|
injectInspector();
|
|
}
|
|
};
|
|
|
|
/******************************************************************************/
|
|
|
|
const toggleVCompactView = function() {
|
|
var state = inspector.classList.toggle('vExpanded');
|
|
var branches = document.querySelectorAll('#domInspector li.branch');
|
|
for ( var branch of branches ) {
|
|
branch.classList.toggle('show', state);
|
|
}
|
|
};
|
|
|
|
const toggleHCompactView = function() {
|
|
inspector.classList.toggle('hCompact');
|
|
};
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
var toggleHighlightMode = function() {
|
|
vAPI.MessagingConnection.sendTo(inspectorConnectionId, {
|
|
what: 'highlightMode',
|
|
invert: uDom.nodeFromSelector('#domInspector .permatoolbar .highlightMode').classList.toggle('invert')
|
|
});
|
|
};
|
|
*/
|
|
/******************************************************************************/
|
|
|
|
const revert = function() {
|
|
uDom('#domTree .off').removeClass('off');
|
|
vAPI.MessagingConnection.sendTo(
|
|
inspectorConnectionId,
|
|
{ what: 'resetToggledNodes' }
|
|
);
|
|
inspector.querySelector('.permatoolbar .revert').classList.add('disabled');
|
|
inspector.querySelector('.permatoolbar .commit').classList.add('disabled');
|
|
};
|
|
|
|
/******************************************************************************/
|
|
|
|
const toggleOn = function() {
|
|
uDom.nodeFromId('inspectors').classList.add('dom');
|
|
window.addEventListener('beforeunload', toggleOff);
|
|
document.addEventListener('tabIdChanged', onTabIdChanged);
|
|
domTree.addEventListener('click', onClicked, true);
|
|
domTree.addEventListener('mouseover', onMouseOver, true);
|
|
uDom.nodeFromSelector('#domInspector .vCompactToggler').addEventListener('click', toggleVCompactView);
|
|
uDom.nodeFromSelector('#domInspector .hCompactToggler').addEventListener('click', toggleHCompactView);
|
|
//uDom.nodeFromSelector('#domInspector .permatoolbar .highlightMode').addEventListener('click', toggleHighlightMode);
|
|
uDom.nodeFromSelector('#domInspector .permatoolbar .revert').addEventListener('click', revert);
|
|
uDom.nodeFromSelector('#domInspector .permatoolbar .commit').addEventListener('click', startDialog);
|
|
injectInspector();
|
|
};
|
|
|
|
/******************************************************************************/
|
|
|
|
const toggleOff = function() {
|
|
showdomButton.classList.remove('active');
|
|
uDom.nodeFromId('inspectors').classList.remove('dom');
|
|
shutdownInspector();
|
|
window.removeEventListener('beforeunload', toggleOff);
|
|
document.removeEventListener('tabIdChanged', onTabIdChanged);
|
|
domTree.removeEventListener('click', onClicked, true);
|
|
domTree.removeEventListener('mouseover', onMouseOver, true);
|
|
uDom.nodeFromSelector('#domInspector .vCompactToggler').removeEventListener('click', toggleVCompactView);
|
|
uDom.nodeFromSelector('#domInspector .hCompactToggler').removeEventListener('click', toggleHCompactView);
|
|
//uDom.nodeFromSelector('#domInspector .permatoolbar .highlightMode').removeEventListener('click', toggleHighlightMode);
|
|
uDom.nodeFromSelector('#domInspector .permatoolbar .revert').removeEventListener('click', revert);
|
|
uDom.nodeFromSelector('#domInspector .permatoolbar .commit').removeEventListener('click', startDialog);
|
|
inspectedTabId = 0;
|
|
};
|
|
|
|
/******************************************************************************/
|
|
|
|
const toggle = function() {
|
|
if ( showdomButton.classList.toggle('active') ) {
|
|
toggleOn();
|
|
} else {
|
|
toggleOff();
|
|
}
|
|
logger.resize();
|
|
};
|
|
|
|
/******************************************************************************/
|
|
|
|
showdomButton.addEventListener('click', toggle);
|
|
|
|
/******************************************************************************/
|
|
|
|
})();
|