Compare commits
61 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
9a57758425 | 5 years ago |
|
|
64a911333f | 5 years ago |
|
|
300c482314 | 5 years ago |
|
|
ad456600ed | 5 years ago |
|
|
a5a9104e77 | 5 years ago |
|
|
9140e3392d | 5 years ago |
|
|
06b6ca01f1 | 5 years ago |
|
|
1c45aa35a3 | 5 years ago |
|
|
c3fd99a692 | 5 years ago |
|
|
122e5ca082 | 5 years ago |
|
|
088eea918b | 5 years ago |
|
|
e4fd3a0e93 | 5 years ago |
|
|
af770ebeb8 | 5 years ago |
|
|
1cc436b779 | 5 years ago |
|
|
b2f09f89b5 | 5 years ago |
|
|
e9274d6e30 | 5 years ago |
|
|
eca5ca3f32 | 5 years ago |
|
|
bda7383bc8 | 5 years ago |
|
|
7562a3d697 | 5 years ago |
|
|
954d827934 | 5 years ago |
|
|
e7899435fe | 5 years ago |
|
|
93edb4aca0 | 5 years ago |
|
|
c9ddc9d5d0 | 5 years ago |
|
|
0bcb7669e7 | 6 years ago |
|
|
89b7e026c3 | 6 years ago |
|
|
ba0dfe5d9b | 6 years ago |
|
|
57eb9fc150 | 6 years ago |
|
|
e0800f89df | 6 years ago |
|
|
b26b3bb960 | 6 years ago |
|
|
2d8e32c61b | 6 years ago |
|
|
41133dffd2 | 6 years ago |
|
|
a1ec20423c | 6 years ago |
|
|
e3ebfdfba4 | 6 years ago |
|
|
43cd137fff | 6 years ago |
|
|
a697ce0be9 | 6 years ago |
|
|
b75500eff4 | 6 years ago |
|
|
3f4425d9db | 6 years ago |
|
|
f8c82add03 | 6 years ago |
|
|
a78a6465b0 | 6 years ago |
|
|
ae7d450827 | 6 years ago |
|
|
c908ae5210 | 6 years ago |
|
|
ea688f3942 | 6 years ago |
|
|
8a39b0e171 | 6 years ago |
|
|
5c06fed370 | 6 years ago |
|
|
035f3f53a2 | 6 years ago |
|
|
17430ded93 | 6 years ago |
|
|
b8e62f0c55 | 6 years ago |
|
|
e800756163 | 6 years ago |
|
|
0190fdaf3d | 6 years ago |
|
|
0db579da97 | 6 years ago |
|
|
e5cf0d4684 | 6 years ago |
|
|
a2f213492e | 6 years ago |
|
|
a9f32a475f | 6 years ago |
|
|
cb9934f67a | 6 years ago |
|
|
e7140262f2 | 6 years ago |
|
|
a9bcc70a2b | 6 years ago |
|
|
2936d73911 | 6 years ago |
|
|
df4a403473 | 6 years ago |
|
|
d993b8442a | 6 years ago |
|
|
5aab1fb00b | 6 years ago |
|
|
9b292304d3 | 6 years ago |
@ -1,9 +0,0 @@
|
|||||||
<--
|
|
||||||
|
|
||||||
Do not open issue here.
|
|
||||||
|
|
||||||
The official issue tracker for uMatrix is at:
|
|
||||||
|
|
||||||
https://github.com/uBlockOrigin/uMatrix-issues/issues
|
|
||||||
|
|
||||||
-->
|
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
Steps to reproduce the behavior:
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. Scroll down to '....'
|
||||||
|
4. See error
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
|
**Browser (please complete the following information):**
|
||||||
|
- OS: [e.g. MacOS, Linux]
|
||||||
|
- Browser [e.g. Firefox]
|
||||||
|
- Version [e.g. 80.0.1]
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context about the problem here.
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Is your feature request related to a problem? Please describe.**
|
||||||
|
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||||
|
|
||||||
|
**Describe the solution you'd like**
|
||||||
|
A clear and concise description of what you want to happen.
|
||||||
|
|
||||||
|
**Describe alternatives you've considered**
|
||||||
|
A clear and concise description of any alternative solutions or features you've considered.
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context or screenshots about the feature request here.
|
||||||
@ -1 +1 @@
|
|||||||
1.4.0
|
1.5.0.0
|
||||||
|
|||||||
@ -0,0 +1,39 @@
|
|||||||
|
## Building nuTensor
|
||||||
|
|
||||||
|
### Requirements
|
||||||
|
|
||||||
|
Tools:
|
||||||
|
* bash
|
||||||
|
* python 3
|
||||||
|
|
||||||
|
You will need both this nuTensor and the nuAssets repositories. These should both be placed in the same directory:
|
||||||
|
```
|
||||||
|
git clone https://github.com/geekprojects/nuAssets.git
|
||||||
|
git clone https://github.com/geekprojects/nuTensor.git
|
||||||
|
cd nuTensor
|
||||||
|
```
|
||||||
|
|
||||||
|
### Packaging
|
||||||
|
You can now run the scripts that package everything up.
|
||||||
|
These are bash scripts. They have only been tested on Linux and MacOS.
|
||||||
|
|
||||||
|
#### For Firefox
|
||||||
|
```
|
||||||
|
tools/make-firefox.sh all
|
||||||
|
```
|
||||||
|
|
||||||
|
#### For Chrome/Chromium (Not yet tested)
|
||||||
|
```
|
||||||
|
tools/make-chromium.sh all
|
||||||
|
```
|
||||||
|
|
||||||
|
#### For Opera (Not yet tested)
|
||||||
|
```
|
||||||
|
tools/make-opera.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
The installation package should now be found in dist/build/
|
||||||
|
|
||||||
|
### Installing
|
||||||
|
|
||||||
|
Follow the instructions in [README.md](README.md) to install it.
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,308 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
uBlock Origin - a browser extension to block requests.
|
||||||
|
Copyright (C) 2019-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
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
|
||||||
|
// For non-background page
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
// Direct messaging connection ability
|
||||||
|
|
||||||
|
(( ) => {
|
||||||
|
// >>>>>>>> start of private namespace
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof vAPI !== 'object' ||
|
||||||
|
vAPI.messaging instanceof Object === false ||
|
||||||
|
vAPI.MessagingConnection instanceof Function
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const listeners = new Set();
|
||||||
|
const connections = new Map();
|
||||||
|
|
||||||
|
vAPI.MessagingConnection = class {
|
||||||
|
constructor(handler, details) {
|
||||||
|
this.messaging = vAPI.messaging;
|
||||||
|
this.handler = handler;
|
||||||
|
this.id = details.id;
|
||||||
|
this.to = details.to;
|
||||||
|
this.toToken = details.toToken;
|
||||||
|
this.from = details.from;
|
||||||
|
this.fromToken = details.fromToken;
|
||||||
|
this.checkTimer = undefined;
|
||||||
|
// On Firefox it appears ports are not automatically disconnected
|
||||||
|
// when navigating to another page.
|
||||||
|
const ctor = vAPI.MessagingConnection;
|
||||||
|
if ( ctor.pagehide !== undefined ) { return; }
|
||||||
|
ctor.pagehide = ( ) => {
|
||||||
|
for ( const connection of connections.values() ) {
|
||||||
|
connection.disconnect();
|
||||||
|
connection.handler(
|
||||||
|
connection.toDetails('connectionBroken')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
window.addEventListener('pagehide', ctor.pagehide);
|
||||||
|
}
|
||||||
|
toDetails(what, payload) {
|
||||||
|
return {
|
||||||
|
what: what,
|
||||||
|
id: this.id,
|
||||||
|
from: this.from,
|
||||||
|
fromToken: this.fromToken,
|
||||||
|
to: this.to,
|
||||||
|
toToken: this.toToken,
|
||||||
|
payload: payload
|
||||||
|
};
|
||||||
|
}
|
||||||
|
disconnect() {
|
||||||
|
if ( this.checkTimer !== undefined ) {
|
||||||
|
clearTimeout(this.checkTimer);
|
||||||
|
this.checkTimer = undefined;
|
||||||
|
}
|
||||||
|
connections.delete(this.id);
|
||||||
|
const port = this.messaging.getPort();
|
||||||
|
if ( port === null ) { return; }
|
||||||
|
port.postMessage({
|
||||||
|
channel: 'vapi',
|
||||||
|
msg: this.toDetails('connectionBroken'),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
checkAsync() {
|
||||||
|
if ( this.checkTimer !== undefined ) {
|
||||||
|
clearTimeout(this.checkTimer);
|
||||||
|
}
|
||||||
|
this.checkTimer = vAPI.setTimeout(
|
||||||
|
( ) => { this.check(); },
|
||||||
|
499
|
||||||
|
);
|
||||||
|
}
|
||||||
|
check() {
|
||||||
|
this.checkTimer = undefined;
|
||||||
|
if ( connections.has(this.id) === false ) { return; }
|
||||||
|
const port = this.messaging.getPort();
|
||||||
|
if ( port === null ) { return; }
|
||||||
|
port.postMessage({
|
||||||
|
channel: 'vapi',
|
||||||
|
msg: this.toDetails('connectionCheck'),
|
||||||
|
});
|
||||||
|
this.checkAsync();
|
||||||
|
}
|
||||||
|
receive(details) {
|
||||||
|
switch ( details.what ) {
|
||||||
|
case 'connectionAccepted':
|
||||||
|
this.toToken = details.toToken;
|
||||||
|
this.handler(details);
|
||||||
|
this.checkAsync();
|
||||||
|
break;
|
||||||
|
case 'connectionBroken':
|
||||||
|
connections.delete(this.id);
|
||||||
|
this.handler(details);
|
||||||
|
break;
|
||||||
|
case 'connectionMessage':
|
||||||
|
this.handler(details);
|
||||||
|
this.checkAsync();
|
||||||
|
break;
|
||||||
|
case 'connectionCheck':
|
||||||
|
const port = this.messaging.getPort();
|
||||||
|
if ( port === null ) { return; }
|
||||||
|
if ( connections.has(this.id) ) {
|
||||||
|
this.checkAsync();
|
||||||
|
} else {
|
||||||
|
details.what = 'connectionBroken';
|
||||||
|
port.postMessage({ channel: 'vapi', msg: details });
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'connectionRefused':
|
||||||
|
connections.delete(this.id);
|
||||||
|
this.handler(details);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
send(payload) {
|
||||||
|
const port = this.messaging.getPort();
|
||||||
|
if ( port === null ) { return; }
|
||||||
|
port.postMessage({
|
||||||
|
channel: 'vapi',
|
||||||
|
msg: this.toDetails('connectionMessage', payload),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static addListener(listener) {
|
||||||
|
listeners.add(listener);
|
||||||
|
}
|
||||||
|
static async connectTo(from, to, handler) {
|
||||||
|
const port = vAPI.messaging.getPort();
|
||||||
|
if ( port === null ) { return; }
|
||||||
|
const connection = new vAPI.MessagingConnection(handler, {
|
||||||
|
id: `${from}-${to}-${vAPI.sessionId}`,
|
||||||
|
to: to,
|
||||||
|
from: from,
|
||||||
|
fromToken: port.name
|
||||||
|
});
|
||||||
|
connections.set(connection.id, connection);
|
||||||
|
port.postMessage({
|
||||||
|
channel: 'vapi',
|
||||||
|
msg: {
|
||||||
|
what: 'connectionRequested',
|
||||||
|
id: connection.id,
|
||||||
|
from: from,
|
||||||
|
fromToken: port.name,
|
||||||
|
to: to,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return connection.id;
|
||||||
|
}
|
||||||
|
static disconnectFrom(connectionId) {
|
||||||
|
const connection = connections.get(connectionId);
|
||||||
|
if ( connection === undefined ) { return; }
|
||||||
|
connection.disconnect();
|
||||||
|
}
|
||||||
|
static sendTo(connectionId, payload) {
|
||||||
|
const connection = connections.get(connectionId);
|
||||||
|
if ( connection === undefined ) { return; }
|
||||||
|
connection.send(payload);
|
||||||
|
}
|
||||||
|
static canDestroyPort() {
|
||||||
|
return listeners.length === 0 && connections.size === 0;
|
||||||
|
}
|
||||||
|
static mustDestroyPort() {
|
||||||
|
if ( connections.size === 0 ) { return; }
|
||||||
|
for ( const connection of connections.values() ) {
|
||||||
|
connection.receive({ what: 'connectionBroken' });
|
||||||
|
}
|
||||||
|
connections.clear();
|
||||||
|
}
|
||||||
|
static canProcessMessage(details) {
|
||||||
|
if ( details.channel !== 'vapi' ) { return; }
|
||||||
|
switch ( details.msg.what ) {
|
||||||
|
case 'connectionAccepted':
|
||||||
|
case 'connectionBroken':
|
||||||
|
case 'connectionCheck':
|
||||||
|
case 'connectionMessage':
|
||||||
|
case 'connectionRefused': {
|
||||||
|
const connection = connections.get(details.msg.id);
|
||||||
|
if ( connection === undefined ) { break; }
|
||||||
|
connection.receive(details.msg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case 'connectionRequested':
|
||||||
|
if ( listeners.length === 0 ) { return; }
|
||||||
|
const port = vAPI.messaging.getPort();
|
||||||
|
if ( port === null ) { break; }
|
||||||
|
let listener, result;
|
||||||
|
for ( listener of listeners ) {
|
||||||
|
result = listener(details.msg);
|
||||||
|
if ( result !== undefined ) { break; }
|
||||||
|
}
|
||||||
|
if ( result === undefined ) { break; }
|
||||||
|
if ( result === true ) {
|
||||||
|
details.msg.what = 'connectionAccepted';
|
||||||
|
details.msg.toToken = port.name;
|
||||||
|
const connection = new vAPI.MessagingConnection(
|
||||||
|
listener,
|
||||||
|
details.msg
|
||||||
|
);
|
||||||
|
connections.set(connection.id, connection);
|
||||||
|
} else {
|
||||||
|
details.msg.what = 'connectionRefused';
|
||||||
|
}
|
||||||
|
port.postMessage(details);
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
vAPI.messaging.extensions.push(vAPI.MessagingConnection);
|
||||||
|
|
||||||
|
// <<<<<<<< end of private namespace
|
||||||
|
})();
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
// Broadcast listening ability
|
||||||
|
|
||||||
|
(( ) => {
|
||||||
|
// >>>>>>>> start of private namespace
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof vAPI !== 'object' ||
|
||||||
|
vAPI.messaging instanceof Object === false ||
|
||||||
|
vAPI.broadcastListener instanceof Object
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const listeners = new Set();
|
||||||
|
|
||||||
|
vAPI.broadcastListener = {
|
||||||
|
add: function(listener) {
|
||||||
|
listeners.add(listener);
|
||||||
|
vAPI.messaging.getPort();
|
||||||
|
},
|
||||||
|
remove: function(listener) {
|
||||||
|
listeners.delete(listener);
|
||||||
|
},
|
||||||
|
canDestroyPort() {
|
||||||
|
return listeners.size === 0;
|
||||||
|
},
|
||||||
|
mustDestroyPort() {
|
||||||
|
listeners.clear();
|
||||||
|
},
|
||||||
|
canProcessMessage(details) {
|
||||||
|
if ( details.broadcast === false ) { return; }
|
||||||
|
for ( const listener of listeners ) {
|
||||||
|
listener(details.msg);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
vAPI.messaging.extensions.push(vAPI.broadcastListener);
|
||||||
|
|
||||||
|
// <<<<<<<< end of private namespace
|
||||||
|
})();
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
DO NOT:
|
||||||
|
- Remove the following code
|
||||||
|
- Add code beyond the following code
|
||||||
|
Reason:
|
||||||
|
- https://github.com/gorhill/uBlock/pull/3721
|
||||||
|
- uBO never uses the return value from injected content scripts
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
void 0;
|
||||||
@ -0,0 +1,86 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
uMatrix - a browser extension to block requests.
|
||||||
|
Copyright (C) 2017-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
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/* global HTMLDocument, XMLDocument */
|
||||||
|
|
||||||
|
// For background page, auxiliary pages, and content scripts.
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
if ( self.browser instanceof Object ) {
|
||||||
|
self.chrome = self.browser;
|
||||||
|
} else {
|
||||||
|
self.browser = self.chrome;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=1408996#c9
|
||||||
|
var vAPI = self.vAPI; // jshint ignore:line
|
||||||
|
|
||||||
|
// https://github.com/chrisaljoudi/uBlock/issues/464
|
||||||
|
// https://github.com/chrisaljoudi/uBlock/issues/1528
|
||||||
|
// A XMLDocument can be a valid HTML document.
|
||||||
|
|
||||||
|
// https://github.com/gorhill/uBlock/issues/1124
|
||||||
|
// Looks like `contentType` is on track to be standardized:
|
||||||
|
// https://dom.spec.whatwg.org/#concept-document-content-type
|
||||||
|
|
||||||
|
// https://forums.lanik.us/viewtopic.php?f=64&t=31522
|
||||||
|
// Skip text/plain documents.
|
||||||
|
|
||||||
|
if (
|
||||||
|
(
|
||||||
|
document instanceof HTMLDocument ||
|
||||||
|
document instanceof XMLDocument &&
|
||||||
|
document.createElement('div') instanceof HTMLDivElement
|
||||||
|
) &&
|
||||||
|
(
|
||||||
|
/^image\/|^text\/plain/.test(document.contentType || '') === false
|
||||||
|
) &&
|
||||||
|
(
|
||||||
|
self.vAPI instanceof Object === false || vAPI.nuTensor !== true
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
vAPI = self.vAPI = { nuTensor: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
DO NOT:
|
||||||
|
- Remove the following code
|
||||||
|
- Add code beyond the following code
|
||||||
|
Reason:
|
||||||
|
- https://github.com/gorhill/uBlock/pull/3721
|
||||||
|
- uMatrix never uses the return value from injected content scripts
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
void 0;
|
||||||
@ -0,0 +1,176 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
uBlock Origin - a browser extension to block requests.
|
||||||
|
Copyright (C) 2019-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
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// `webext` is a promisified api of `chrome`. Entries are added as
|
||||||
|
// the promisification of uBO progress.
|
||||||
|
|
||||||
|
const webext = (( ) => { // jshint ignore:line
|
||||||
|
// >>>>> start of private scope
|
||||||
|
|
||||||
|
const noopFunc = ( ) => { };
|
||||||
|
|
||||||
|
const promisifyNoFail = function(thisArg, fnName, outFn = r => r) {
|
||||||
|
const fn = thisArg[fnName];
|
||||||
|
return function() {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
fn.call(thisArg, ...arguments, function() {
|
||||||
|
if ( chrome.runtime.lastError instanceof Object ) {
|
||||||
|
void chrome.runtime.lastError.message;
|
||||||
|
}
|
||||||
|
resolve(outFn(...arguments));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const promisify = function(thisArg, fnName) {
|
||||||
|
const fn = thisArg[fnName];
|
||||||
|
return function() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
fn.call(thisArg, ...arguments, function() {
|
||||||
|
const lastError = chrome.runtime.lastError;
|
||||||
|
if ( lastError instanceof Object ) {
|
||||||
|
return reject(lastError.message);
|
||||||
|
}
|
||||||
|
resolve(...arguments);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const webext = {
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/browserAction
|
||||||
|
browserAction: {
|
||||||
|
setBadgeBackgroundColor: promisifyNoFail(chrome.browserAction, 'setBadgeBackgroundColor'),
|
||||||
|
setBadgeText: promisifyNoFail(chrome.browserAction, 'setBadgeText'),
|
||||||
|
setBadgeTextColor: noopFunc,
|
||||||
|
setIcon: promisifyNoFail(chrome.browserAction, 'setIcon'),
|
||||||
|
setTitle: promisifyNoFail(chrome.browserAction, 'setTitle'),
|
||||||
|
},
|
||||||
|
cookies: {
|
||||||
|
getAll: promisifyNoFail(chrome.cookies, 'getAll'),
|
||||||
|
remove: promisifyNoFail(chrome.cookies, 'remove'),
|
||||||
|
},
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/menus
|
||||||
|
/*
|
||||||
|
menus: {
|
||||||
|
create: function() {
|
||||||
|
return chrome.contextMenus.create(...arguments, ( ) => {
|
||||||
|
void chrome.runtime.lastError;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onClicked: chrome.contextMenus.onClicked,
|
||||||
|
remove: promisifyNoFail(chrome.contextMenus, 'remove'),
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/privacy
|
||||||
|
privacy: {
|
||||||
|
},
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/storage
|
||||||
|
storage: {
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/storage/local
|
||||||
|
local: {
|
||||||
|
clear: promisify(chrome.storage.local, 'clear'),
|
||||||
|
get: promisify(chrome.storage.local, 'get'),
|
||||||
|
getBytesInUse: promisify(chrome.storage.local, 'getBytesInUse'),
|
||||||
|
remove: promisify(chrome.storage.local, 'remove'),
|
||||||
|
set: promisify(chrome.storage.local, 'set'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs
|
||||||
|
tabs: {
|
||||||
|
get: promisifyNoFail(chrome.tabs, 'get', tab => tab instanceof Object ? tab : null),
|
||||||
|
executeScript: promisifyNoFail(chrome.tabs, 'executeScript'),
|
||||||
|
insertCSS: promisifyNoFail(chrome.tabs, 'insertCSS'),
|
||||||
|
query: promisifyNoFail(chrome.tabs, 'query', tabs => Array.isArray(tabs) ? tabs : []),
|
||||||
|
reload: promisifyNoFail(chrome.tabs, 'reload'),
|
||||||
|
remove: promisifyNoFail(chrome.tabs, 'remove'),
|
||||||
|
update: promisifyNoFail(chrome.tabs, 'update', tab => tab instanceof Object ? tab : null),
|
||||||
|
},
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/webNavigation
|
||||||
|
webNavigation: {
|
||||||
|
getFrame: promisify(chrome.webNavigation, 'getFrame'),
|
||||||
|
},
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/windows
|
||||||
|
windows: {
|
||||||
|
get: promisifyNoFail(chrome.windows, 'get', win => win instanceof Object ? win : null),
|
||||||
|
create: promisifyNoFail(chrome.windows, 'create', win => win instanceof Object ? win : null),
|
||||||
|
update: promisifyNoFail(chrome.windows, 'update', win => win instanceof Object ? win : null),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// browser.privacy entries
|
||||||
|
{
|
||||||
|
const settings = [
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/privacy/network
|
||||||
|
[ 'network', 'networkPredictionEnabled' ],
|
||||||
|
[ 'network', 'webRTCIPHandlingPolicy' ],
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/privacy/websites
|
||||||
|
[ 'websites', 'hyperlinkAuditingEnabled' ],
|
||||||
|
];
|
||||||
|
for ( const [ category, setting ] of settings ) {
|
||||||
|
let categoryEntry = webext.privacy[category];
|
||||||
|
if ( categoryEntry instanceof Object === false ) {
|
||||||
|
categoryEntry = webext.privacy[category] = {};
|
||||||
|
}
|
||||||
|
const settingEntry = categoryEntry[setting] = {};
|
||||||
|
const thisArg = chrome.privacy[category][setting];
|
||||||
|
settingEntry.clear = promisifyNoFail(thisArg, 'clear');
|
||||||
|
settingEntry.get = promisifyNoFail(thisArg, 'get');
|
||||||
|
settingEntry.set = promisifyNoFail(thisArg, 'set');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/storage/managed
|
||||||
|
if ( chrome.storage.managed instanceof Object ) {
|
||||||
|
webext.storage.managed = {
|
||||||
|
get: promisify(chrome.storage.managed, 'get'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/storage/sync
|
||||||
|
if ( chrome.storage.sync instanceof Object ) {
|
||||||
|
webext.storage.sync = {
|
||||||
|
QUOTA_BYTES: chrome.storage.sync.QUOTA_BYTES,
|
||||||
|
QUOTA_BYTES_PER_ITEM: chrome.storage.sync.QUOTA_BYTES_PER_ITEM,
|
||||||
|
MAX_ITEMS: chrome.storage.sync.MAX_ITEMS,
|
||||||
|
MAX_WRITE_OPERATIONS_PER_HOUR: chrome.storage.sync.MAX_WRITE_OPERATIONS_PER_HOUR,
|
||||||
|
MAX_WRITE_OPERATIONS_PER_MINUTE: chrome.storage.sync.MAX_WRITE_OPERATIONS_PER_MINUTE,
|
||||||
|
|
||||||
|
clear: promisify(chrome.storage.sync, 'clear'),
|
||||||
|
get: promisify(chrome.storage.sync, 'get'),
|
||||||
|
getBytesInUse: promisify(chrome.storage.sync, 'getBytesInUse'),
|
||||||
|
remove: promisify(chrome.storage.sync, 'remove'),
|
||||||
|
set: promisify(chrome.storage.sync, 'set'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=608854
|
||||||
|
if ( chrome.tabs.removeCSS instanceof Function ) {
|
||||||
|
webext.tabs.removeCSS = promisifyNoFail(chrome.tabs, 'removeCSS');
|
||||||
|
}
|
||||||
|
|
||||||
|
return webext;
|
||||||
|
|
||||||
|
// <<<<< end of private scope
|
||||||
|
})();
|
||||||
@ -1,263 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
uMatrix - a browser extension to block requests.
|
|
||||||
Copyright (C) 2016-2017 The uBlock Origin authors
|
|
||||||
|
|
||||||
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 indexedDB, IDBDatabase */
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
// The code below has been originally manually imported from:
|
|
||||||
// Commit: https://github.com/nikrolls/uBlock-Edge/commit/d1538ea9bea89d507219d3219592382eee306134
|
|
||||||
// Commit date: 29 October 2016
|
|
||||||
// Commit author: https://github.com/nikrolls
|
|
||||||
// Commit message: "Implement cacheStorage using IndexedDB"
|
|
||||||
|
|
||||||
// The original imported code has been subsequently modified as it was not
|
|
||||||
// compatible with Firefox.
|
|
||||||
// (a Promise thing, see https://github.com/dfahlander/Dexie.js/issues/317)
|
|
||||||
// Furthermore, code to migrate from browser.storage.local to vAPI.cacheStorage
|
|
||||||
// has been added, for seamless migration of cache-related entries into
|
|
||||||
// indexedDB.
|
|
||||||
|
|
||||||
// Imported from uBlock Origin project.
|
|
||||||
|
|
||||||
vAPI.cacheStorage = (function() {
|
|
||||||
const STORAGE_NAME = 'uMatrixCacheStorage';
|
|
||||||
var db;
|
|
||||||
var pending = [];
|
|
||||||
|
|
||||||
// prime the db so that it's ready asap for next access.
|
|
||||||
getDb(noopfn);
|
|
||||||
|
|
||||||
return { get, set, remove, clear, getBytesInUse };
|
|
||||||
|
|
||||||
function get(input, callback) {
|
|
||||||
if ( typeof callback !== 'function' ) { return; }
|
|
||||||
if ( input === null ) {
|
|
||||||
return getAllFromDb(callback);
|
|
||||||
}
|
|
||||||
var toRead, output = {};
|
|
||||||
if ( typeof input === 'string' ) {
|
|
||||||
toRead = [ input ];
|
|
||||||
} else if ( Array.isArray(input) ) {
|
|
||||||
toRead = input;
|
|
||||||
} else /* if ( typeof input === 'object' ) */ {
|
|
||||||
toRead = Object.keys(input);
|
|
||||||
output = input;
|
|
||||||
}
|
|
||||||
return getFromDb(toRead, output, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
function set(input, callback) {
|
|
||||||
putToDb(input, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
function remove(key, callback) {
|
|
||||||
deleteFromDb(key, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
function clear(callback) {
|
|
||||||
clearDb(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getBytesInUse(keys, callback) {
|
|
||||||
// TODO: implement this
|
|
||||||
callback(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
function genericErrorHandler(error) {
|
|
||||||
console.error('[%s]', STORAGE_NAME, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
function noopfn() {
|
|
||||||
}
|
|
||||||
|
|
||||||
function processPendings() {
|
|
||||||
var cb;
|
|
||||||
while ( (cb = pending.shift()) ) {
|
|
||||||
cb(db);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDb(callback) {
|
|
||||||
if ( pending === undefined ) {
|
|
||||||
return callback();
|
|
||||||
}
|
|
||||||
if ( pending.length !== 0 ) {
|
|
||||||
return pending.push(callback);
|
|
||||||
}
|
|
||||||
if ( db instanceof IDBDatabase ) {
|
|
||||||
return callback(db);
|
|
||||||
}
|
|
||||||
pending.push(callback);
|
|
||||||
if ( pending.length !== 1 ) { return; }
|
|
||||||
// https://github.com/gorhill/uBlock/issues/3156
|
|
||||||
// I have observed that no event was fired in Tor Browser 7.0.7 +
|
|
||||||
// medium security level after the request to open the database was
|
|
||||||
// created. When this occurs, I have also observed that the `error`
|
|
||||||
// property was already set, so this means uBO can detect here whether
|
|
||||||
// the database can be opened successfully. A try-catch block is
|
|
||||||
// necessary when reading the `error` property because we are not
|
|
||||||
// allowed to read this propery outside of event handlers in newer
|
|
||||||
// implementation of IDBRequest (my understanding).
|
|
||||||
var req;
|
|
||||||
try {
|
|
||||||
req = indexedDB.open(STORAGE_NAME, 1);
|
|
||||||
if ( req.error ) {
|
|
||||||
console.log(req.error);
|
|
||||||
req = undefined;
|
|
||||||
}
|
|
||||||
} catch(ex) {
|
|
||||||
}
|
|
||||||
if ( req === undefined ) {
|
|
||||||
processPendings();
|
|
||||||
pending = undefined;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
req.onupgradeneeded = function(ev) {
|
|
||||||
req = undefined;
|
|
||||||
db = ev.target.result;
|
|
||||||
db.onerror = db.onabort = genericErrorHandler;
|
|
||||||
var table = db.createObjectStore(STORAGE_NAME, { keyPath: 'key' });
|
|
||||||
table.createIndex('value', 'value', { unique: false });
|
|
||||||
};
|
|
||||||
req.onsuccess = function(ev) {
|
|
||||||
req = undefined;
|
|
||||||
db = ev.target.result;
|
|
||||||
db.onerror = db.onabort = genericErrorHandler;
|
|
||||||
processPendings();
|
|
||||||
};
|
|
||||||
req.onerror = req.onblocked = function() {
|
|
||||||
req = undefined;
|
|
||||||
console.log(this.error);
|
|
||||||
processPendings();
|
|
||||||
pending = undefined;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFromDb(keys, store, callback) {
|
|
||||||
if ( typeof callback !== 'function' ) { return; }
|
|
||||||
if ( keys.length === 0 ) { return callback(store); }
|
|
||||||
var gotOne = function() {
|
|
||||||
if ( typeof this.result === 'object' ) {
|
|
||||||
store[this.result.key] = this.result.value;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
getDb(function(db) {
|
|
||||||
if ( !db ) { return callback(); }
|
|
||||||
var transaction = db.transaction(STORAGE_NAME);
|
|
||||||
transaction.oncomplete =
|
|
||||||
transaction.onerror =
|
|
||||||
transaction.onabort = function() {
|
|
||||||
return callback(store);
|
|
||||||
};
|
|
||||||
var table = transaction.objectStore(STORAGE_NAME);
|
|
||||||
for ( var key of keys ) {
|
|
||||||
var req = table.get(key);
|
|
||||||
req.onsuccess = gotOne;
|
|
||||||
req.onerror = noopfn;
|
|
||||||
req = undefined;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAllFromDb(callback) {
|
|
||||||
if ( typeof callback !== 'function' ) {
|
|
||||||
callback = noopfn;
|
|
||||||
}
|
|
||||||
getDb(function(db) {
|
|
||||||
if ( !db ) { return callback(); }
|
|
||||||
var output = {};
|
|
||||||
var transaction = db.transaction(STORAGE_NAME);
|
|
||||||
transaction.oncomplete =
|
|
||||||
transaction.onerror =
|
|
||||||
transaction.onabort = function() {
|
|
||||||
callback(output);
|
|
||||||
};
|
|
||||||
var table = transaction.objectStore(STORAGE_NAME),
|
|
||||||
req = table.openCursor();
|
|
||||||
req.onsuccess = function(ev) {
|
|
||||||
var cursor = ev.target.result;
|
|
||||||
if ( !cursor ) { return; }
|
|
||||||
output[cursor.key] = cursor.value;
|
|
||||||
cursor.continue();
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function putToDb(input, callback) {
|
|
||||||
if ( typeof callback !== 'function' ) {
|
|
||||||
callback = noopfn;
|
|
||||||
}
|
|
||||||
var keys = Object.keys(input);
|
|
||||||
if ( keys.length === 0 ) { return callback(); }
|
|
||||||
getDb(function(db) {
|
|
||||||
if ( !db ) { return callback(); }
|
|
||||||
var transaction = db.transaction(STORAGE_NAME, 'readwrite');
|
|
||||||
transaction.oncomplete =
|
|
||||||
transaction.onerror =
|
|
||||||
transaction.onabort = callback;
|
|
||||||
var table = transaction.objectStore(STORAGE_NAME);
|
|
||||||
for ( var key of keys ) {
|
|
||||||
var entry = {};
|
|
||||||
entry.key = key;
|
|
||||||
entry.value = input[key];
|
|
||||||
table.put(entry);
|
|
||||||
entry = undefined;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteFromDb(input, callback) {
|
|
||||||
if ( typeof callback !== 'function' ) {
|
|
||||||
callback = noopfn;
|
|
||||||
}
|
|
||||||
var keys = Array.isArray(input) ? input.slice() : [ input ];
|
|
||||||
if ( keys.length === 0 ) { return callback(); }
|
|
||||||
getDb(function(db) {
|
|
||||||
if ( !db ) { return callback(); }
|
|
||||||
var transaction = db.transaction(STORAGE_NAME, 'readwrite');
|
|
||||||
transaction.oncomplete =
|
|
||||||
transaction.onerror =
|
|
||||||
transaction.onabort = callback;
|
|
||||||
var table = transaction.objectStore(STORAGE_NAME);
|
|
||||||
for ( var key of keys ) {
|
|
||||||
table.delete(key);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearDb(callback) {
|
|
||||||
if ( typeof callback !== 'function' ) {
|
|
||||||
callback = noopfn;
|
|
||||||
}
|
|
||||||
getDb(function(db) {
|
|
||||||
if ( !db ) { return callback(); }
|
|
||||||
var req = db.transaction(STORAGE_NAME, 'readwrite')
|
|
||||||
.objectStore(STORAGE_NAME)
|
|
||||||
.clear();
|
|
||||||
req.onsuccess = req.onerror = callback;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}());
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
uBlock Origin - a browser extension to block requests.
|
||||||
|
Copyright (C) 2019-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
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const webext = browser; // jshint ignore:line
|
||||||
@ -1,425 +1,623 @@
|
|||||||
body {
|
body {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
border: 0;
|
border: 0;
|
||||||
box-sizing: border-box;
|
|
||||||
-moz-box-sizing: border-box;
|
|
||||||
color: black;
|
color: black;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100vh;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
overflow-x: hidden;
|
overflow: hidden;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
width: 100%;
|
width: 100vw;
|
||||||
}
|
|
||||||
.fa-icon {
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 150%;
|
|
||||||
padding: 0.4em 0.6em;
|
|
||||||
}
|
}
|
||||||
.fa-icon:hover {
|
textarea {
|
||||||
background-color: #eee;
|
box-sizing: border-box;
|
||||||
|
direction: ltr;
|
||||||
|
resize: none;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
#toolbar {
|
.permatoolbar {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
border: 0;
|
border: 0;
|
||||||
border-bottom: 1px solid #ccc;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
-moz-box-sizing: border-box;
|
display: flex;
|
||||||
left: 0;
|
flex-shrink: 0;
|
||||||
|
font-size: 120%;
|
||||||
|
justify-content: space-between;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0.5em 1em;
|
padding: 0.25em;
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
width: 100%;
|
|
||||||
z-index: 10;
|
|
||||||
}
|
}
|
||||||
#toolbar > div {
|
.permatoolbar > div {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 0.5em;
|
}
|
||||||
white-space: nowrap;
|
.permatoolbar .button {
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 150%;
|
||||||
|
padding: 0.25em;
|
||||||
|
}
|
||||||
|
.permatoolbar .button.active {
|
||||||
|
fill: #5F9EA0;
|
||||||
|
}
|
||||||
|
.permatoolbar .button:hover {
|
||||||
|
background-color: #eee;
|
||||||
}
|
}
|
||||||
#pageSelector {
|
#pageSelector {
|
||||||
|
padding: 0.25em 0;
|
||||||
width: 28em;
|
width: 28em;
|
||||||
margin-right: 0.5em;
|
}
|
||||||
padding: 0.2em 0;
|
body[dir="ltr"] #pageSelector {
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
|
body[dir="rtl"] #pageSelector {
|
||||||
|
margin-left: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#showpopup {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
#info {
|
||||||
|
fill: #ccc;
|
||||||
|
}
|
||||||
|
#info:hover {
|
||||||
|
fill: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
https://github.com/gorhill/uBlock/issues/3293
|
||||||
|
=> https://devhints.io/css-system-font-stack
|
||||||
|
*/
|
||||||
|
#inspectors {
|
||||||
|
flex-grow: 1;
|
||||||
|
font-family: "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
||||||
|
}
|
||||||
|
.inspector {
|
||||||
|
border-top: 1px solid #ccc;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.vscrollable {
|
||||||
|
direction: ltr;
|
||||||
|
flex-grow: 1;
|
||||||
|
font-size: small;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inspector:not(.vExpanded) .vCompactToggler.button {
|
||||||
|
transform: scaleY(-1)
|
||||||
|
}
|
||||||
|
.hCompact .hCompactToggler.button {
|
||||||
|
transform: scaleX(-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes popupPanelShow {
|
#inspectors.dom #netInspector {
|
||||||
from { opacity: 0; }
|
display: none;
|
||||||
to { opacity: 1; }
|
}
|
||||||
|
|
||||||
|
#netInspector #pause > span:last-of-type {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
#popupPanelContainer {
|
#netInspector.paused #pause > span:first-of-type {
|
||||||
background: white;
|
|
||||||
border: 1px solid gray;
|
|
||||||
display: none;
|
display: none;
|
||||||
overflow: hidden;
|
}
|
||||||
position: fixed;
|
#netInspector.paused #pause > span:last-of-type {
|
||||||
right: 0;
|
display: inline-flex;
|
||||||
z-index: 2000;
|
fill: #5F9EA0;
|
||||||
|
}
|
||||||
|
#netInspector #filterExprGroup {
|
||||||
|
display: flex;
|
||||||
|
margin: 0 1em;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
body.popupPanelOn #popupPanelContainer {
|
#netInspector #filterButton {
|
||||||
animation-duration: 0.25s;
|
opacity: 0.25;
|
||||||
animation-name: popupPanelShow;
|
|
||||||
display: block;
|
|
||||||
}
|
}
|
||||||
#popupPanelContainer.hide {
|
#netInspector.f #filterButton {
|
||||||
width: 6em !important;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
#popupPanelContainer > iframe {
|
#netInspector #filterInput {
|
||||||
|
border: 1px solid gray;
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
#netInspector #filterInput > input {
|
||||||
border: 0;
|
border: 0;
|
||||||
padding: 0;
|
min-width: 16em;
|
||||||
margin: 0;
|
}
|
||||||
overflow: hidden;
|
#netInspector #filterExprButton {
|
||||||
width: 100%;
|
transform: scaleY(-1);
|
||||||
|
}
|
||||||
|
#netInspector #filterExprButton:hover {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
#netInspector #filterExprButton.expanded {
|
||||||
|
transform: scaleY(1);
|
||||||
}
|
}
|
||||||
#popupPanelContainer.hide > iframe {
|
#netInspector #filterExprPicker {
|
||||||
|
background-color: white;
|
||||||
|
border: 1px solid gray;
|
||||||
display: none;
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
flex-direction: column;
|
||||||
|
font-size: small;
|
||||||
|
top: 100%;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
body[dir="ltr"] #netInspector #filterExprPicker {
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
body[dir="rtl"] #netInspector #filterExprPicker {
|
||||||
|
left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#popupPanelButton use {
|
#netInspector #filterExprGroup:hover #filterExprButton.expanded ~ #filterExprPicker {
|
||||||
transform: scale(1, 0.4);
|
display: flex;
|
||||||
}
|
}
|
||||||
body.popupPanelOn #popupPanelButton use {
|
#netInspector #filterExprPicker > div {
|
||||||
transform: scale(1, 1);
|
border: 1px dotted #ddd;
|
||||||
|
border-left: 0;
|
||||||
|
border-right: 0;
|
||||||
|
display: flex;
|
||||||
|
padding: 0.5em;
|
||||||
}
|
}
|
||||||
body.compactView #compactViewToggler use {
|
#netInspector #filterExprPicker > div:first-of-type {
|
||||||
transform: scale(1, -1);
|
border-top: 0;
|
||||||
transform-origin: center;
|
|
||||||
}
|
}
|
||||||
#filterButton {
|
#netInspector #filterExprPicker > div:last-of-type {
|
||||||
opacity: 0.25;
|
border-bottom: 0;
|
||||||
}
|
}
|
||||||
body.f #filterButton {
|
#netInspector #filterExprPicker div {
|
||||||
opacity: 1;
|
display: flex;
|
||||||
}
|
}
|
||||||
#filterInput.bad {
|
#netInspector #filterExprPicker span[data-filtex] {
|
||||||
background-color: #fee;
|
align-items: center;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-flex;
|
||||||
|
margin: 0 0.5em 0 0;
|
||||||
|
padding: 0.5em;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
#maxEntries {
|
#netInspector #filterExprPicker span[data-filtex]:last-of-type {
|
||||||
margin: 0 2em;
|
margin: 0;
|
||||||
}
|
}
|
||||||
input:focus {
|
#netInspector #filterExprPicker span[data-filtex]:hover {
|
||||||
background-color: #ffe;
|
background-color: aliceblue;
|
||||||
|
border: 1px solid lightblue;
|
||||||
}
|
}
|
||||||
#content {
|
#netInspector #filterExprPicker span.on[data-filtex] {
|
||||||
font-family: "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
background-color: lightblue;
|
||||||
font-size: 13px;
|
border: 1px solid lightblue;
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#content table {
|
#netInspector .vscrollable {
|
||||||
border: 0;
|
overflow: hidden;
|
||||||
border-collapse: collapse;
|
}
|
||||||
direction: ltr;
|
#vwRenderer {
|
||||||
table-layout: fixed;
|
box-sizing: border-box;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
#content table > colgroup > col:nth-of-type(1) {
|
#vwRenderer #vwScroller {
|
||||||
width: 4.6em;
|
height: 100%;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
#content table > colgroup > col:nth-of-type(2) {
|
#vwRenderer #vwScroller #vwVirtualContent {
|
||||||
width: 25%;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
#content table > colgroup > col:nth-of-type(3) {
|
#vwRenderer #vwContent {
|
||||||
width: 2.2em;
|
left: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
#content table > colgroup > col:nth-of-type(4) {
|
#vwRenderer .logEntry {
|
||||||
width: 5.4em;
|
display: block;
|
||||||
|
left: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
#content table > colgroup > col:nth-of-type(5) {
|
#vwRenderer .logEntry:empty {
|
||||||
width: calc(100% - 4.6em - 25% - 2.2em - 5.4em - 1.8em);
|
display: none;
|
||||||
}
|
}
|
||||||
#content table > colgroup > col:nth-of-type(6) {
|
#vwRenderer .logEntry > div {
|
||||||
width: 1.8em;
|
height: 100%;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
#content table tr {
|
#vwRenderer .logEntry > div[data-status="--"] {
|
||||||
background-color: #fafafa;
|
background-color: rgba(192, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
body.f table tr.f {
|
body.colorBlind #vwRenderer .logEntry > div[data-status="--"] {
|
||||||
display: none;
|
background-color: rgba(0, 19, 110, 0.1);
|
||||||
}
|
}
|
||||||
#content table tr:nth-of-type(2n+1) {
|
#vwRenderer .logEntry > div[data-status="3"] {
|
||||||
background-color: #eee;
|
background-color: rgba(108, 108, 108, 0.1);
|
||||||
}
|
}
|
||||||
|
body.colorBlind #vwRenderer .logEntry > div[data-status="3"] {
|
||||||
#content table tr.cat_info {
|
background-color: rgba(96, 96, 96, 0.1);
|
||||||
color: #00f;
|
}
|
||||||
|
#vwRenderer .logEntry > div[data-status="++"] {
|
||||||
|
background-color: rgba(0, 160, 0, 0.1);
|
||||||
|
}
|
||||||
|
body.colorBlind #vwRenderer .logEntry > div[data-status="++"] {
|
||||||
|
background-color: rgba(255, 194, 57, 0.1)
|
||||||
|
}
|
||||||
|
#vwRenderer .logEntry > div[data-tabid="-1"] {
|
||||||
|
text-shadow: 0 0.2em 0.4em #aaa;
|
||||||
}
|
}
|
||||||
#content table tr.blocked {
|
#vwRenderer .logEntry > div[data-aliasid] {
|
||||||
color: #f00;
|
color: mediumblue;
|
||||||
}
|
}
|
||||||
#content table tr.doc {
|
#vwRenderer .logEntry > div[data-type="tabLoad"] {
|
||||||
background-color: #666;
|
background-color: #666;
|
||||||
color: white;
|
color: white;
|
||||||
text-align: center;
|
}
|
||||||
|
#vwRenderer .logEntry > div[data-type="error"] {
|
||||||
|
color: #800;
|
||||||
|
}
|
||||||
|
#vwRenderer .logEntry > div[data-type="info"] {
|
||||||
|
color: #008;
|
||||||
|
}
|
||||||
|
#vwRenderer .logEntry > div.voided {
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
#vwRenderer .logEntry > div.voided:hover {
|
||||||
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
body #content td {
|
#vwRenderer .logEntry > div > span {
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
min-width: 0.5em;
|
border-top: 0;
|
||||||
padding: 3px;
|
border-right: 0;
|
||||||
vertical-align: top;
|
box-sizing: border-box;
|
||||||
white-space: normal;
|
display: inline-block;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0.2em;
|
||||||
|
text-align: left;
|
||||||
|
vertical-align: middle;
|
||||||
|
white-space: nowrap;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
word-wrap: break-word;
|
|
||||||
}
|
}
|
||||||
#content table tr td:first-of-type {
|
#vwRenderer .logEntry > div.canDetails:hover > span {
|
||||||
border-left: none;
|
background-color: rgba(0,0,0,0.04);
|
||||||
}
|
}
|
||||||
#content table tr td:last-of-type {
|
body[dir="ltr"] #vwRenderer .logEntry > div > span:first-child {
|
||||||
border-right: none;
|
border-left: 0;
|
||||||
}
|
}
|
||||||
body.compactView #content tr:not(.vExpanded) td {
|
body[dir="rtl"] #vwRenderer .logEntry > div > span:first-child {
|
||||||
overflow: hidden;
|
border-right: 0;
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
}
|
||||||
|
#vwRenderer .logEntry > div > span:nth-of-type(1) {
|
||||||
#content table tr td:nth-of-type(1) {
|
text-align: center;
|
||||||
cursor: default;
|
|
||||||
text-align: right;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
}
|
||||||
#content table tr td:nth-of-type(2):not([colspan]) {
|
#vwRenderer .logEntry > div > span:nth-of-type(2) {
|
||||||
direction: rtl;
|
|
||||||
text-align: right;
|
text-align: right;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
.vExpanded #vwRenderer .logEntry > div > span:nth-of-type(2) {
|
||||||
|
overflow-y: auto;
|
||||||
|
white-space: pre-line;
|
||||||
|
}
|
||||||
|
#netInspector.vExpanded #vwRenderer .logEntry > div > span:nth-of-type(2) {
|
||||||
|
text-align: left;
|
||||||
unicode-bidi: plaintext;
|
unicode-bidi: plaintext;
|
||||||
}
|
}
|
||||||
#content table tr[data-tabid="-1"] td:nth-of-type(2):not([colspan]) {
|
#vwRenderer .logEntry > div:not(.messageRealm) > span:nth-of-type(2) {
|
||||||
position: relative;
|
direction: rtl;
|
||||||
|
}
|
||||||
|
#vwRenderer .logEntry > div.messageRealm > span:nth-of-type(2) {
|
||||||
|
color: blue;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
#vwRenderer .logEntry > div.messageRealm[data-type="tabLoad"] > span:nth-of-type(2) {
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
#vwRenderer .logEntry > div.messageRealm > span:nth-of-type(2) ~ span {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
#content table tr td:nth-of-type(3) {
|
#vwRenderer .logEntry > div > span:nth-of-type(3) {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
#vwRenderer #vwContent .logEntry > div > span:nth-of-type(4) {
|
||||||
|
color: #888;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
/* visual for tabless network requests */
|
#vwRenderer #vwContent .logEntry > div[data-header] > span:nth-of-type(4) {
|
||||||
#content table tr[data-tabid="-1"] td:nth-of-type(3)::before {
|
color: black;
|
||||||
border: 5px solid #bbb;
|
}
|
||||||
border-bottom: 0;
|
.vExpanded #vwRenderer #vwContent .logEntry > div > span:nth-of-type(4) {
|
||||||
border-top: 0;
|
overflow-y: auto;
|
||||||
bottom: 0;
|
text-overflow: clip;
|
||||||
content: '\00a0';
|
white-space: pre-line;
|
||||||
left: 0;
|
}
|
||||||
|
#vwRenderer .logEntry > div > span:nth-of-type(4) b {
|
||||||
|
color: black;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
#vwRenderer .logEntry > div[data-aliasid] > span:nth-of-type(4) b {
|
||||||
|
color: mediumblue;
|
||||||
|
}
|
||||||
|
#vwRenderer .logEntry > div > span:nth-of-type(4) a {
|
||||||
|
background-color: dimgray;
|
||||||
|
color: white;
|
||||||
|
display: none;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0 0.25em;
|
||||||
|
opacity: 0.4;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
|
text-decoration: none;
|
||||||
top: 0;
|
top: 0;
|
||||||
width: calc(100% - 10px);
|
|
||||||
}
|
}
|
||||||
#content table tr.tab:not(.canMtx) {
|
#netInspector.vExpanded #vwRenderer .logEntry > div > span:nth-of-type(4) a {
|
||||||
opacity: 0.3;
|
bottom: 0px;
|
||||||
|
height: unset;
|
||||||
|
padding: 0.25em;
|
||||||
|
top: unset;
|
||||||
}
|
}
|
||||||
#content table tr.tab:not(.canMtx):hover {
|
#vwRenderer .logEntry > div > span:nth-of-type(4) a::after {
|
||||||
opacity: 0.7;
|
content: '\2197';
|
||||||
}
|
}
|
||||||
#content table tr.cat_net td:nth-of-type(3) {
|
#vwRenderer .logEntry > div.networkRealm > span:nth-of-type(4):hover a {
|
||||||
cursor: pointer;
|
align-items: center;
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
#vwRenderer .logEntry > div > span:nth-of-type(4) a:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
#vwRenderer .logEntry > div > span:nth-of-type(5) {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
/* visual for tabless network requests */
|
||||||
|
#vwRenderer .logEntry > div > span:nth-of-type(5) {
|
||||||
|
}
|
||||||
|
#vwRenderer .logEntry > div > span:nth-of-type(6) {
|
||||||
font: 12px monospace;
|
font: 12px monospace;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
white-space: nowrap;
|
|
||||||
}
|
}
|
||||||
#content table tr.cat_net td:nth-of-type(5) {
|
#vwRenderer .logEntry > div.canDetails:hover > span:nth-of-type(1),
|
||||||
|
#vwRenderer .logEntry > div.canDetails:hover > span:nth-of-type(3),
|
||||||
|
#vwRenderer .logEntry > div.canDetails:hover > span:nth-of-type(6) {
|
||||||
|
background: rgba(0, 0, 255, 0.1);
|
||||||
|
cursor: zoom-in;
|
||||||
}
|
}
|
||||||
#content table tr.cat_net td:nth-of-type(5) > span > * {
|
|
||||||
opacity: 0.6;
|
#vwRenderer #vwBottom {
|
||||||
|
background-color: #00F;
|
||||||
|
height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
#content table tr.cat_net td:nth-of-type(5) > span > b:first-of-type {
|
#vwRenderer #vwLineSizer {
|
||||||
opacity: 1;
|
left: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#popupContainer {
|
||||||
|
background: white;
|
||||||
|
border: 1px solid gray;
|
||||||
|
bottom: 0;
|
||||||
|
box-sizing: content-box;
|
||||||
|
display: none;
|
||||||
|
max-height: 75vh;
|
||||||
|
overflow: hidden;
|
||||||
|
position: fixed;
|
||||||
|
right: 0;
|
||||||
|
z-index: 200;
|
||||||
|
}
|
||||||
|
#inspectors.popupOn #popupContainer {
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modalDialog {
|
#modalOverlay {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
display: flex;
|
border: 0;
|
||||||
height: 100vh;
|
bottom: 0;
|
||||||
|
display: none;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
margin: 0;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
right: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
width: 100vw;
|
z-index: 400;
|
||||||
z-index: 5000;
|
|
||||||
}
|
}
|
||||||
.modalDialog > .dialog {
|
#modalOverlay.on {
|
||||||
background-color: white;
|
|
||||||
font: 15px httpsb,sans-serif;
|
|
||||||
min-width: fit-content;
|
|
||||||
padding: 0.5em;
|
|
||||||
width: 90%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ruleEditor section {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
.scopeWidget {
|
#modalOverlay > div {
|
||||||
line-height: 2.5em;
|
position: relative;
|
||||||
margin-bottom: 0.5em;
|
|
||||||
}
|
}
|
||||||
#specificScope, .ruleCell:nth-of-type(1) {
|
#modalOverlay > div > div:nth-of-type(1) {
|
||||||
flex-grow: 1;
|
background-color: white;
|
||||||
|
border: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 1em;
|
||||||
|
max-height: 90vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
width: 90vw;
|
||||||
|
}
|
||||||
|
#modalOverlay > div > div:nth-of-type(2) {
|
||||||
|
stroke: #000;
|
||||||
|
stroke-width: 3px;
|
||||||
|
position: absolute;
|
||||||
|
width: 1.6em;
|
||||||
|
height: 1.6em;
|
||||||
|
bottom: calc(100% + 2px);
|
||||||
|
background-color: white;
|
||||||
}
|
}
|
||||||
#globalScope, .ruleCell:nth-of-type(2) {
|
body[dir="ltr"] #modalOverlay > div > div:nth-of-type(2) {
|
||||||
width: 4em;
|
right: 0;
|
||||||
}
|
}
|
||||||
.ruleEditorToolbar {
|
body[dir="rtl"] #modalOverlay > div > div:nth-of-type(2) {
|
||||||
display: flex;
|
left: 0;
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-around;
|
|
||||||
margin-left: 0.5em;
|
|
||||||
padding: 0.2em;
|
|
||||||
}
|
}
|
||||||
.ruleEditorToolbar .fa-icon {
|
#modalOverlay > div > div:nth-of-type(2):hover {
|
||||||
padding: 0.4em;
|
background-color: #eee;
|
||||||
}
|
}
|
||||||
|
#modalOverlay > div > div:nth-of-type(2) > * {
|
||||||
.fa-icon.scopeRel {
|
pointer-events: none;
|
||||||
color: #24c;
|
|
||||||
fill: #24c;
|
|
||||||
}
|
}
|
||||||
body[data-scope="*"] .fa-icon.scopeRel {
|
|
||||||
color: #000;
|
#netFilteringDialog {
|
||||||
fill: #000;
|
font-size: 95%;
|
||||||
}
|
}
|
||||||
.ruleWidgets {
|
#netFilteringDialog a {
|
||||||
display: flex;
|
text-decoration: none;
|
||||||
flex-direction: column;
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
}
|
||||||
.ruleRow {
|
#netFilteringDialog > .headers {
|
||||||
display: flex;
|
border-bottom: 1px solid #888;
|
||||||
line-height: 2em;
|
line-height: 2;
|
||||||
margin-top: 1px;
|
position: relative;
|
||||||
}
|
}
|
||||||
.ruleCell {
|
#netFilteringDialog > .headers > .header {
|
||||||
background-color: #eee;
|
background-color: #eee;
|
||||||
border: 1px dotted rgba(0,0,0,0.2);
|
border: 1px solid #aaa;
|
||||||
|
border-bottom: 1px solid #888;
|
||||||
|
border-top-left-radius: 4px;
|
||||||
|
border-top-right-radius: 4px;
|
||||||
|
color: #888;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-left: 1px;
|
padding: 0 1em;
|
||||||
padding: 1px;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
|
||||||
.ruleCell:hover {
|
|
||||||
border-style: solid;
|
|
||||||
}
|
|
||||||
.ruleCell:nth-of-type(1) {
|
|
||||||
margin-left: 0;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
.ruleCell:nth-of-type(2) {
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
top: 1px;
|
||||||
}
|
}
|
||||||
.ruleCell[data-tcolor="1"] {
|
#netFilteringDialog[data-pane="details"] > .headers > [data-pane="details"],
|
||||||
border-color: #debaba;
|
#netFilteringDialog[data-pane="rule"] > .headers > [data-pane="rule"] {
|
||||||
color: black;
|
background-color: white;
|
||||||
background-color: #f8d0d0;
|
border-color: #888;
|
||||||
}
|
border-bottom: 1px solid white;
|
||||||
#ruleEditor.colorblind .ruleCell[data-tcolor="1"] {
|
|
||||||
border-color: rgba(0, 19, 110, 0.3);
|
|
||||||
color: black;
|
color: black;
|
||||||
background-color: rgba(0, 19, 110, 0.2);
|
|
||||||
}
|
}
|
||||||
.ruleCell[data-tcolor="2"] {
|
#netFilteringDialog > div.panes {
|
||||||
border-color: #bad6ba;
|
height: 50vh;
|
||||||
color: black;
|
overflow: hidden;
|
||||||
background-color: #d0f0d0;
|
overflow-y: auto;
|
||||||
|
padding-top: 1em;
|
||||||
}
|
}
|
||||||
#ruleEditor.colorblind .ruleCell[data-tcolor="2"] {
|
#netFilteringDialog > div.panes > div {
|
||||||
border-color: rgba(255, 194, 57, 0.3);
|
display: none;
|
||||||
color: black;
|
height: 100%;
|
||||||
background-color: rgba(255, 194, 57, 0.2);
|
|
||||||
}
|
}
|
||||||
.ruleCell[data-tcolor="129"] {
|
#netFilteringDialog[data-pane="details"] > .panes > [data-pane="details"],
|
||||||
color: white;
|
#netFilteringDialog[data-pane="rule"] > .panes > [data-pane="rule"] {
|
||||||
background-color: #c00;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
#ruleEditor.colorblind .ruleCell[data-tcolor="129"] {
|
#netFilteringDialog > .panes > [data-pane="details"] > div {
|
||||||
color: white;
|
align-items: stretch;
|
||||||
background-color: rgb(0, 19, 110);
|
background-color: #e6e6e6;
|
||||||
|
border: 0;
|
||||||
|
border-bottom: 1px solid white;
|
||||||
|
display: flex;
|
||||||
}
|
}
|
||||||
.ruleCell[data-tcolor="130"] {
|
#netFilteringDialog > .panes > [data-pane="details"] > div > span {
|
||||||
color: white;
|
padding: 0.5em;
|
||||||
background-color: #080;
|
|
||||||
}
|
}
|
||||||
#ruleEditor.colorblind .ruleCell[data-tcolor="130"] {
|
#netFilteringDialog > .panes > [data-pane="details"] > div > span:nth-of-type(1) {
|
||||||
border-color: rgb(255, 194, 57);
|
border: 0;
|
||||||
color: black;
|
flex-grow: 0;
|
||||||
background-color: rgb(255, 194, 57);
|
flex-shrink: 0;
|
||||||
|
text-align: right;
|
||||||
|
width: 8em;
|
||||||
}
|
}
|
||||||
.ruleCell[data-pcolor="129"] {
|
body[dir="ltr"] #netFilteringDialog > .panes > [data-pane="details"] > div > span:nth-of-type(1) {
|
||||||
background-image: url('../img/permanent-black-small.png');
|
border-right: 1px solid white;
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: -1px -1px;
|
|
||||||
}
|
}
|
||||||
#ruleEditor.colorblind .ruleCell[data-pcolor="129"] {
|
body[dir="rtl"] #netFilteringDialog > .panes > [data-pane="details"] > div > span:nth-of-type(1) {
|
||||||
background-image: url('../img/permanent-black-small-cb.png');
|
border-left: 1px solid white;
|
||||||
}
|
}
|
||||||
.ruleCell[data-pcolor="130"] {
|
#netFilteringDialog > .panes > [data-pane="details"] > div > span:nth-of-type(2) {
|
||||||
background-image: url('../img/permanent-white-small.png');
|
flex-grow: 1;
|
||||||
background-repeat: no-repeat;
|
max-height: 20vh;
|
||||||
background-position: -1px -1px;
|
overflow: hidden auto;
|
||||||
|
white-space: pre-line
|
||||||
}
|
}
|
||||||
#ruleEditor.colorblind .ruleCell[data-pcolor="130"] {
|
#netFilteringDialog > .panes > [data-pane="details"] > div > span:nth-of-type(2):not(.prose) {
|
||||||
background-image: url('../img/permanent-white-small-cb.png');
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
#netFilteringDialog > .panes > [data-pane="rule"] iframe {
|
||||||
#ruleActionPicker {
|
|
||||||
border: 0;
|
border: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
left: 0;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
width: 100%;
|
|
||||||
z-index: 10;
|
|
||||||
}
|
}
|
||||||
.allowRule, .blockRule {
|
|
||||||
|
#loggerExportDialog {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
#loggerExportDialog .options {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
#loggerExportDialog .options > div {
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
#loggerExportDialog .options span[data-i18n] {
|
||||||
|
border: 1px solid lightblue;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 90%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
border: 0;
|
padding: 0.5em;
|
||||||
padding: 0;
|
white-space: nowrap;
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 50%;
|
|
||||||
background: transparent;
|
|
||||||
}
|
}
|
||||||
.allowRule {
|
#loggerExportDialog .options span[data-i18n]:hover {
|
||||||
top: 0;
|
background-color: aliceblue;
|
||||||
}
|
}
|
||||||
.blockRule {
|
#loggerExportDialog .options span.on[data-i18n],
|
||||||
top: 50%;
|
#loggerExportDialog .options span.pushbutton:active {
|
||||||
|
background-color: lightblue;
|
||||||
}
|
}
|
||||||
.ruleCell[data-tcolor="1"] .allowRule:hover {
|
#loggerExportDialog .output {
|
||||||
background-color: #080;
|
font: smaller mono;
|
||||||
opacity: 0.25;
|
height: 60vh;
|
||||||
|
padding: 0.5em;
|
||||||
|
white-space: pre;
|
||||||
}
|
}
|
||||||
.ruleCell[data-tcolor="1"] .blockRule:hover {
|
|
||||||
background-color: #c00;
|
#loggerSettingsDialog {
|
||||||
opacity: 0.25;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
.ruleCell[data-tcolor="2"] .allowRule:hover {
|
#loggerSettingsDialog > div {
|
||||||
background-color: #080;
|
padding-bottom: 1em;
|
||||||
opacity: 0.25;
|
|
||||||
}
|
}
|
||||||
.ruleCell[data-tcolor="2"] .blockRule:hover {
|
#loggerSettingsDialog > div:last-of-type {
|
||||||
background-color: #c00;
|
padding-bottom: 0;
|
||||||
opacity: 0.25;
|
|
||||||
}
|
}
|
||||||
.ruleCell[data-tcolor="129"] .allowRule:hover {
|
#loggerSettingsDialog ul {
|
||||||
background-color: transparent;
|
padding: 0;
|
||||||
}
|
}
|
||||||
.ruleCell[data-tcolor="129"] .blockRule:hover {
|
body[dir="ltr"] #loggerSettingsDialog ul {
|
||||||
background-color: transparent;
|
padding-left: 2em;
|
||||||
}
|
}
|
||||||
.ruleCell[data-pcolor="130"] .allowRule:hover {
|
body[dir="rtl"] #loggerSettingsDialog ul {
|
||||||
background-color: transparent;
|
padding-right: 2em;
|
||||||
}
|
}
|
||||||
.ruleCell[data-pcolor="130"] .blockRule:hover {
|
#loggerSettingsDialog li {
|
||||||
background-color: transparent;
|
list-style-type: none;
|
||||||
|
margin: 0.5em 0 0 0;
|
||||||
}
|
}
|
||||||
#ruleEditor.colorblind .ruleCell[data-tcolor="1"] .allowRule:hover,
|
#loggerSettingsDialog input {
|
||||||
#ruleEditor.colorblind .ruleCell[data-tcolor="2"] .allowRule:hover {
|
max-width: 6em;
|
||||||
background-color: rgb(255, 194, 57);
|
|
||||||
opacity: 0.6;
|
|
||||||
}
|
}
|
||||||
#ruleEditor.colorblind .ruleCell[data-tcolor="1"] .blockRule:hover,
|
|
||||||
#ruleEditor.colorblind .ruleCell[data-tcolor="2"] .blockRule:hover {
|
.hide {
|
||||||
background-color: rgb(0, 19, 110);
|
display: none !important;
|
||||||
opacity: 0.4;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,20 +1,16 @@
|
|||||||
div.body {
|
html {
|
||||||
box-sizing: border-box;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
justify-content: space-between;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
p {
|
body {
|
||||||
margin: 0.5em 0;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
textarea {
|
#rawSettings {
|
||||||
box-sizing: border-box;
|
border-top: 1px solid #ddd;
|
||||||
flex-grow: 1;
|
height: 75vh;
|
||||||
resize: none;
|
|
||||||
text-align: left;
|
text-align: left;
|
||||||
white-space: pre;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
word-wrap: normal;
|
}
|
||||||
|
.CodeMirror-wrap pre {
|
||||||
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 26 KiB |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,465 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
uBlock Origin - a browser extension to block requests.
|
||||||
|
Copyright (C) 2016-present The uBlock Origin authors
|
||||||
|
|
||||||
|
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 IDBDatabase, indexedDB */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
// The code below has been originally manually imported from:
|
||||||
|
// Commit: https://github.com/nikrolls/uBlock-Edge/commit/d1538ea9bea89d507219d3219592382eee306134
|
||||||
|
// Commit date: 29 October 2016
|
||||||
|
// Commit author: https://github.com/nikrolls
|
||||||
|
// Commit message: "Implement cacheStorage using IndexedDB"
|
||||||
|
|
||||||
|
// The original imported code has been subsequently modified as it was not
|
||||||
|
// compatible with Firefox.
|
||||||
|
// (a Promise thing, see https://github.com/dfahlander/Dexie.js/issues/317)
|
||||||
|
// Furthermore, code to migrate from browser.storage.local to vAPI.storage
|
||||||
|
// has been added, for seamless migration of cache-related entries into
|
||||||
|
// indexedDB.
|
||||||
|
|
||||||
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=1371255
|
||||||
|
// Firefox-specific: we use indexedDB because browser.storage.local() has
|
||||||
|
// poor performance in Firefox.
|
||||||
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/328
|
||||||
|
// Use IndexedDB for Chromium as well, to take advantage of LZ4
|
||||||
|
// compression.
|
||||||
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/399
|
||||||
|
// Revert Chromium support of IndexedDB, use advanced setting to force
|
||||||
|
// IndexedDB.
|
||||||
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/409
|
||||||
|
// Allow forcing the use of webext storage on Firefox.
|
||||||
|
|
||||||
|
µMatrix.cacheStorage = (function() {
|
||||||
|
|
||||||
|
const STORAGE_NAME = 'uMatrixCacheStorage';
|
||||||
|
|
||||||
|
// Default to webext storage.
|
||||||
|
const localStorage = webext.storage.local;
|
||||||
|
const api = {
|
||||||
|
name: 'browser.storage.local',
|
||||||
|
get: localStorage.get,
|
||||||
|
set: localStorage.set,
|
||||||
|
remove: localStorage.remove,
|
||||||
|
clear: localStorage.clear,
|
||||||
|
getBytesInUse: localStorage.getBytesInUse,
|
||||||
|
select: function(selectedBackend) {
|
||||||
|
let actualBackend = selectedBackend;
|
||||||
|
if ( actualBackend === undefined || actualBackend === 'unset' ) {
|
||||||
|
actualBackend = vAPI.webextFlavor.soup.has('firefox')
|
||||||
|
? 'indexedDB'
|
||||||
|
: 'browser.storage.local';
|
||||||
|
}
|
||||||
|
if ( actualBackend === 'indexedDB' ) {
|
||||||
|
return selectIDB().then(success => {
|
||||||
|
if ( success || selectedBackend === 'indexedDB' ) {
|
||||||
|
clearWebext();
|
||||||
|
return 'indexedDB';
|
||||||
|
}
|
||||||
|
clearIDB();
|
||||||
|
return 'browser.storage.local';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if ( actualBackend === 'browser.storage.local' ) {
|
||||||
|
clearIDB();
|
||||||
|
}
|
||||||
|
return Promise.resolve('browser.storage.local');
|
||||||
|
|
||||||
|
},
|
||||||
|
error: undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
// Reassign API entries to that of indexedDB-based ones
|
||||||
|
const selectIDB = async function() {
|
||||||
|
let db;
|
||||||
|
let dbPromise;
|
||||||
|
let dbTimer;
|
||||||
|
|
||||||
|
const noopfn = function () {
|
||||||
|
};
|
||||||
|
|
||||||
|
const disconnect = function() {
|
||||||
|
if ( dbTimer !== undefined ) {
|
||||||
|
clearTimeout(dbTimer);
|
||||||
|
dbTimer = undefined;
|
||||||
|
}
|
||||||
|
if ( db instanceof IDBDatabase ) {
|
||||||
|
db.close();
|
||||||
|
db = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const keepAlive = function() {
|
||||||
|
if ( dbTimer !== undefined ) {
|
||||||
|
clearTimeout(dbTimer);
|
||||||
|
}
|
||||||
|
dbTimer = vAPI.setTimeout(
|
||||||
|
( ) => {
|
||||||
|
dbTimer = undefined;
|
||||||
|
disconnect();
|
||||||
|
},
|
||||||
|
Math.max(
|
||||||
|
µMatrix.rawSettings.autoUpdateAssetFetchPeriod * 2 * 1000,
|
||||||
|
180000
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://github.com/gorhill/uBlock/issues/3156
|
||||||
|
// I have observed that no event was fired in Tor Browser 7.0.7 +
|
||||||
|
// medium security level after the request to open the database was
|
||||||
|
// created. When this occurs, I have also observed that the `error`
|
||||||
|
// property was already set, so this means uBO can detect here whether
|
||||||
|
// the database can be opened successfully. A try-catch block is
|
||||||
|
// necessary when reading the `error` property because we are not
|
||||||
|
// allowed to read this propery outside of event handlers in newer
|
||||||
|
// implementation of IDBRequest (my understanding).
|
||||||
|
|
||||||
|
const getDb = function() {
|
||||||
|
keepAlive();
|
||||||
|
if ( db !== undefined ) {
|
||||||
|
return Promise.resolve(db);
|
||||||
|
}
|
||||||
|
if ( dbPromise !== undefined ) {
|
||||||
|
return dbPromise;
|
||||||
|
}
|
||||||
|
dbPromise = new Promise(resolve => {
|
||||||
|
let req;
|
||||||
|
try {
|
||||||
|
req = indexedDB.open(STORAGE_NAME, 1);
|
||||||
|
if ( req.error ) {
|
||||||
|
console.log(req.error);
|
||||||
|
req = undefined;
|
||||||
|
}
|
||||||
|
} catch(ex) {
|
||||||
|
}
|
||||||
|
if ( req === undefined ) {
|
||||||
|
db = null;
|
||||||
|
dbPromise = undefined;
|
||||||
|
return resolve(null);
|
||||||
|
}
|
||||||
|
req.onupgradeneeded = function(ev) {
|
||||||
|
if ( ev.oldVersion === 1 ) { return; }
|
||||||
|
try {
|
||||||
|
const db = ev.target.result;
|
||||||
|
db.createObjectStore(STORAGE_NAME, { keyPath: 'key' });
|
||||||
|
} catch(ex) {
|
||||||
|
req.onerror();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
req.onsuccess = function(ev) {
|
||||||
|
if ( resolve === undefined ) { return; }
|
||||||
|
req = undefined;
|
||||||
|
db = ev.target.result;
|
||||||
|
dbPromise = undefined;
|
||||||
|
resolve(db);
|
||||||
|
resolve = undefined;
|
||||||
|
};
|
||||||
|
req.onerror = req.onblocked = function() {
|
||||||
|
if ( resolve === undefined ) { return; }
|
||||||
|
req = undefined;
|
||||||
|
console.log(this.error);
|
||||||
|
db = null;
|
||||||
|
dbPromise = undefined;
|
||||||
|
resolve(null);
|
||||||
|
resolve = undefined;
|
||||||
|
};
|
||||||
|
setTimeout(( ) => {
|
||||||
|
if ( resolve === undefined ) { return; }
|
||||||
|
db = null;
|
||||||
|
dbPromise = undefined;
|
||||||
|
resolve(null);
|
||||||
|
resolve = undefined;
|
||||||
|
}, 5000);
|
||||||
|
});
|
||||||
|
return dbPromise;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getFromDb = async function(keys, keyvalStore, callback) {
|
||||||
|
if ( typeof callback !== 'function' ) { return; }
|
||||||
|
if ( keys.length === 0 ) { return callback(keyvalStore); }
|
||||||
|
const promises = [];
|
||||||
|
const gotOne = function() {
|
||||||
|
if ( typeof this.result !== 'object' ) { return; }
|
||||||
|
keyvalStore[this.result.key] = this.result.value;
|
||||||
|
if ( this.result.value instanceof Blob === false ) { return; }
|
||||||
|
promises.push(
|
||||||
|
µMatrix.lz4Codec.decode(
|
||||||
|
this.result.key,
|
||||||
|
this.result.value
|
||||||
|
).then(result => {
|
||||||
|
keyvalStore[result.key] = result.data;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const db = await getDb();
|
||||||
|
if ( !db ) { return callback(); }
|
||||||
|
const transaction = db.transaction(STORAGE_NAME, 'readonly');
|
||||||
|
transaction.oncomplete =
|
||||||
|
transaction.onerror =
|
||||||
|
transaction.onabort = ( ) => {
|
||||||
|
Promise.all(promises).then(( ) => {
|
||||||
|
callback(keyvalStore);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const table = transaction.objectStore(STORAGE_NAME);
|
||||||
|
for ( const key of keys ) {
|
||||||
|
const req = table.get(key);
|
||||||
|
req.onsuccess = gotOne;
|
||||||
|
req.onerror = noopfn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(reason) {
|
||||||
|
console.info(`cacheStorage.getFromDb() failed: ${reason}`);
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const visitAllFromDb = async function(visitFn) {
|
||||||
|
const db = await getDb();
|
||||||
|
if ( !db ) { return visitFn(); }
|
||||||
|
const transaction = db.transaction(STORAGE_NAME, 'readonly');
|
||||||
|
transaction.oncomplete =
|
||||||
|
transaction.onerror =
|
||||||
|
transaction.onabort = ( ) => visitFn();
|
||||||
|
const table = transaction.objectStore(STORAGE_NAME);
|
||||||
|
const req = table.openCursor();
|
||||||
|
req.onsuccess = function(ev) {
|
||||||
|
let cursor = ev.target && ev.target.result;
|
||||||
|
if ( !cursor ) { return; }
|
||||||
|
let entry = cursor.value;
|
||||||
|
visitFn(entry);
|
||||||
|
cursor.continue();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const getAllFromDb = function(callback) {
|
||||||
|
if ( typeof callback !== 'function' ) { return; }
|
||||||
|
const promises = [];
|
||||||
|
const keyvalStore = {};
|
||||||
|
visitAllFromDb(entry => {
|
||||||
|
if ( entry === undefined ) {
|
||||||
|
Promise.all(promises).then(( ) => {
|
||||||
|
callback(keyvalStore);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
keyvalStore[entry.key] = entry.value;
|
||||||
|
if ( entry.value instanceof Blob === false ) { return; }
|
||||||
|
promises.push(
|
||||||
|
µMatrix.lz4Codec.decode(
|
||||||
|
entry.key,
|
||||||
|
entry.value
|
||||||
|
).then(result => {
|
||||||
|
keyvalStore[result.key] = result.value;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}).catch(reason => {
|
||||||
|
console.info(`cacheStorage.getAllFromDb() failed: ${reason}`);
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/141
|
||||||
|
// Mind that IDBDatabase.transaction() and IDBObjectStore.put()
|
||||||
|
// can throw:
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/API/IDBDatabase/transaction
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/API/IDBObjectStore/put
|
||||||
|
|
||||||
|
const putToDb = async function(keyvalStore, callback) {
|
||||||
|
if ( typeof callback !== 'function' ) {
|
||||||
|
callback = noopfn;
|
||||||
|
}
|
||||||
|
const keys = Object.keys(keyvalStore);
|
||||||
|
if ( keys.length === 0 ) { return callback(); }
|
||||||
|
const promises = [ getDb() ];
|
||||||
|
const entries = [];
|
||||||
|
const dontCompress =
|
||||||
|
µMatrix.rawSettings.cacheStorageCompression !== true;
|
||||||
|
const handleEncodingResult = result => {
|
||||||
|
entries.push({ key: result.key, value: result.data });
|
||||||
|
};
|
||||||
|
for ( const key of keys ) {
|
||||||
|
const data = keyvalStore[key];
|
||||||
|
const isString = typeof data === 'string';
|
||||||
|
if ( isString === false || dontCompress ) {
|
||||||
|
entries.push({ key, value: data });
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
promises.push(
|
||||||
|
µMatrix.lz4Codec.encode(key, data).then(handleEncodingResult)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const finish = ( ) => {
|
||||||
|
if ( callback === undefined ) { return; }
|
||||||
|
let cb = callback;
|
||||||
|
callback = undefined;
|
||||||
|
cb();
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const results = await Promise.all(promises);
|
||||||
|
const db = results[0];
|
||||||
|
if ( !db ) { return callback(); }
|
||||||
|
const transaction = db.transaction(
|
||||||
|
STORAGE_NAME,
|
||||||
|
'readwrite'
|
||||||
|
);
|
||||||
|
transaction.oncomplete =
|
||||||
|
transaction.onerror =
|
||||||
|
transaction.onabort = finish;
|
||||||
|
const table = transaction.objectStore(STORAGE_NAME);
|
||||||
|
for ( const entry of entries ) {
|
||||||
|
table.put(entry);
|
||||||
|
}
|
||||||
|
} catch (ex) {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteFromDb = async function(input, callback) {
|
||||||
|
if ( typeof callback !== 'function' ) {
|
||||||
|
callback = noopfn;
|
||||||
|
}
|
||||||
|
const keys = Array.isArray(input) ? input.slice() : [ input ];
|
||||||
|
if ( keys.length === 0 ) { return callback(); }
|
||||||
|
const finish = ( ) => {
|
||||||
|
if ( callback === undefined ) { return; }
|
||||||
|
let cb = callback;
|
||||||
|
callback = undefined;
|
||||||
|
cb();
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const db = await getDb();
|
||||||
|
if ( !db ) { return callback(); }
|
||||||
|
const transaction = db.transaction(STORAGE_NAME, 'readwrite');
|
||||||
|
transaction.oncomplete =
|
||||||
|
transaction.onerror =
|
||||||
|
transaction.onabort = finish;
|
||||||
|
const table = transaction.objectStore(STORAGE_NAME);
|
||||||
|
for ( const key of keys ) {
|
||||||
|
table.delete(key);
|
||||||
|
}
|
||||||
|
} catch (ex) {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearDb = async function(callback) {
|
||||||
|
if ( typeof callback !== 'function' ) {
|
||||||
|
callback = noopfn;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const db = await getDb();
|
||||||
|
if ( !db ) { return callback(); }
|
||||||
|
const transaction = db.transaction(STORAGE_NAME, 'readwrite');
|
||||||
|
transaction.oncomplete =
|
||||||
|
transaction.onerror =
|
||||||
|
transaction.onabort = ( ) => {
|
||||||
|
callback();
|
||||||
|
};
|
||||||
|
transaction.objectStore(STORAGE_NAME).clear();
|
||||||
|
}
|
||||||
|
catch(reason) {
|
||||||
|
console.info(`cacheStorage.clearDb() failed: ${reason}`);
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
await getDb();
|
||||||
|
if ( !db ) { return false; }
|
||||||
|
|
||||||
|
api.name = 'indexedDB';
|
||||||
|
api.get = function get(keys) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
if ( keys === null ) {
|
||||||
|
return getAllFromDb(bin => resolve(bin));
|
||||||
|
}
|
||||||
|
let toRead, output = {};
|
||||||
|
if ( typeof keys === 'string' ) {
|
||||||
|
toRead = [ keys ];
|
||||||
|
} else if ( Array.isArray(keys) ) {
|
||||||
|
toRead = keys;
|
||||||
|
} else /* if ( typeof keys === 'object' ) */ {
|
||||||
|
toRead = Object.keys(keys);
|
||||||
|
output = keys;
|
||||||
|
}
|
||||||
|
getFromDb(toRead, output, bin => resolve(bin));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
api.set = function set(keys) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
putToDb(keys, details => resolve(details));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
api.remove = function remove(keys) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
deleteFromDb(keys, ( ) => resolve());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
api.clear = function clear() {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
clearDb(( ) => resolve());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
api.getBytesInUse = function getBytesInUse() {
|
||||||
|
return Promise.resolve(0);
|
||||||
|
};
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/328
|
||||||
|
// Delete cache-related entries from webext storage.
|
||||||
|
const clearWebext = async function() {
|
||||||
|
const bin = await webext.storage.local.get('assetCacheRegistry');
|
||||||
|
if (
|
||||||
|
bin instanceof Object === false ||
|
||||||
|
bin.assetCacheRegistry instanceof Object === false
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const toRemove = [
|
||||||
|
'assetCacheRegistry',
|
||||||
|
'assetSourceRegistry',
|
||||||
|
'resourcesSelfie',
|
||||||
|
'selfie'
|
||||||
|
];
|
||||||
|
for ( const key in bin.assetCacheRegistry ) {
|
||||||
|
if ( bin.assetCacheRegistry.hasOwnProperty(key) ) {
|
||||||
|
toRemove.push('cache/' + key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
webext.storage.local.remove(toRemove);
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearIDB = function() {
|
||||||
|
try {
|
||||||
|
indexedDB.deleteDatabase(STORAGE_NAME);
|
||||||
|
} catch(ex) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return api;
|
||||||
|
}());
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
uBlock Origin - a browser extension to block requests.
|
||||||
|
Copyright (C) 2019-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
|
||||||
|
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 CodeMirror */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
CodeMirror.defineMode('raw-settings', function() {
|
||||||
|
return {
|
||||||
|
token: function(stream) {
|
||||||
|
if ( stream.sol() ) {
|
||||||
|
stream.match(/\s*\S+/);
|
||||||
|
return 'keyword';
|
||||||
|
}
|
||||||
|
stream.skipToEnd();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue