From 5b7a3c99830abf9bb062ddf83ab5718e3495d102 Mon Sep 17 00:00:00 2001 From: Raymond Hill Date: Fri, 14 Dec 2018 11:01:21 -0500 Subject: [PATCH] fix https://github.com/uBlockOrigin/uBlock-issues/issues/256; add regex support in logger filter field --- platform/chromium/vapi-background.js | 29 +++++- src/js/logger-ui.js | 138 +++++++++++++++------------ src/js/messaging.js | 84 ++++++++++------ src/js/utils.js | 19 +++- 4 files changed, 179 insertions(+), 91 deletions(-) diff --git a/platform/chromium/vapi-background.js b/platform/chromium/vapi-background.js index a4e341bd7..1df622c57 100644 --- a/platform/chromium/vapi-background.js +++ b/platform/chromium/vapi-background.js @@ -482,10 +482,35 @@ vAPI.tabs.open = function(details) { }; // Open in a standalone window + // // https://github.com/uBlockOrigin/uBlock-issues/issues/168#issuecomment-413038191 // Not all platforms support browser.windows API. - if ( details.popup === true && chrome.windows instanceof Object ) { - chrome.windows.create({ url: details.url, type: 'popup' }); + // + // For some reasons, some platforms do not honor the left,top + // position when specified. I found that further calling + // windows.update again with the same position _may_ help. + if ( details.popup === true && browser.windows instanceof Object ) { + const options = { + url: details.url, + type: 'popup', + }; + if ( details.box instanceof Object ) { + Object.assign(options, details.box); + } + browser.windows.create(options, win => { + if ( win instanceof Object === false ) { return; } + if ( details.box instanceof Object === false ) { return; } + if ( + win.left === details.box.left && + win.top === details.box.top + ) { + return; + } + browser.windows.update(win.id, { + left: details.box.left, + top: details.box.top + }); + }); return; } diff --git a/src/js/logger-ui.js b/src/js/logger-ui.js index 0c1e2bb07..96421a5d7 100644 --- a/src/js/logger-ui.js +++ b/src/js/logger-ui.js @@ -30,11 +30,8 @@ /******************************************************************************/ const messaging = vAPI.messaging; - -const logger = self.logger = { - ownerId: Date.now() -}; - +const logger = self.logger = { ownerId: Date.now() }; +let popupLoggerBox; let activeTabId; /******************************************************************************/ @@ -576,15 +573,27 @@ const onLogBufferRead = function(response) { const readLogBuffer = function() { if ( logger.ownerId === undefined ) { return; } - vAPI.messaging.send( - 'loggerUI', - { - what: 'readAll', - ownerId: logger.ownerId, - tabIdsToken: allTabIdsToken, - }, - onLogBufferRead - ); + const msg = { + what: 'readAll', + ownerId: logger.ownerId, + tabIdsToken: allTabIdsToken, + }; + if ( + popupLoggerBox instanceof Object && + ( + self.screenX !== popupLoggerBox.x || + self.screenY !== popupLoggerBox.y || + self.outerWidth !== popupLoggerBox.w || + self.outerHeight !== popupLoggerBox.h + ) + ) { + popupLoggerBox.x = self.screenX; + popupLoggerBox.y = self.screenY; + popupLoggerBox.w = self.outerWidth; + popupLoggerBox.h = self.outerHeight; + msg.popupLoggerBoxChanged = true; + } + vAPI.messaging.send('loggerUI', msg, onLogBufferRead); }; const readLogBufferAsync = function() { @@ -1398,42 +1407,50 @@ var reverseLookupManager = (function() { /******************************************************************************/ const rowFilterer = (function() { - let filters = []; + const filters = []; const parseInput = function() { - filters = []; + filters.length = 0; - var rawPart, hardBeg, hardEnd; - var raw = uDom('#filterInput').val().trim(); - var rawParts = raw.split(/\s+/); - var reStr, reStrs = [], not = false; - var n = rawParts.length; - for ( var i = 0; i < n; i++ ) { - rawPart = rawParts[i]; + const rawParts = uDom('#filterInput').val().trim().split(/\s+/); + const n = rawParts.length; + const reStrs = []; + let not = false; + for ( let i = 0; i < n; i++ ) { + let rawPart = rawParts[i]; if ( rawPart.charAt(0) === '!' ) { if ( reStrs.length === 0 ) { not = true; } rawPart = rawPart.slice(1); } - hardBeg = rawPart.charAt(0) === '|'; - if ( hardBeg ) { - rawPart = rawPart.slice(1); + let reStr = ''; + if ( rawPart.startsWith('/') && rawPart.endsWith('/') ) { + reStr = rawPart.slice(1, -1); + try { + new RegExp(reStr); + } catch(ex) { + reStr = ''; + } } - hardEnd = rawPart.slice(-1) === '|'; - if ( hardEnd ) { - rawPart = rawPart.slice(0, -1); - } - if ( rawPart === '' ) { - continue; - } - // https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions - reStr = rawPart.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - if ( hardBeg ) { - reStr = '(?:^|\\s)' + reStr; - } - if ( hardEnd ) { - reStr += '(?:\\s|$)'; + if ( reStr === '' ) { + const hardBeg = rawPart.startsWith('|'); + if ( hardBeg ) { + rawPart = rawPart.slice(1); + } + const hardEnd = rawPart.endsWith('|'); + if ( hardEnd ) { + rawPart = rawPart.slice(0, -1); + } + if ( rawPart === '' ) { continue; } + // https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions + reStr = rawPart.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + if ( hardBeg ) { + reStr = '(?:^|\\s)' + reStr; + } + if ( hardEnd ) { + reStr += '(?:\\s|$)'; + } } reStrs.push(reStr); if ( i < (n - 1) && rawParts[i + 1] === '||' ) { @@ -1445,22 +1462,18 @@ const rowFilterer = (function() { re: new RegExp(reStr, 'i'), r: !not }); - reStrs = []; + reStrs.length = 0; not = false; } }; const filterOne = function(tr, clean) { - const ff = filters; - const fcount = ff.length; - if ( fcount === 0 && clean === true ) { - return; - } + if ( filters.length === 0 && clean === true ) { return; } // do not filter out doc boundaries, they help separate important // section of log. const cl = tr.classList; if ( cl.contains('maindoc') ) { return; } - if ( fcount === 0 ) { + if ( filters.length === 0 ) { cl.remove('f'); return; } @@ -1470,8 +1483,7 @@ const rowFilterer = (function() { // if... // positive filter expression = there must one hit on any field // negative filter expression = there must be no hit on all fields - for ( let i = 0; i < fcount; i++ ) { - let f = ff[i]; + for ( const f of filters ) { let hit = !f.r; for ( let j = 1; j < ccount; j++ ) { if ( f.re.test(cc[j].textContent) ) { @@ -1493,23 +1505,20 @@ const rowFilterer = (function() { uDom('#netInspector tr').removeClass('f'); return; } - var tbody = document.querySelector('#netInspector tbody'); - var rows = tbody.rows; - var i = rows.length; - while ( i-- ) { - filterOne(rows[i]); + for ( const row of document.querySelector('#netInspector tbody').rows ) { + filterOne(row); } }; const onFilterChangedAsync = (function() { - var timer = null; - var commit = function() { - timer = null; + let timer; + const commit = ( ) => { + timer = undefined; parseInput(); filterAll(); }; return function() { - if ( timer !== null ) { + if ( timer !== undefined ) { clearTimeout(timer); } timer = vAPI.setTimeout(commit, 750); @@ -1536,7 +1545,7 @@ const rowFilterer = (function() { /******************************************************************************/ -var toJunkyard = function(trs) { +const toJunkyard = function(trs) { trs.remove(); var i = trs.length; while ( i-- ) { @@ -1725,6 +1734,17 @@ uDom('#netInspector').on('click', 'tr.cat_net > td:nth-of-type(3)', netFiltering pageSelectorFromURLHash(); window.addEventListener('hashchange', pageSelectorFromURLHash); +if ( self.location.search.includes('popup=1') ) { + window.addEventListener('load', ( ) => { + popupLoggerBox = { + x: self.screenX, + y: self.screenY, + w: self.outerWidth, + h: self.outerHeight, + }; + }, { once: true }); +} + /******************************************************************************/ })(); diff --git a/src/js/messaging.js b/src/js/messaging.js index f242809e4..8cacd0edf 100644 --- a/src/js/messaging.js +++ b/src/js/messaging.js @@ -1124,13 +1124,13 @@ vAPI.messaging.listen('dashboard', onMessage); /******************************************************************************/ -var µb = µBlock, - extensionOriginURL = vAPI.getURL(''); +const µb = µBlock; +const extensionOriginURL = vAPI.getURL(''); /******************************************************************************/ -var getLoggerData = function(details, activeTabId, callback) { - let response = { +const getLoggerData = function(details, activeTabId, callback) { + const response = { colorBlind: µb.userSettings.colorBlindFriendly, entries: µb.logger.readAll(details.ownerId), maxEntries: µb.userSettings.requestLogMaxEntries, @@ -1138,16 +1138,16 @@ var getLoggerData = function(details, activeTabId, callback) { tabIdsToken: µb.pageStoresToken }; if ( µb.pageStoresToken !== details.tabIdsToken ) { - let tabIds = new Map(); - for ( let entry of µb.pageStores ) { - let pageStore = entry[1]; + const tabIds = new Map(); + for ( const entry of µb.pageStores ) { + const pageStore = entry[1]; if ( pageStore.rawURL.startsWith(extensionOriginURL) ) { continue; } tabIds.set(entry[0], pageStore.title); } response.tabIds = Array.from(tabIds); } if ( activeTabId ) { - let pageStore = µb.pageStoreFromTabId(activeTabId); + const pageStore = µb.pageStoreFromTabId(activeTabId); if ( pageStore === null || pageStore.rawURL.startsWith(extensionOriginURL) @@ -1155,43 +1155,71 @@ var getLoggerData = function(details, activeTabId, callback) { response.activeTabId = undefined; } } + if ( details.popupLoggerBoxChanged && browser.windows instanceof Object ) { + browser.tabs.query( + { url: vAPI.getURL('/logger-ui.html?popup=1') }, + tabs => { + if ( Array.isArray(tabs) === false ) { return; } + if ( tabs.length === 0 ) { return; } + browser.windows.get( + tabs[0].windowId, + { windowTypes: [ 'popup' ] }, + win => { + if ( win instanceof Object === false ) { return; } + vAPI.localStorage.setItem( + 'popupLoggerBox', + JSON.stringify({ + left: win.left, + top: win.top, + width: win.width, + height: win.height, + }) + ); + } + ); + } + ); + } callback(response); }; /******************************************************************************/ -var getURLFilteringData = function(details) { - var colors = {}; - var response = { +const getURLFilteringData = function(details) { + const colors = {}; + const response = { dirty: false, colors: colors }; - var suf = µb.sessionURLFiltering; - var puf = µb.permanentURLFiltering; - var urls = details.urls, - context = details.context, - type = details.type; - var url, colorEntry; - var i = urls.length; - while ( i-- ) { - url = urls[i]; - colorEntry = colors[url] = { r: 0, own: false }; + const suf = µb.sessionURLFiltering; + const puf = µb.permanentURLFiltering; + const urls = details.urls; + const context = details.context; + const type = details.type; + for ( const url of urls ) { + const colorEntry = colors[url] = { r: 0, own: false }; if ( suf.evaluateZ(context, url, type).r !== 0 ) { colorEntry.r = suf.r; - colorEntry.own = suf.r !== 0 && suf.context === context && suf.url === url && suf.type === type; - } - if ( response.dirty ) { - continue; + colorEntry.own = suf.r !== 0 && + suf.context === context && + suf.url === url && + suf.type === type; } + if ( response.dirty ) { continue; } puf.evaluateZ(context, url, type); - response.dirty = colorEntry.own !== (puf.r !== 0 && puf.context === context && puf.url === url && puf.type === type); + response.dirty = colorEntry.own !== ( + puf.r !== 0 && + puf.context === context && + puf.url === url && + puf.type === type + ); } return response; }; /******************************************************************************/ -var onMessage = function(request, sender, callback) { +const onMessage = function(request, sender, callback) { // Async switch ( request.what ) { case 'readAll': @@ -1212,7 +1240,7 @@ var onMessage = function(request, sender, callback) { } // Sync - var response; + let response; switch ( request.what ) { case 'releaseView': diff --git a/src/js/utils.js b/src/js/utils.js index 7b889238f..e5d166f58 100644 --- a/src/js/utils.js +++ b/src/js/utils.js @@ -1,7 +1,7 @@ /******************************************************************************* uBlock Origin - a browser extension to block requests. - Copyright (C) 2014-2018 Raymond Hill + Copyright (C) 2014-present 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 @@ -365,6 +365,21 @@ ); } details.popup = this.userSettings.alwaysDetachLogger; + if ( details.popup ) { + const url = new URL(vAPI.getURL(details.url)); + url.searchParams.set('popup', '1'); + details.url = url.href; + let popupLoggerBox; + try { + popupLoggerBox = JSON.parse( + vAPI.localStorage.getItem('popupLoggerBox') + ); + } catch(ex) { + } + if ( popupLoggerBox !== undefined ) { + details.box = popupLoggerBox; + } + } } vAPI.tabs.open(details); }; @@ -478,4 +493,4 @@ µBlock.orphanizeString = function(s) { return JSON.parse(JSON.stringify(s)); -}; \ No newline at end of file +};