mirror of
https://github.com/gorhill/uMatrix.git
synced 2024-06-01 18:10:17 +12:00
extremely early draft of matrix integration within the logger
This commit is contained in:
parent
b518ab5573
commit
6f786635f4
|
@ -103,7 +103,6 @@ vAPI.noTabId = '-1';
|
|||
|
||||
vAPI.tabs.registerListeners = function() {
|
||||
var onNavigationClient = this.onNavigation || noopFunc;
|
||||
var onPopupClient = this.onPopup || noopFunc;
|
||||
var onUpdatedClient = this.onUpdated || noopFunc;
|
||||
var onClosedClient = this.onClosed || noopFunc;
|
||||
|
||||
|
@ -114,59 +113,6 @@ vAPI.tabs.registerListeners = function() {
|
|||
// onDOMContentLoaded ->
|
||||
// onCompleted
|
||||
|
||||
var popupCandidates = Object.create(null);
|
||||
|
||||
var PopupCandidate = function(details) {
|
||||
this.targetTabId = details.tabId;
|
||||
this.openerTabId = details.sourceTabId;
|
||||
this.targetURL = details.url;
|
||||
this.selfDestructionTimer = null;
|
||||
};
|
||||
|
||||
PopupCandidate.prototype.selfDestruct = function() {
|
||||
if ( this.selfDestructionTimer !== null ) {
|
||||
clearTimeout(this.selfDestructionTimer);
|
||||
}
|
||||
delete popupCandidates[this.targetTabId];
|
||||
};
|
||||
|
||||
PopupCandidate.prototype.launchSelfDestruction = function() {
|
||||
if ( this.selfDestructionTimer !== null ) {
|
||||
clearTimeout(this.selfDestructionTimer);
|
||||
}
|
||||
this.selfDestructionTimer = setTimeout(this.selfDestruct.bind(this), 10000);
|
||||
};
|
||||
|
||||
var popupCandidateCreate = function(details) {
|
||||
var popup = popupCandidates[details.tabId];
|
||||
// This really should not happen...
|
||||
if ( popup !== undefined ) {
|
||||
return;
|
||||
}
|
||||
popup = popupCandidates[details.tabId] = new PopupCandidate(details);
|
||||
return popup;
|
||||
};
|
||||
|
||||
var popupCandidateTest = function(details) {
|
||||
var popup = popupCandidates[details.tabId];
|
||||
if ( popup === undefined ) {
|
||||
return;
|
||||
}
|
||||
popup.targetURL = details.url;
|
||||
if ( onPopupClient(popup) !== true ) {
|
||||
return;
|
||||
}
|
||||
popup.selfDestruct();
|
||||
return true;
|
||||
};
|
||||
|
||||
var popupCandidateDestroy = function(details) {
|
||||
var popup = popupCandidates[details.tabId];
|
||||
if ( popup instanceof PopupCandidate ) {
|
||||
popup.launchSelfDestruction();
|
||||
}
|
||||
};
|
||||
|
||||
// The chrome.webRequest.onBeforeRequest() won't be called for everything
|
||||
// else than `http`/`https`. Thus, in such case, we will bind the tab as
|
||||
// early as possible in order to increase the likelihood of a context
|
||||
|
@ -176,30 +122,17 @@ vAPI.tabs.registerListeners = function() {
|
|||
var reGoodForWebRequestAPI = /^https?:\/\//;
|
||||
|
||||
var onCreatedNavigationTarget = function(details) {
|
||||
details.tabId = details.tabId.toString();
|
||||
//console.debug('onCreatedNavigationTarget: popup candidate tab id %d = "%s"', details.tabId, details.url);
|
||||
if ( reGoodForWebRequestAPI.test(details.url) === false ) {
|
||||
details.frameId = 0;
|
||||
onNavigationClient(details);
|
||||
}
|
||||
popupCandidateCreate(details);
|
||||
popupCandidateTest(details);
|
||||
};
|
||||
|
||||
var onBeforeNavigate = function(details) {
|
||||
if ( details.frameId !== 0 ) {
|
||||
//console.debug('onCreatedNavigationTarget: tab id %d = "%s"', details.tabId, details.url);
|
||||
if ( reGoodForWebRequestAPI.test(details.url) ) {
|
||||
return;
|
||||
}
|
||||
//console.debug('onBeforeNavigate: popup candidate tab id %d = "%s"', details.tabId, details.url);
|
||||
details.tabId = details.tabId.toString();
|
||||
popupCandidateTest(details);
|
||||
details.frameId = 0;
|
||||
onNavigationClient(details);
|
||||
};
|
||||
|
||||
var onUpdated = function(tabId, changeInfo, tab) {
|
||||
tabId = tabId.toString();
|
||||
if ( changeInfo.url && popupCandidateTest({ tabId: tabId, url: changeInfo.url }) ) {
|
||||
return;
|
||||
}
|
||||
onUpdatedClient(tabId, changeInfo, tab);
|
||||
};
|
||||
|
||||
|
@ -209,11 +142,7 @@ vAPI.tabs.registerListeners = function() {
|
|||
}
|
||||
details.tabId = details.tabId.toString();
|
||||
onNavigationClient(details);
|
||||
//console.debug('onCommitted: popup candidate tab id %d = "%s"', details.tabId, details.url);
|
||||
if ( popupCandidateTest(details) === true ) {
|
||||
return;
|
||||
}
|
||||
popupCandidateDestroy(details);
|
||||
//console.debug('onCommitted: tab id %d = "%s"', details.tabId, details.url);
|
||||
};
|
||||
|
||||
var onClosed = function(tabId) {
|
||||
|
@ -221,7 +150,6 @@ vAPI.tabs.registerListeners = function() {
|
|||
};
|
||||
|
||||
chrome.webNavigation.onCreatedNavigationTarget.addListener(onCreatedNavigationTarget);
|
||||
chrome.webNavigation.onBeforeNavigate.addListener(onBeforeNavigate);
|
||||
chrome.webNavigation.onCommitted.addListener(onCommitted);
|
||||
chrome.tabs.onUpdated.addListener(onUpdated);
|
||||
chrome.tabs.onRemoved.addListener(onClosed);
|
||||
|
|
|
@ -390,7 +390,6 @@ vAPI.tabs = {};
|
|||
|
||||
vAPI.tabs.registerListeners = function() {
|
||||
// onClosed - handled in tabWatcher.onTabClose
|
||||
// onPopup - handled in httpObserver.handlePopup
|
||||
|
||||
for ( var win of this.getWindows() ) {
|
||||
windowWatcher.onReady.call(win);
|
||||
|
@ -1101,24 +1100,6 @@ var httpObserver = {
|
|||
);
|
||||
},
|
||||
|
||||
handlePopup: function(URI, tabId, sourceTabId) {
|
||||
if ( !sourceTabId ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !URI.schemeIs('http') && !URI.schemeIs('https') ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var result = vAPI.tabs.onPopup({
|
||||
targetTabId: tabId,
|
||||
openerTabId: sourceTabId,
|
||||
targetURL: URI.asciiSpec
|
||||
});
|
||||
|
||||
return result === true;
|
||||
},
|
||||
|
||||
handleRequest: function(channel, URI, details) {
|
||||
var type = this.typeMap[details.type] || 'other';
|
||||
var result;
|
||||
|
@ -1297,11 +1278,6 @@ var httpObserver = {
|
|||
|
||||
var channelData = oldChannel.getProperty(this.REQDATAKEY);
|
||||
|
||||
if ( this.handlePopup(URI, channelData[3], channelData[2]) ) {
|
||||
result = this.ABORT;
|
||||
return;
|
||||
}
|
||||
|
||||
var details = {
|
||||
frameId: channelData[0],
|
||||
parentFrameId: channelData[1],
|
||||
|
@ -1345,34 +1321,6 @@ vAPI.net.registerListeners = function() {
|
|||
var details = e.data;
|
||||
var tabId = vAPI.tabs.getTabId(e.target);
|
||||
var sourceTabId = null;
|
||||
|
||||
// Popup candidate
|
||||
if ( details.openerURL ) {
|
||||
for ( var tab of vAPI.tabs.getAllSync() ) {
|
||||
var URI = getBrowserForTab(tab).currentURI;
|
||||
|
||||
// Probably isn't the best method to identify the source tab
|
||||
if ( URI.spec !== details.openerURL ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sourceTabId = vAPI.tabs.getTabId(tab);
|
||||
|
||||
if ( sourceTabId === tabId ) {
|
||||
sourceTabId = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
URI = Services.io.newURI(details.url, null, null);
|
||||
|
||||
if ( httpObserver.handlePopup(URI, tabId, sourceTabId) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var lastRequest = httpObserver.lastRequest;
|
||||
lastRequest[1] = lastRequest[0];
|
||||
lastRequest[0] = {
|
||||
|
|
|
@ -21,6 +21,7 @@ body {
|
|||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 10;
|
||||
}
|
||||
#toolbar .button {
|
||||
background-color: white;
|
||||
|
@ -35,6 +36,12 @@ body {
|
|||
#toolbar .button:hover {
|
||||
background-color: #eee;
|
||||
}
|
||||
body #compactViewToggler.button:before {
|
||||
content: '\f102';
|
||||
}
|
||||
body.compactView #compactViewToggler.button:before {
|
||||
content: '\f103';
|
||||
}
|
||||
body.filterOff #toolbar #filterButton {
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
@ -48,73 +55,154 @@ input:focus {
|
|||
background-color: #ffe;
|
||||
}
|
||||
#content {
|
||||
font: 13px sans-serif;
|
||||
margin-top: 40px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#content table {
|
||||
border: 0;
|
||||
border-collapse: collapse;
|
||||
direction: ltr;
|
||||
font: 12px monospace;
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
}
|
||||
#content table > colgroup > col:nth-of-type(1) {
|
||||
width: 6em;
|
||||
}
|
||||
#content table > colgroup > col:nth-of-type(2) {
|
||||
width: 3em;
|
||||
}
|
||||
#content table > colgroup > col:nth-of-type(3) {
|
||||
width: 3em;
|
||||
}
|
||||
#content table > colgroup > col:nth-of-type(4) {
|
||||
width: 8em;
|
||||
}
|
||||
#content table > colgroup > col:nth-of-type(5) {
|
||||
width: calc(100% - 20em);
|
||||
}
|
||||
#content table tr {
|
||||
background-color: #fafafa;
|
||||
color: #444;
|
||||
}
|
||||
#content table tr:nth-of-type(2n+1) {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
#content table tr.cat_info {
|
||||
color: #00f;
|
||||
}
|
||||
#content table tr.blocked {
|
||||
color: #f00;
|
||||
}
|
||||
#content table tr:nth-of-type(2n+1) {
|
||||
background-color: #eee;
|
||||
}
|
||||
#content table tr.doc {
|
||||
background-color: #666;
|
||||
color: white;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
body:not(.filterOff) #content table tr.hidden {
|
||||
display: none;
|
||||
}
|
||||
#content table tr td {
|
||||
|
||||
body #content td {
|
||||
border: 1px solid #ccc;
|
||||
border-top: none;
|
||||
min-width: 0.5em;
|
||||
padding: 3px;
|
||||
vertical-align: top;
|
||||
}
|
||||
#content table tr.doc > td {
|
||||
border: 0;
|
||||
}
|
||||
#content table tr td:nth-of-type(1) {
|
||||
text-align: center;
|
||||
white-space: pre;
|
||||
width: 8em;
|
||||
}
|
||||
#content table tr td:nth-of-type(2) {
|
||||
width: 1em;
|
||||
}
|
||||
#content table tr td:nth-of-type(3) {
|
||||
white-space: pre;
|
||||
width: 2em;
|
||||
}
|
||||
#content table tr td:nth-of-type(4) {
|
||||
white-space: pre;
|
||||
width: 8em;
|
||||
}
|
||||
#content table tr td:nth-of-type(5) {
|
||||
border-right: none;
|
||||
white-space: normal;
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
#content table tr td {
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
#content table tr td:first-of-type {
|
||||
border-left: none;
|
||||
}
|
||||
#content table tr td:last-of-type {
|
||||
border-right: none;
|
||||
}
|
||||
body.compactView #content td {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#content table tr td:nth-of-type(1) {
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
#content table tr td:nth-of-type(2) {
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
#content table tr.tab_bts > td:nth-of-type(2):before {
|
||||
content: '\f070';
|
||||
font: 1em FontAwesome;
|
||||
}
|
||||
#content table tr > td[colspan="3"]:nth-of-type(3) {
|
||||
white-space: normal;
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
#content table tr.cat_net td:nth-of-type(2) {
|
||||
cursor: zoom-in;
|
||||
}
|
||||
#content table tr.cat_net td:nth-of-type(3) {
|
||||
font: 12px monospace;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
#content table tr.cat_net td:nth-of-type(5) {
|
||||
}
|
||||
#content table tr.cat_net td:nth-of-type(5) > span > span {
|
||||
opacity: 0.6;
|
||||
}
|
||||
#content table tr.cat_net td:nth-of-type(5) > span > b {
|
||||
font-weight: bold;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#popupContainer {
|
||||
background: #444;
|
||||
border: 1px solid gray;
|
||||
cursor: -webkit-grab;
|
||||
cursor: grab;
|
||||
display: none;
|
||||
overflow: hidden;
|
||||
position: fixed;
|
||||
z-index: 200;
|
||||
}
|
||||
#popupContainer.show {
|
||||
display: block;
|
||||
}
|
||||
#popupContainer > iframe {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
margin: 1.5em 0 0 0;
|
||||
width: 100%;
|
||||
}
|
||||
#focusOverlay {
|
||||
bottom: 0;
|
||||
cursor: not-allowed;
|
||||
display: none;
|
||||
left: 0;
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
#popupContainer.show ~ #focusOverlay {
|
||||
display: block;
|
||||
}
|
||||
#movingOverlay {
|
||||
bottom: 0;
|
||||
display: none;
|
||||
left: 0;
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 0;
|
||||
z-index: 300;
|
||||
}
|
||||
#popupContainer.moving ~ #movingOverlay {
|
||||
cursor: -webkit-grabbing;
|
||||
cursor: grabbing;
|
||||
display: block;
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ return {
|
|||
displayTextSize: '13px',
|
||||
externalHostsFiles: '',
|
||||
iconBadgeEnabled: true,
|
||||
maxLoggedRequests: 50,
|
||||
maxLoggedRequests: 2000,
|
||||
popupCollapseDomains: false,
|
||||
popupCollapseSpecificDomains: {},
|
||||
popupHideBlacklisted: false,
|
||||
|
|
|
@ -381,7 +381,7 @@ var nodesAddedHandler = function(nodeList, summary) {
|
|||
|
||||
case 'script':
|
||||
// https://github.com/gorhill/httpswitchboard/issues/252
|
||||
// Do not count µMatrix's own script tags, they are not required
|
||||
// Do not count uMatrix's own script tags, they are not required
|
||||
// to "unbreak" a web page
|
||||
if ( typeof node.id === 'string' && node.id.lastIndexOf('uMatrix-', 0) === 0 ) {
|
||||
break;
|
||||
|
@ -404,22 +404,6 @@ var nodesAddedHandler = function(nodeList, summary) {
|
|||
summary.mustReport = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'object':
|
||||
src = (node.data || '').trim();
|
||||
if ( src !== '' ) {
|
||||
summary.pluginSources[src] = true;
|
||||
summary.mustReport = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'embed':
|
||||
src = (node.src || '').trim();
|
||||
if ( src !== '' ) {
|
||||
summary.pluginSources[src] = true;
|
||||
summary.mustReport = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -435,7 +419,6 @@ var nodeListsAddedHandler = function(nodeLists) {
|
|||
what: 'contentScriptSummary',
|
||||
locationURL: window.location.href,
|
||||
scriptSources: {}, // to avoid duplicates
|
||||
pluginSources: {}, // to avoid duplicates
|
||||
mustReport: false
|
||||
};
|
||||
while ( i-- ) {
|
||||
|
@ -458,14 +441,13 @@ var nodeListsAddedHandler = function(nodeLists) {
|
|||
what: 'contentScriptSummary',
|
||||
locationURL: window.location.href,
|
||||
scriptSources: {}, // to avoid duplicates
|
||||
pluginSources: {}, // to avoid duplicates
|
||||
mustReport: true
|
||||
};
|
||||
// https://github.com/gorhill/httpswitchboard/issues/25
|
||||
// &
|
||||
// Looks for inline javascript also in at least one a[href] element.
|
||||
// https://github.com/gorhill/httpswitchboard/issues/131
|
||||
nodesAddedHandler(document.querySelectorAll('a[href^="javascript:"],embed,object,script'), summary);
|
||||
nodesAddedHandler(document.querySelectorAll('a[href^="javascript:"],script'), summary);
|
||||
|
||||
//console.debug('contentscript-end.js > firstObservationHandler(): found %d script tags in "%s"', Object.keys(summary.scriptSources).length, window.location.href);
|
||||
|
||||
|
|
|
@ -224,22 +224,22 @@ var recordPageCookie = function(pageStore, cookieKey) {
|
|||
}
|
||||
|
||||
var cookieEntry = cookieDict[cookieKey];
|
||||
var block = µm.mustBlock(pageStore.pageHostname, cookieEntry.hostname, 'cookie');
|
||||
var pageHostname = pageStore.pageHostname;
|
||||
var block = µm.mustBlock(pageHostname, cookieEntry.hostname, 'cookie');
|
||||
|
||||
cookieLogEntryBuilder[0] = cookieURLFromCookieEntry(cookieEntry);
|
||||
cookieLogEntryBuilder[2] = cookieEntry.session ? 'session' : 'persistent';
|
||||
cookieLogEntryBuilder[4] = encodeURIComponent(cookieEntry.name);
|
||||
|
||||
var cookieURL = cookieLogEntryBuilder.join('');
|
||||
|
||||
// rhill 2013-11-20:
|
||||
// https://github.com/gorhill/httpswitchboard/issues/60
|
||||
// Need to URL-encode cookie name
|
||||
pageStore.recordRequest(
|
||||
'cookie',
|
||||
cookieLogEntryBuilder.join(''),
|
||||
block
|
||||
);
|
||||
pageStore.recordRequest('cookie', cookieURL, block);
|
||||
µm.logger.writeOne(pageStore.tabId, 'net', pageHostname, cookieURL, 'cookie', block);
|
||||
|
||||
cookieEntry.usedOn[pageStore.pageHostname] = true;
|
||||
cookieEntry.usedOn[pageHostname] = true;
|
||||
|
||||
// rhill 2013-11-21:
|
||||
// https://github.com/gorhill/httpswitchboard/issues/65
|
||||
|
|
|
@ -134,17 +134,7 @@
|
|||
}
|
||||
|
||||
// Blocked by matrix filtering?
|
||||
if ( this.mustBlock(srcHostname, desHostname, type) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Cookies are not really requests, but are conveniently treated
|
||||
// as such from matrix filtering point of view only.
|
||||
if ( type === 'cookie' ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
return this.mustBlock(srcHostname, desHostname, type);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
var messager = vAPI.messaging.channel('logger-ui.js');
|
||||
|
||||
var inspectedTabId = '';
|
||||
var maxEntries = 0;
|
||||
var doc = document;
|
||||
var body = doc.body;
|
||||
var tbody = doc.querySelector('#content tbody');
|
||||
|
@ -43,7 +42,9 @@ var trJunkyard = [];
|
|||
var tdJunkyard = [];
|
||||
var firstVarDataCol = 2; // currently, column 2 (0-based index)
|
||||
var lastVarDataIndex = 3; // currently, d0-d3
|
||||
var maxEntries = 5000;
|
||||
var noTabId = '';
|
||||
var popupTabId;
|
||||
|
||||
var prettyRequestTypes = {
|
||||
'main_frame': 'doc',
|
||||
|
@ -53,13 +54,57 @@ var prettyRequestTypes = {
|
|||
};
|
||||
|
||||
var timeOptions = {
|
||||
month: 'short',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit'
|
||||
second: '2-digit',
|
||||
hour12: false
|
||||
};
|
||||
|
||||
var dateOptions = {
|
||||
month: 'short',
|
||||
day: '2-digit'
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var escapeHTML = function(s) {
|
||||
return s.replace(reEscapeLeftBracket, '<')
|
||||
.replace(reEscapeRightBracket, '>');
|
||||
};
|
||||
|
||||
var reEscapeLeftBracket = /</g;
|
||||
var reEscapeRightBracket = />/g;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Emphasize hostname in URL, as this is what matters in uMatrix's rules.
|
||||
|
||||
var nodeFromURL = function(url) {
|
||||
var hnbeg = url.indexOf('://');
|
||||
if ( hnbeg === -1 ) {
|
||||
return document.createTextNode(url);
|
||||
}
|
||||
hnbeg += 3;
|
||||
|
||||
var hnend = url.indexOf('/', hnbeg);
|
||||
if ( hnend === -1 ) {
|
||||
hnend = url.slice(hnbeg).search(/\?#/);
|
||||
if ( hnend !== -1 ) {
|
||||
hnend += hnbeg;
|
||||
} else {
|
||||
hnend = url.length;
|
||||
}
|
||||
}
|
||||
|
||||
var node = renderedURLTemplate.cloneNode(true);
|
||||
node.childNodes[0].textContent = url.slice(0, hnbeg);
|
||||
node.childNodes[1].textContent = url.slice(hnbeg, hnend);
|
||||
node.childNodes[2].textContent = url.slice(hnend);
|
||||
return node;
|
||||
};
|
||||
|
||||
var renderedURLTemplate = document.querySelector('#renderedURLTemplate > span');
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var createCellAt = function(tr, index) {
|
||||
|
@ -82,7 +127,7 @@ var createCellAt = function(tr, index) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var createRow = function(entry) {
|
||||
var createRow = function(layout) {
|
||||
var tr = trJunkyard.pop();
|
||||
if ( tr ) {
|
||||
tr.className = '';
|
||||
|
@ -98,7 +143,7 @@ var createRow = function(entry) {
|
|||
if ( i === lastVarDataIndex ) {
|
||||
break;
|
||||
}
|
||||
if ( entry['d' + i] === undefined ) {
|
||||
if ( layout.charAt(i) !== '1' ) {
|
||||
span += 1;
|
||||
} else {
|
||||
if ( span !== 1 ) {
|
||||
|
@ -122,7 +167,7 @@ var createRow = function(entry) {
|
|||
/******************************************************************************/
|
||||
|
||||
var createGap = function(url) {
|
||||
var tr = createRow({ d0: '' });
|
||||
var tr = createRow('1');
|
||||
tr.classList.add('doc');
|
||||
tr.cells[firstVarDataCol].textContent = url;
|
||||
tbody.insertBefore(tr, tbody.firstChild);
|
||||
|
@ -131,8 +176,43 @@ var createGap = function(url) {
|
|||
/******************************************************************************/
|
||||
|
||||
var renderLogEntry = function(entry) {
|
||||
var tr;
|
||||
var fvdc = firstVarDataCol;
|
||||
var tr = createRow(entry);
|
||||
|
||||
switch ( entry.cat ) {
|
||||
case 'error':
|
||||
case 'info':
|
||||
tr = createRow('1');
|
||||
tr.cells[fvdc].textContent = entry.d0;
|
||||
break;
|
||||
|
||||
case 'net':
|
||||
tr = createRow('111');
|
||||
// If the request is that of a root frame, insert a gap in the table
|
||||
// in order to visually separate entries for different documents.
|
||||
if ( entry.d2 === 'doc' ) {
|
||||
createGap(entry.d1);
|
||||
}
|
||||
if ( entry.d3 ) {
|
||||
tr.classList.add('blocked');
|
||||
tr.cells[fvdc].textContent = '---';
|
||||
} else {
|
||||
tr.cells[fvdc].textContent = '';
|
||||
}
|
||||
tr.cells[fvdc+1].textContent = (prettyRequestTypes[entry.d2] || entry.d2);
|
||||
tr.cells[fvdc+2].appendChild(nodeFromURL(entry.d1));
|
||||
break;
|
||||
|
||||
default:
|
||||
tr = createRow('1');
|
||||
tr.cells[fvdc].textContent = entry.d0;
|
||||
break;
|
||||
}
|
||||
|
||||
// Fields common to all rows.
|
||||
var time = new Date(entry.tstamp);
|
||||
tr.cells[0].textContent = time.toLocaleTimeString('fullwide', timeOptions);
|
||||
tr.cells[0].title = time.toLocaleDateString('fullwide', dateOptions);
|
||||
|
||||
if ( entry.tab === noTabId ) {
|
||||
tr.classList.add('tab_bts');
|
||||
|
@ -143,36 +223,6 @@ var renderLogEntry = function(entry) {
|
|||
tr.classList.add('cat_' + entry.cat);
|
||||
}
|
||||
|
||||
var time = new Date(entry.tstamp);
|
||||
tr.cells[0].textContent = time.toLocaleString('fullwide', timeOptions);
|
||||
|
||||
switch ( entry.cat ) {
|
||||
case 'error':
|
||||
case 'info':
|
||||
tr.cells[fvdc].textContent = entry.d0;
|
||||
break;
|
||||
|
||||
case 'net':
|
||||
// If the request is that of a root frame, insert a gap in the table
|
||||
// in order to visually separate entries for different documents.
|
||||
if ( entry.d1 === 'doc' ) {
|
||||
createGap(entry.d2);
|
||||
}
|
||||
if ( entry.d0 ) {
|
||||
tr.classList.add('blocked');
|
||||
tr.cells[fvdc].textContent = '---';
|
||||
} else {
|
||||
tr.cells[fvdc].textContent = '';
|
||||
}
|
||||
tr.cells[fvdc+1].textContent = (prettyRequestTypes[entry.d1] || entry.d1) + '\t';
|
||||
tr.cells[fvdc+2].textContent = entry.d2 + '\t';
|
||||
break;
|
||||
|
||||
default:
|
||||
tr.cells[fvdc].textContent = entry.d0;
|
||||
break;
|
||||
}
|
||||
|
||||
tbody.insertBefore(tr, tbody.firstChild);
|
||||
};
|
||||
|
||||
|
@ -225,9 +275,9 @@ var renderLogBuffer = function(response) {
|
|||
|
||||
var truncateLog = function(size) {
|
||||
if ( size === 0 ) {
|
||||
size = 25000;
|
||||
size = 5000;
|
||||
}
|
||||
size = Math.min(size, 25000);
|
||||
size = Math.min(size, 5000);
|
||||
var tr;
|
||||
while ( tbody.childElementCount > size ) {
|
||||
tr = tbody.lastElementChild;
|
||||
|
@ -238,6 +288,10 @@ var truncateLog = function(size) {
|
|||
/******************************************************************************/
|
||||
|
||||
var onBufferRead = function(response) {
|
||||
if ( response.maxLoggedRequests !== maxEntries ) {
|
||||
maxEntries = response.maxLoggedRequests;
|
||||
uDom('#maxEntries').val(maxEntries || '');
|
||||
}
|
||||
renderLogBuffer(response);
|
||||
setTimeout(readLogBuffer, 1000);
|
||||
};
|
||||
|
@ -264,12 +318,148 @@ var clearBuffer = function() {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var reloadTab = function() {
|
||||
messager.send({ what: 'reloadTab', tabId: inspectedTabId });
|
||||
var toggleCompactView = function() {
|
||||
body.classList.toggle(
|
||||
'compactView',
|
||||
body.classList.contains('compactView') === false
|
||||
);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var togglePopup = (function() {
|
||||
var container = null;
|
||||
var movingOverlay = null;
|
||||
var popup = null;
|
||||
var popupObserver = null;
|
||||
var style = null;
|
||||
var styleTemplate = 'tr:not(.tab_{{tabId}}) { opacity: 0.1; }';
|
||||
var dx, dy;
|
||||
|
||||
var moveTo = function(ev) {
|
||||
container.style.left = (ev.clientX + dx) + 'px';
|
||||
container.style.top = (ev.clientY + dy) + 'px';
|
||||
};
|
||||
|
||||
var onMouseMove = function(ev) {
|
||||
moveTo(ev);
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
};
|
||||
|
||||
var onMouseUp = function(ev) {
|
||||
moveTo(ev);
|
||||
movingOverlay.removeEventListener('mouseup', onMouseUp);
|
||||
movingOverlay.removeEventListener('mousemove', onMouseMove);
|
||||
movingOverlay = null;
|
||||
container.classList.remove('moving');
|
||||
var rect = container.getBoundingClientRect();
|
||||
vAPI.localStorage.setItem('popupLastPosition', JSON.stringify({
|
||||
x: rect.left,
|
||||
y: rect.top
|
||||
}));
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
};
|
||||
|
||||
var onMove = function(ev) {
|
||||
container.classList.add('moving');
|
||||
var rect = container.getBoundingClientRect();
|
||||
dx = rect.left - ev.clientX;
|
||||
dy = rect.top - ev.clientY;
|
||||
movingOverlay = document.getElementById('movingOverlay');
|
||||
movingOverlay.addEventListener('mousemove', onMouseMove, true);
|
||||
movingOverlay.addEventListener('mouseup', onMouseUp, true);
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
};
|
||||
|
||||
var resizePopup = function() {
|
||||
var popupBody = popup.contentWindow.document.body;
|
||||
if ( popupBody.clientWidth !== 0 && container.clientWidth !== popupBody.clientWidth ) {
|
||||
container.style.width = popupBody.clientWidth + 'px';
|
||||
}
|
||||
if ( popupBody.clientHeight !== 0 && popup.clientHeight !== popupBody.clientHeight ) {
|
||||
popup.style.height = popupBody.clientHeight + 'px';
|
||||
}
|
||||
};
|
||||
|
||||
var onLoad = function() {
|
||||
resizePopup();
|
||||
popupObserver.observe(popup.contentDocument.body, {
|
||||
subtree: true,
|
||||
attributes: true
|
||||
});
|
||||
};
|
||||
|
||||
var toggleOn = function(td) {
|
||||
var tr = td.parentNode;
|
||||
var matches = tr.className.match(/(?:^| )tab_([^ ]+)/);
|
||||
if ( matches === null ) {
|
||||
return;
|
||||
}
|
||||
var tabId = matches[1];
|
||||
if ( tabId === 'bts' ) {
|
||||
tabId = noTabId;
|
||||
}
|
||||
|
||||
// Use last position if one is defined
|
||||
var x, y;
|
||||
var json = vAPI.localStorage.getItem('popupLastPosition');
|
||||
if ( json ) {
|
||||
try {
|
||||
var popupLastPosition = JSON.parse(json);
|
||||
x = popupLastPosition.x;
|
||||
y = popupLastPosition.y;
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
}
|
||||
// Fall back to cell position if no position defined
|
||||
if ( x === undefined ) {
|
||||
var rect = td.getBoundingClientRect();
|
||||
x = rect.left;
|
||||
y = rect.bottom;
|
||||
}
|
||||
container = document.getElementById('popupContainer');
|
||||
container.style.left = x + 'px';
|
||||
container.style.top = y + 'px';
|
||||
container.addEventListener('mousedown', onMove);
|
||||
popup = container.querySelector('iframe');
|
||||
popup.setAttribute('src', 'popup.html?tabId=' + tabId);
|
||||
popup.addEventListener('load', onLoad);
|
||||
popupObserver = new MutationObserver(resizePopup);
|
||||
style = document.querySelector('#content > style');
|
||||
style.textContent = styleTemplate.replace('{{tabId}}', tabId);
|
||||
container.classList.add('show');
|
||||
popupTabId = tabId;
|
||||
};
|
||||
|
||||
var toggleOff = function() {
|
||||
style.textContent = '';
|
||||
style = null;
|
||||
popupObserver.disconnect();
|
||||
popupObserver = null;
|
||||
popup.removeEventListener('load', onLoad);
|
||||
popup.setAttribute('src', '');
|
||||
popup = null;
|
||||
container.classList.remove('show');
|
||||
container.removeEventListener('mousedown', onMove);
|
||||
container = null;
|
||||
popupTabId = undefined;
|
||||
};
|
||||
|
||||
return function(ev) {
|
||||
if ( popupTabId !== undefined ) {
|
||||
toggleOff();
|
||||
} else {
|
||||
toggleOn(ev.target);
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var onMaxEntriesChanged = function() {
|
||||
var raw = uDom(this).val();
|
||||
try {
|
||||
|
@ -283,7 +473,7 @@ var onMaxEntriesChanged = function() {
|
|||
|
||||
messager.send({
|
||||
what: 'userSettings',
|
||||
name: 'requestLogMaxEntries',
|
||||
name: 'maxLoggedRequests',
|
||||
value: maxEntries
|
||||
});
|
||||
|
||||
|
@ -299,17 +489,13 @@ uDom.onLoad(function() {
|
|||
inspectedTabId = matches[1];
|
||||
}
|
||||
|
||||
var onSettingsReady = function(settings) {
|
||||
maxEntries = settings.requestLogMaxEntries || 0;
|
||||
uDom('#maxEntries').val(maxEntries || '');
|
||||
};
|
||||
messager.send({ what: 'getUserSettings' }, onSettingsReady);
|
||||
|
||||
readLogBuffer();
|
||||
|
||||
uDom('#reload').on('click', reloadTab);
|
||||
uDom('#compactViewToggler').on('click', toggleCompactView);
|
||||
uDom('#clear').on('click', clearBuffer);
|
||||
uDom('#maxEntries').on('change', onMaxEntriesChanged);
|
||||
uDom('#content table').on('click', 'tr.cat_net > td:nth-of-type(2)', togglePopup);
|
||||
uDom('#focusOverlay').on('click', togglePopup);
|
||||
});
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -269,11 +269,13 @@ var matrixSnapshot = function(tabId, details) {
|
|||
/******************************************************************************/
|
||||
|
||||
var matrixSnapshotFromTabId = function(details, callback) {
|
||||
// Specific tab id requested?
|
||||
if ( details.tabId ) {
|
||||
callback(matrixSnapshot(details.tabId, details));
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise use tab id of current tab
|
||||
vAPI.tabs.get(null, function(tab) {
|
||||
callback(matrixSnapshot(tab.id, details));
|
||||
});
|
||||
|
@ -373,6 +375,7 @@ var contentScriptSummaryHandler = function(tabId, details) {
|
|||
}
|
||||
var pageStore = µm.pageStoreFromTabId(tabId);
|
||||
var pageURL = pageStore.pageUrl;
|
||||
var pageHostname = pageStore.pageHostname;
|
||||
var µmuri = µm.URI.set(details.locationURL);
|
||||
var frameURL = µmuri.normalizedURI();
|
||||
var frameHostname = µmuri.hostname;
|
||||
|
@ -380,7 +383,7 @@ var contentScriptSummaryHandler = function(tabId, details) {
|
|||
|
||||
// https://github.com/gorhill/httpswitchboard/issues/333
|
||||
// Look-up here whether inline scripting is blocked for the frame.
|
||||
var inlineScriptBlocked = µm.mustBlock(µm.scopeFromURL(pageURL), frameHostname, 'script');
|
||||
var inlineScriptBlocked = µm.mustBlock(pageHostname, frameHostname, 'script');
|
||||
|
||||
// scripts
|
||||
// https://github.com/gorhill/httpswitchboard/issues/25
|
||||
|
@ -394,23 +397,8 @@ var contentScriptSummaryHandler = function(tabId, details) {
|
|||
url = frameURL + '{inline_script}';
|
||||
}
|
||||
r = µm.filterRequest(pageURL, 'script', url);
|
||||
pageStore.recordRequest('script', url, r !== false, r);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: as of 2014-05-26, not sure this is needed anymore, since µMatrix
|
||||
// no longer uses chrome.contentSettings API (I think that was the reason
|
||||
// this code was put in).
|
||||
// plugins
|
||||
// https://github.com/gorhill/httpswitchboard/issues/25
|
||||
if ( pageStore ) {
|
||||
urls = details.pluginSources;
|
||||
for ( url in urls ) {
|
||||
if ( !urls.hasOwnProperty(url) ) {
|
||||
continue;
|
||||
}
|
||||
r = µm.filterRequest(pageURL, 'plugin', url);
|
||||
pageStore.recordRequest('plugin', url, r !== false, r);
|
||||
pageStore.recordRequest('script', url, r !== false);
|
||||
µm.logger.writeOne(tabId, 'net', pageHostname, url, 'script', r);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -974,8 +962,9 @@ var onMessage = function(request, sender, callback) {
|
|||
case 'readMany':
|
||||
response = {
|
||||
colorBlind: false,
|
||||
noTabId: vAPI.noTabId,
|
||||
entries: µm.logger.readAll(request.tabId)
|
||||
entries: µm.logger.readAll(request.tabId),
|
||||
maxLoggedRequests: µm.userSettings.maxLoggedRequests,
|
||||
noTabId: vAPI.noTabId
|
||||
};
|
||||
break;
|
||||
|
||||
|
|
|
@ -385,8 +385,6 @@ PageStore.prototype.recordRequest = function(type, url, block) {
|
|||
this.perLoadAllowedRequestCount++;
|
||||
}
|
||||
|
||||
µm.logger.writeOne(this.tabId, 'net', block ? '---' : '', type, url);
|
||||
|
||||
if ( !this.requests.createEntryIfNotExists(url, type, block) ) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1177,9 +1177,19 @@ var onMatrixSnapshotReady = function(response) {
|
|||
/******************************************************************************/
|
||||
|
||||
var queryMatrixSnapshot = function(callback) {
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
var request = {
|
||||
what: 'matrixSnapshot',
|
||||
tabId: matrixSnapshot.tabId,
|
||||
tabId: tabId,
|
||||
tabURL: matrixSnapshot.url
|
||||
};
|
||||
var snapshotReceived = function(response) {
|
||||
|
|
|
@ -406,6 +406,11 @@
|
|||
|
||||
µMatrix.assetUpdatedHandler = function(details) {
|
||||
var path = details.path || '';
|
||||
|
||||
if ( path !== '' ) {
|
||||
this.logger.writeOne('', 'info', 'asset updated: ' + path);
|
||||
}
|
||||
|
||||
if ( this.liveHostsFiles.hasOwnProperty(path) === false ) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -607,9 +607,11 @@ vAPI.tabs.registerListeners();
|
|||
|
||||
µm.recordFromTabId = function(tabId, type, url, blocked) {
|
||||
var pageStore = this.pageStoreFromTabId(tabId);
|
||||
if ( pageStore ) {
|
||||
pageStore.recordRequest(type, url, blocked);
|
||||
if ( pageStore === null ) {
|
||||
return;
|
||||
}
|
||||
pageStore.recordRequest(type, url, blocked);
|
||||
this.logger.writeOne(tabId, 'net', pageStore.pageHostname, url, type, blocked);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -40,17 +40,18 @@ var onBeforeRootFrameRequestHandler = function(details) {
|
|||
µm.tabContextManager.push(tabId, requestURL);
|
||||
|
||||
var tabContext = µm.tabContextManager.mustLookup(tabId);
|
||||
var rootHostname = tabContext.rootHostname;
|
||||
var pageStore = µm.bindTabToPageStats(tabId);
|
||||
|
||||
// Disallow request as per matrix?
|
||||
var block = µm.mustBlock(tabContext.rootHostname, details.hostname, 'doc');
|
||||
var block = µm.mustBlock(rootHostname, details.hostname, 'doc');
|
||||
|
||||
pageStore.recordRequest('doc', requestURL, block);
|
||||
µm.logger.writeOne(tabId, 'net', rootHostname, requestURL, 'doc', block);
|
||||
|
||||
// Not blocked
|
||||
if ( !block ) {
|
||||
// rhill 2013-11-07: Senseless to do this for behind-the-scene requests.
|
||||
// rhill 2013-12-03: Do this here only for root frames.
|
||||
µm.cookieHunter.recordPageCookies(pageStore);
|
||||
return;
|
||||
}
|
||||
|
@ -114,20 +115,21 @@ var onBeforeRequestHandler = function(details) {
|
|||
// https://github.com/gorhill/httpswitchboard/issues/91#issuecomment-37180275
|
||||
var tabContext = µm.tabContextManager.mustLookup(details.tabId);
|
||||
var tabId = tabContext.tabId;
|
||||
var rootHostname = tabContext.rootHostname;
|
||||
|
||||
// Enforce strict secure connection?
|
||||
var block = false;
|
||||
if (
|
||||
tabContext.secure &&
|
||||
µm.URI.isSecureScheme(requestScheme) === false &&
|
||||
µm.tMatrix.evaluateSwitchZ('https-strict', tabContext.rootHostname)
|
||||
µm.tMatrix.evaluateSwitchZ('https-strict', rootHostname)
|
||||
) {
|
||||
block = true;
|
||||
}
|
||||
|
||||
// Disallow request as per temporary matrix?
|
||||
if ( block === false ) {
|
||||
block = µm.mustBlock(tabContext.rootHostname, details.hostname, requestType);
|
||||
block = µm.mustBlock(rootHostname, details.hostname, requestType);
|
||||
}
|
||||
|
||||
// Record request.
|
||||
|
@ -136,8 +138,9 @@ var onBeforeRequestHandler = function(details) {
|
|||
// processing has already been performed, and that a synthetic URL has
|
||||
// been constructed for logging purpose. Use this synthetic URL if
|
||||
// it is available.
|
||||
var pageStore = µm.mustPageStoreFromTabId(tabContext.tabId);
|
||||
var pageStore = µm.mustPageStoreFromTabId(tabId);
|
||||
pageStore.recordRequest(requestType, requestURL, block);
|
||||
µm.logger.writeOne(tabId, 'net', rootHostname, requestURL, requestType, block);
|
||||
|
||||
// Allowed?
|
||||
if ( !block ) {
|
||||
|
@ -198,6 +201,7 @@ var onBeforeSendHeadersHandler = function(details) {
|
|||
if ( linkAuditor !== '' ) {
|
||||
var block = µm.userSettings.processHyperlinkAuditing;
|
||||
pageStore.recordRequest('other', requestURL + '{Ping-To:' + linkAuditor + '}', block);
|
||||
µm.logger.writeOne(tabId, 'net', '', requestURL, 'ping', block);
|
||||
if ( block ) {
|
||||
µm.hyperlinkAuditingFoiledCounter += 1;
|
||||
return { 'cancel': true };
|
||||
|
@ -293,7 +297,8 @@ var onMainDocHeadersReceived = function(details) {
|
|||
|
||||
// console.debug('onMainDocHeadersReceived()> "%s": %o', requestURL, details);
|
||||
|
||||
var blockScript = µm.mustBlock(tabContext.rootHostname, tabContext.rootHostname, 'script');
|
||||
var rootHostname = tabContext.rootHostname;
|
||||
var blockScript = µm.mustBlock(rootHostname, rootHostname, 'script');
|
||||
|
||||
// https://github.com/gorhill/httpswitchboard/issues/181
|
||||
var pageStore = µm.pageStoreFromTabId(tabId);
|
||||
|
@ -305,7 +310,7 @@ var onMainDocHeadersReceived = function(details) {
|
|||
return;
|
||||
}
|
||||
|
||||
µm.logger.writeOne(tabId, 'net', '---', 'inline-script', requestURL);
|
||||
µm.logger.writeOne(tabId, 'net', rootHostname, requestURL + '{inline_script}', 'script', true);
|
||||
|
||||
// If javascript not allowed, say so through a `Content-Security-Policy` directive.
|
||||
details.responseHeaders.push({
|
||||
|
@ -356,7 +361,7 @@ var onSubDocHeadersReceived = function(details) {
|
|||
|
||||
// console.debug('onSubDocHeadersReceived()> FRAME CSP "%s": %o, scope="%s"', details.url, details, pageURL);
|
||||
|
||||
µm.logger.writeOne(tabId, 'net', '---', 'inline-script', details.url);
|
||||
µm.logger.writeOne(tabId, 'net', tabContext.rootHostname, details.url + '{inline_script}', 'script', true);
|
||||
|
||||
// If javascript not allowed, say so through a `Content-Security-Policy` directive.
|
||||
details.responseHeaders.push({
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*******************************************************************************
|
||||
|
||||
µMatrix - a Chromium browser extension to black/white list requests.
|
||||
Copyright (C) 2014 Raymond Hill
|
||||
uMatrix - a Chromium browser extension to black/white list requests.
|
||||
Copyright (C) 2014-2015 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
|
||||
|
@ -60,6 +60,7 @@ var userAgentSpoofer = function(force) {
|
|||
if ( uaStr === '' ) {
|
||||
µm.userAgentReplaceStr = userAgentRandomPicker();
|
||||
µm.userAgentReplaceStrBirth = Date.now();
|
||||
µm.logger.writeOne('', 'info', 'spoofing user agent with: ' + µm.userAgentReplaceStr);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -6,20 +6,38 @@
|
|||
<link rel="stylesheet" type="text/css" href="css/logger-ui.css">
|
||||
<title>uMatrix log</title>
|
||||
</head>
|
||||
<body>
|
||||
<body class="compactView">
|
||||
|
||||
<div id="toolbar">
|
||||
<span id="reload" class="button fa"></span>
|
||||
<span id="compactViewToggler" class="button fa"></span>
|
||||
<span id="clear" class="button fa"></span>
|
||||
<span id="filterButton" class="button fa"></span><input id="filterExpression" type="text" placeholder="logFilterPrompt">
|
||||
<input id="maxEntries" type="text" size="5" title="logMaxEntriesTip">
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
<table><tbody></tbody></table>
|
||||
<style></style>
|
||||
<table>
|
||||
<colgroup><col><col><col><col><col></colgroup>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="popupContainer">
|
||||
<iframe src></iframe>
|
||||
</div>
|
||||
<div id="focusOverlay"></div>
|
||||
<div id="movingOverlay"></div>
|
||||
|
||||
<div style="display: none;">
|
||||
<div id="renderedURLTemplate"><span><span></span><b></b><span></span></span></div>
|
||||
</div>
|
||||
|
||||
<script src="js/vapi-common.js"></script>
|
||||
<script src="js/vapi-client.js"></script>
|
||||
<script src="js/udom.js"></script>
|
||||
<script src="js/i18n.js"></script>
|
||||
<script src="js/logger-ui.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
Loading…
Reference in a new issue