mirror of https://github.com/gorhill/uBlock.git
DOM inspector: incremental rendering when inspected DOM changes
This commit is contained in:
parent
f12bbd4703
commit
f988d74b4d
|
@ -144,8 +144,9 @@ var tabIdFromClassName = function(className) {
|
||||||
var tabSelector = uDom.nodeFromId('pageSelector');
|
var tabSelector = uDom.nodeFromId('pageSelector');
|
||||||
|
|
||||||
var nodeFromDomEntry = function(entry) {
|
var nodeFromDomEntry = function(entry) {
|
||||||
var node;
|
var node, value;
|
||||||
var li = document.createElement('li');
|
var li = document.createElement('li');
|
||||||
|
li.setAttribute('id', entry.nid);
|
||||||
// expander/collapser
|
// expander/collapser
|
||||||
node = document.createElement('span');
|
node = document.createElement('span');
|
||||||
li.appendChild(node);
|
li.appendChild(node);
|
||||||
|
@ -154,11 +155,11 @@ var tabIdFromClassName = function(className) {
|
||||||
node.textContent = entry.sel;
|
node.textContent = entry.sel;
|
||||||
li.appendChild(node);
|
li.appendChild(node);
|
||||||
// descendant count
|
// descendant count
|
||||||
if ( entry.cnt !== 0 ) {
|
value = entry.cnt || 0;
|
||||||
node = document.createElement('span');
|
node = document.createElement('span');
|
||||||
node.textContent = entry.cnt.toLocaleString();
|
node.textContent = value !== 0 ? value.toLocaleString() : '';
|
||||||
|
node.setAttribute('data-cnt', value);
|
||||||
li.appendChild(node);
|
li.appendChild(node);
|
||||||
}
|
|
||||||
// cosmetic filter
|
// cosmetic filter
|
||||||
if ( entry.filter !== undefined ) {
|
if ( entry.filter !== undefined ) {
|
||||||
node = document.createElement('code');
|
node = document.createElement('code');
|
||||||
|
@ -186,10 +187,10 @@ var tabIdFromClassName = function(className) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var renderDOM = function(response) {
|
var renderDOMFull = function(response) {
|
||||||
var ul = document.createElement('ul');
|
var ul = document.createElement('ul');
|
||||||
var lvl = 0;
|
var lvl = 0;
|
||||||
var entries = response;
|
var entries = response.layout;
|
||||||
var n = entries.length;
|
var n = entries.length;
|
||||||
var li, entry;
|
var li, entry;
|
||||||
for ( var i = 0; i < n; i++ ) {
|
for ( var i = 0; i < n; i++ ) {
|
||||||
|
@ -229,6 +230,85 @@ var tabIdFromClassName = function(className) {
|
||||||
inspector.appendChild(ul);
|
inspector.appendChild(ul);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var patchIncremental = function(from, delta) {
|
||||||
|
var span, cnt;
|
||||||
|
var li = from.parentElement.parentElement;
|
||||||
|
var patchCosmeticHide = delta >= 0 &&
|
||||||
|
from.classList.contains('isCosmeticFilter') &&
|
||||||
|
li.classList.contains('hasCosmeticFilter') === false;
|
||||||
|
for ( ; li.localName === 'li'; li = li.parentElement.parentElement ) {
|
||||||
|
span = li.children[2];
|
||||||
|
if ( delta !== 0 ) {
|
||||||
|
cnt = parseInt(span.getAttribute('data-cnt'), 10) + delta;
|
||||||
|
span.textContent = cnt !== 0 ? cnt.toLocaleString() : '';
|
||||||
|
span.setAttribute('data-cnt', cnt);
|
||||||
|
}
|
||||||
|
if ( patchCosmeticHide ) {
|
||||||
|
li.classList.add('hasCosmeticFilter');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var renderDOMIncremental = function(response) {
|
||||||
|
// Process each journal entry:
|
||||||
|
// 1 = node added
|
||||||
|
// -1 = node removed
|
||||||
|
var journal = response.journal;
|
||||||
|
var nodes = 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[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[entry.nid]);
|
||||||
|
ul.appendChild(li);
|
||||||
|
patchIncremental(li, 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
var selectorFromNode = function(node, nth) {
|
var selectorFromNode = function(node, nth) {
|
||||||
var selector = '';
|
var selector = '';
|
||||||
var code;
|
var code;
|
||||||
|
@ -377,13 +457,23 @@ var tabIdFromClassName = function(className) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( response.layout === 'NOCHANGE' ) {
|
switch ( response.status ) {
|
||||||
fetchDOMAsync();
|
case 'full':
|
||||||
return;
|
renderDOMFull(response);
|
||||||
}
|
|
||||||
|
|
||||||
renderDOM(response.layout);
|
|
||||||
fingerprint = response.fingerprint;
|
fingerprint = response.fingerprint;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'incremental':
|
||||||
|
renderDOMIncremental(response);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'nochange':
|
||||||
|
case 'busy':
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
fetchDOMAsync();
|
fetchDOMAsync();
|
||||||
};
|
};
|
||||||
|
|
|
@ -139,6 +139,7 @@ var cssEscape = (function(root) {
|
||||||
|
|
||||||
var localMessager = vAPI.messaging.channel('dom-inspector.js');
|
var localMessager = vAPI.messaging.channel('dom-inspector.js');
|
||||||
|
|
||||||
|
// Highlighter-related
|
||||||
var svgOcean = null;
|
var svgOcean = null;
|
||||||
var svgIslands = null;
|
var svgIslands = null;
|
||||||
var svgRoot = null;
|
var svgRoot = null;
|
||||||
|
@ -149,6 +150,14 @@ var toggledNodes = new Map();
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
// Some kind of fingerprint for the DOM, without incurring too much overhead.
|
||||||
|
|
||||||
|
var domFingerprint = function() {
|
||||||
|
return vAPI.sessionId;
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
var domLayout = (function() {
|
var domLayout = (function() {
|
||||||
var skipTagNames = {
|
var skipTagNames = {
|
||||||
'br': true,
|
'br': true,
|
||||||
|
@ -165,8 +174,20 @@ var domLayout = (function() {
|
||||||
'object': 'data'
|
'object': 'data'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var idGenerator = 0;
|
||||||
|
var nodeToIdMap = new WeakMap(); // No need to iterate
|
||||||
|
|
||||||
|
// This will be used to uniquely identify nodes across process.
|
||||||
|
|
||||||
|
var newNodeId = function(node) {
|
||||||
|
var nid = 'n' + (idGenerator++).toString(36);
|
||||||
|
nodeToIdMap.set(node, nid);
|
||||||
|
return nid;
|
||||||
|
};
|
||||||
|
|
||||||
// Collect all nodes which are directly affected by cosmetic filters: these
|
// Collect all nodes which are directly affected by cosmetic filters: these
|
||||||
// will be reported in the layout data.
|
// will be reported in the layout data.
|
||||||
|
// TODO: take into account cosmetic filters added after the map is build.
|
||||||
|
|
||||||
var nodeToCosmeticFilterMap = (function() {
|
var nodeToCosmeticFilterMap = (function() {
|
||||||
var out = new WeakMap();
|
var out = new WeakMap();
|
||||||
|
@ -189,25 +210,18 @@ var domLayout = (function() {
|
||||||
return out;
|
return out;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var DomRoot = function() {
|
var matchesSelector = (function() {
|
||||||
this.lvl = 0;
|
if ( typeof Element.prototype.matches === 'function' ) {
|
||||||
this.sel = 'body';
|
return 'matches';
|
||||||
var url = window.location.href;
|
|
||||||
var pos = url.indexOf('#');
|
|
||||||
if ( pos !== -1 ) {
|
|
||||||
url = url.slice(0, pos);
|
|
||||||
}
|
}
|
||||||
this.src = url;
|
if ( typeof Element.prototype.mozMatchesSelector === 'function' ) {
|
||||||
this.top = window === window.top;
|
return 'mozMatchesSelector';
|
||||||
this.cnt = 0;
|
}
|
||||||
};
|
if ( typeof Element.prototype.webkitMatchesSelector === 'function' ) {
|
||||||
|
return 'webkitMatchesSelector';
|
||||||
var DomNode = function(level, selector, filter) {
|
}
|
||||||
this.lvl = level;
|
return '';
|
||||||
this.sel = selector;
|
})();
|
||||||
this.cnt = 0;
|
|
||||||
this.filter = filter;
|
|
||||||
};
|
|
||||||
|
|
||||||
var hasManyMatches = function(node, selector) {
|
var hasManyMatches = function(node, selector) {
|
||||||
var fnName = matchesSelector;
|
var fnName = matchesSelector;
|
||||||
|
@ -228,19 +242,6 @@ var domLayout = (function() {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
var matchesSelector = (function() {
|
|
||||||
if ( typeof Element.prototype.matches === 'function' ) {
|
|
||||||
return 'matches';
|
|
||||||
}
|
|
||||||
if ( typeof Element.prototype.mozMatchesSelector === 'function' ) {
|
|
||||||
return 'mozMatchesSelector';
|
|
||||||
}
|
|
||||||
if ( typeof Element.prototype.webkitMatchesSelector === 'function' ) {
|
|
||||||
return 'webkitMatchesSelector';
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
})();
|
|
||||||
|
|
||||||
var selectorFromNode = function(node) {
|
var selectorFromNode = function(node) {
|
||||||
var str, attr, pos, sw, i;
|
var str, attr, pos, sw, i;
|
||||||
var tag = node.localName;
|
var tag = node.localName;
|
||||||
|
@ -290,6 +291,22 @@ var domLayout = (function() {
|
||||||
return selector;
|
return selector;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var DomRoot = function() {
|
||||||
|
this.nid = newNodeId(document.body);
|
||||||
|
this.lvl = 0;
|
||||||
|
this.sel = 'body';
|
||||||
|
this.cnt = 0;
|
||||||
|
this.filter = nodeToCosmeticFilterMap.get(document.body);
|
||||||
|
};
|
||||||
|
|
||||||
|
var DomNode = function(node, level) {
|
||||||
|
this.nid = newNodeId(node);
|
||||||
|
this.lvl = level;
|
||||||
|
this.sel = selectorFromNode(node);
|
||||||
|
this.cnt = 0;
|
||||||
|
this.filter = nodeToCosmeticFilterMap.get(node);
|
||||||
|
};
|
||||||
|
|
||||||
var domNodeFactory = function(level, node) {
|
var domNodeFactory = function(level, node) {
|
||||||
var localName = node.localName;
|
var localName = node.localName;
|
||||||
if ( skipTagNames.hasOwnProperty(localName) ) {
|
if ( skipTagNames.hasOwnProperty(localName) ) {
|
||||||
|
@ -302,15 +319,13 @@ var domLayout = (function() {
|
||||||
if ( level === 0 && localName === 'body' ) {
|
if ( level === 0 && localName === 'body' ) {
|
||||||
return new DomRoot();
|
return new DomRoot();
|
||||||
}
|
}
|
||||||
var selector = selectorFromNode(node);
|
return new DomNode(node, level);
|
||||||
var filter = nodeToCosmeticFilterMap.get(node);
|
|
||||||
return new DomNode(level, selector, filter);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Collect layout data.
|
// Collect layout data.
|
||||||
|
|
||||||
var getLayoutData = function() {
|
var getLayoutData = function() {
|
||||||
var domLayout = [];
|
var layout = [];
|
||||||
var stack = [];
|
var stack = [];
|
||||||
var node = document.body;
|
var node = document.body;
|
||||||
var domNode;
|
var domNode;
|
||||||
|
@ -319,7 +334,7 @@ var domLayout = (function() {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
domNode = domNodeFactory(lvl, node);
|
domNode = domNodeFactory(lvl, node);
|
||||||
if ( domNode !== null ) {
|
if ( domNode !== null ) {
|
||||||
domLayout.push(domNode);
|
layout.push(domNode);
|
||||||
}
|
}
|
||||||
// children
|
// children
|
||||||
if ( node.firstElementChild !== null ) {
|
if ( node.firstElementChild !== null ) {
|
||||||
|
@ -339,19 +354,20 @@ var domLayout = (function() {
|
||||||
}
|
}
|
||||||
node = node.nextElementSibling;
|
node = node.nextElementSibling;
|
||||||
}
|
}
|
||||||
return domLayout;
|
|
||||||
|
return layout;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Descendant count for each node.
|
// Descendant count for each node.
|
||||||
|
|
||||||
var patchLayoutData = function(domLayout) {
|
var patchLayoutData = function(layout) {
|
||||||
var stack = [], ptr;
|
var stack = [], ptr;
|
||||||
var lvl = 0;
|
var lvl = 0;
|
||||||
var domNode, cnt;
|
var domNode, cnt;
|
||||||
var i = domLayout.length;
|
var i = layout.length;
|
||||||
|
|
||||||
while ( i-- ) {
|
while ( i-- ) {
|
||||||
domNode = domLayout[i];
|
domNode = layout[i];
|
||||||
if ( domNode.lvl === lvl ) {
|
if ( domNode.lvl === lvl ) {
|
||||||
stack[ptr] += 1;
|
stack[ptr] += 1;
|
||||||
continue;
|
continue;
|
||||||
|
@ -372,24 +388,211 @@ var domLayout = (function() {
|
||||||
ptr = lvl - 1;
|
ptr = lvl - 1;
|
||||||
stack[ptr] += cnt + 1;
|
stack[ptr] += cnt + 1;
|
||||||
}
|
}
|
||||||
return domLayout;
|
return layout;
|
||||||
};
|
};
|
||||||
|
|
||||||
return function() {
|
// Track and report mutations to the DOM
|
||||||
return patchLayoutData(getLayoutData());
|
|
||||||
|
var journalEntries = [];
|
||||||
|
var journalNodes = Object.create(null);
|
||||||
|
|
||||||
|
var mutationObserver = null;
|
||||||
|
var mutationTimer = null;
|
||||||
|
var addedNodelists = [];
|
||||||
|
var removedNodelist = [];
|
||||||
|
|
||||||
|
var previousElementSiblingId = function(node) {
|
||||||
|
var sibling = node;
|
||||||
|
for (;;) {
|
||||||
|
sibling = sibling.previousElementSibling;
|
||||||
|
if ( sibling === null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if ( skipTagNames.hasOwnProperty(sibling.localName) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return nodeToIdMap.get(sibling);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var journalFromBranch = function(root, added) {
|
||||||
|
var domNode;
|
||||||
|
var node = root.firstElementChild;
|
||||||
|
while ( node !== null ) {
|
||||||
|
domNode = domNodeFactory(undefined, node);
|
||||||
|
if ( domNode !== null ) {
|
||||||
|
journalNodes[domNode.nid] = domNode;
|
||||||
|
added.push(node);
|
||||||
|
}
|
||||||
|
// down
|
||||||
|
if ( node.firstElementChild !== null ) {
|
||||||
|
node = node.firstElementChild;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// right
|
||||||
|
if ( node.nextElementSibling !== null ) {
|
||||||
|
node = node.nextElementSibling;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// up then right
|
||||||
|
for (;;) {
|
||||||
|
if ( node.parentElement === root ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
node = node.parentElement;
|
||||||
|
if ( node.nextElementSibling !== null ) {
|
||||||
|
node = node.nextElementSibling;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var journalFromMutations = function() {
|
||||||
|
mutationTimer = null;
|
||||||
|
if ( mutationObserver === null ) {
|
||||||
|
addedNodelists = [];
|
||||||
|
removedNodelist = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var i, m, nodelist, j, n, node, domNode, nid;
|
||||||
|
|
||||||
|
// This is used to temporarily hold all added nodes, before resolving
|
||||||
|
// their node id and relative position.
|
||||||
|
var added = [];
|
||||||
|
|
||||||
|
for ( i = 0, m = addedNodelists.length; i < m; i++ ) {
|
||||||
|
nodelist = addedNodelists[i];
|
||||||
|
for ( j = 0, n = nodelist.length; j < n; j++ ) {
|
||||||
|
node = nodelist[j];
|
||||||
|
if ( node.nodeType !== 1 ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// I don't think this can ever happen
|
||||||
|
if ( node.parentElement === null ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
domNode = domNodeFactory(undefined, node);
|
||||||
|
if ( domNode !== null ) {
|
||||||
|
journalNodes[domNode.nid] = domNode;
|
||||||
|
added.push(node);
|
||||||
|
}
|
||||||
|
journalFromBranch(node, added);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addedNodelists = [];
|
||||||
|
for ( i = 0, m = removedNodelist.length; i < m; i++ ) {
|
||||||
|
nodelist = removedNodelist[i];
|
||||||
|
for ( j = 0, n = nodelist.length; j < n; j++ ) {
|
||||||
|
node = nodelist[j];
|
||||||
|
if ( node.nodeType !== 1 ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
nid = nodeToIdMap.get(node);
|
||||||
|
if ( nid === undefined ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
journalEntries.push({
|
||||||
|
what: -1,
|
||||||
|
nid: nid
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
removedNodelist = [];
|
||||||
|
for ( i = 0, n = added.length; i < n; i++ ) {
|
||||||
|
node = added[i];
|
||||||
|
journalEntries.push({
|
||||||
|
what: 1,
|
||||||
|
nid: nodeToIdMap.get(node),
|
||||||
|
u: nodeToIdMap.get(node.parentElement),
|
||||||
|
l: previousElementSiblingId(node)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var onMutationObserved = function(mutationRecords) {
|
||||||
|
var record;
|
||||||
|
for ( var i = 0, n = mutationRecords.length; i < n; i++ ) {
|
||||||
|
record = mutationRecords[i];
|
||||||
|
if ( record.addedNodes.length !== 0 ) {
|
||||||
|
addedNodelists.push(record.addedNodes);
|
||||||
|
}
|
||||||
|
if ( record.removedNodes.length !== 0 ) {
|
||||||
|
removedNodelist.push(record.removedNodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( mutationTimer === null ) {
|
||||||
|
mutationTimer = vAPI.setTimeout(journalFromMutations, 1000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
var getLayout = function(fingerprint) {
|
||||||
|
if ( fingerprint !== domFingerprint() && mutationObserver !== null ) {
|
||||||
|
if ( mutationTimer !== null ) {
|
||||||
|
clearTimeout(mutationTimer);
|
||||||
|
mutationTimer = null;
|
||||||
|
}
|
||||||
|
mutationObserver.disconnect();
|
||||||
|
mutationObserver = null;
|
||||||
|
journalEntries = [];
|
||||||
|
journalNodes = Object.create(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
var response = {
|
||||||
|
what: 'domLayout',
|
||||||
|
fingerprint: domFingerprint()
|
||||||
|
};
|
||||||
|
|
||||||
|
// No mutation observer means we need to send full layout
|
||||||
|
if ( mutationObserver === null ) {
|
||||||
|
mutationObserver = new MutationObserver(onMutationObserved);
|
||||||
|
mutationObserver.observe(document.body, {
|
||||||
|
childList: true,
|
||||||
|
subtree: true
|
||||||
|
});
|
||||||
|
response.status = 'full';
|
||||||
|
response.layout = patchLayoutData(getLayoutData());
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Incremental layout
|
||||||
|
if ( journalEntries.length !== 0 ) {
|
||||||
|
response.status = 'incremental';
|
||||||
|
response.journal = journalEntries;
|
||||||
|
response.nodes = journalNodes;
|
||||||
|
journalEntries = [];
|
||||||
|
journalNodes = Object.create(null);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
response.status = 'nochange';
|
||||||
|
return response;
|
||||||
|
};
|
||||||
|
|
||||||
|
var shutdown = function() {
|
||||||
|
if ( mutationTimer !== null ) {
|
||||||
|
clearTimeout(mutationTimer);
|
||||||
|
mutationTimer = null;
|
||||||
|
}
|
||||||
|
if ( mutationObserver !== null ) {
|
||||||
|
mutationObserver.disconnect();
|
||||||
|
mutationObserver = null;
|
||||||
|
}
|
||||||
|
journalEntries = [];
|
||||||
|
journalNodes = Object.create(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
get: getLayout,
|
||||||
|
shutdown: shutdown
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
// Some kind of fingerprint for the DOM, without incurring too much overhead.
|
|
||||||
|
|
||||||
var domFingerprint = function() {
|
|
||||||
return vAPI.sessionId + '{' + document.getElementsByTagName('*').length + '}';
|
|
||||||
};
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
var highlightElements = function(elems, scrollTo) {
|
var highlightElements = function(elems, scrollTo) {
|
||||||
var wv = pickerRoot.contentWindow.innerWidth;
|
var wv = pickerRoot.contentWindow.innerWidth;
|
||||||
var hv = pickerRoot.contentWindow.innerHeight;
|
var hv = pickerRoot.contentWindow.innerHeight;
|
||||||
|
@ -555,6 +758,7 @@ var resetToggledNodes = function() {
|
||||||
|
|
||||||
var shutdown = function() {
|
var shutdown = function() {
|
||||||
resetToggledNodes();
|
resetToggledNodes();
|
||||||
|
domLayout.shutdown();
|
||||||
localMessager.removeListener(onMessage);
|
localMessager.removeListener(onMessage);
|
||||||
localMessager.close();
|
localMessager.close();
|
||||||
localMessager = null;
|
localMessager = null;
|
||||||
|
@ -572,12 +776,7 @@ var onMessage = function(request) {
|
||||||
|
|
||||||
switch ( msg.what ) {
|
switch ( msg.what ) {
|
||||||
case 'domLayout':
|
case 'domLayout':
|
||||||
var fingerprint = domFingerprint();
|
response = domLayout.get(msg.fingerprint);
|
||||||
response = {
|
|
||||||
what: 'domLayout',
|
|
||||||
layout: msg.fingerprint !== fingerprint ? domLayout() : 'NOCHANGE',
|
|
||||||
fingerprint: fingerprint
|
|
||||||
};
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'highlight':
|
case 'highlight':
|
||||||
|
|
Loading…
Reference in New Issue