mirror of
https://github.com/gorhill/uBlock.git
synced 2024-11-10 01:02:08 +01:00
Revisit the behavior of the click-to-subscribe content script
Related issue: - https://github.com/uBlockOrigin/uBlock-issues/issues/763 Changes: From now on, uBO will allow click-to-subscribe on only a few select domains, currently: - https://filterlists.com/ - https://github.com/ - https://github.io/ More domains can be added if and only the demonstration is made that more than a marginal number of filter lists can be subscribed from those domains. The browser alert box is no longer used to confirm subscription to a filter list. Instead, the asset viewer has been expanded to serve that purpose. This way, users can peruse at the content of a filter list before subscribing to it.
This commit is contained in:
parent
da7ff2b382
commit
e60042595c
15 changed files with 198 additions and 117 deletions
|
@ -45,8 +45,9 @@
|
|||
},
|
||||
{
|
||||
"matches": [
|
||||
"http://*/*",
|
||||
"https://*/*"
|
||||
"https://filterlists.com/*",
|
||||
"https://github.com/*",
|
||||
"https://*.github.io/*"
|
||||
],
|
||||
"js": [
|
||||
"/js/scriptlets/subscriber.js"
|
||||
|
|
|
@ -55,8 +55,9 @@
|
|||
},
|
||||
{
|
||||
"matches": [
|
||||
"http://*/*",
|
||||
"https://*/*"
|
||||
"https://filterlists.com/*",
|
||||
"https://github.com/*",
|
||||
"https://*.github.io/*"
|
||||
],
|
||||
"js": [
|
||||
"/js/scriptlets/subscriber.js"
|
||||
|
|
|
@ -44,15 +44,16 @@
|
|||
"run_at": "document_start"
|
||||
},
|
||||
{
|
||||
"all_frames": false,
|
||||
"js": [
|
||||
"js/scriptlets/subscriber.js"
|
||||
],
|
||||
"matches": [
|
||||
"http://*/*",
|
||||
"https://*/*"
|
||||
"https://filterlists.com/*",
|
||||
"https://github.com/*",
|
||||
"https://*.github.io/*"
|
||||
],
|
||||
"run_at": "document_idle"
|
||||
"js": [
|
||||
"/js/scriptlets/subscriber.js"
|
||||
],
|
||||
"run_at": "document_idle",
|
||||
"all_frames": false
|
||||
}
|
||||
],
|
||||
"default_locale": "en",
|
||||
|
|
|
@ -36,8 +36,9 @@
|
|||
},
|
||||
{
|
||||
"matches": [
|
||||
"http://*/*",
|
||||
"https://*/*"
|
||||
"https://filterlists.com/*",
|
||||
"https://github.com/*",
|
||||
"https://*.github.io/*"
|
||||
],
|
||||
"js": [
|
||||
"/js/scriptlets/subscriber.js"
|
||||
|
|
|
@ -49,8 +49,9 @@
|
|||
},
|
||||
{
|
||||
"matches": [
|
||||
"http://*/*",
|
||||
"https://*/*"
|
||||
"https://filterlists.com/*",
|
||||
"https://github.com/*",
|
||||
"https://*.github.io/*"
|
||||
],
|
||||
"js": [
|
||||
"/js/scriptlets/subscriber.js"
|
||||
|
|
|
@ -904,8 +904,12 @@
|
|||
"description": "English: Network error: {{msg}}"
|
||||
},
|
||||
"subscriberConfirm": {
|
||||
"message": "uBlock₀: Add the following URL to your custom filter lists?\n\nTitle: \"{{title}}\"\nURL: {{url}}",
|
||||
"description": "English: The message seen by the user to confirm subscription to a ABP filter list"
|
||||
"message": "Add the following URL to your custom filter lists?\n\nTitle: \"{{title}}\"\nURL: {{url}}",
|
||||
"description": "No longer used"
|
||||
},
|
||||
"subscribeButton": {
|
||||
"message": "Subscribe",
|
||||
"description": "For the button used to subscribe to a filter list"
|
||||
},
|
||||
"elapsedOneMinuteAgo": {
|
||||
"message": "a minute ago",
|
||||
|
|
|
@ -11,21 +11,17 @@
|
|||
<link rel="stylesheet" href="css/common.css">
|
||||
<link rel="stylesheet" href="css/fa-icons.css">
|
||||
<link rel="stylesheet" href="css/codemirror.css">
|
||||
<link rel="stylesheet" href="css/asset-viewer.css">
|
||||
<link rel="shortcut icon" type="image/png" href="img/icon_32.png"/>
|
||||
<style>
|
||||
body {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
}
|
||||
#content {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<body class="loading">
|
||||
|
||||
<div id="subscribe" class="hide">
|
||||
<span class="logo"><img data-i18n-title="extName" src="img/ublock.svg"></span>
|
||||
<span id="subscribePrompt"><span></span><a></a></span>
|
||||
<span class="fa-icon">spinner</span>
|
||||
<button id="subscribeButton" type="button" data-i18n="subscribeButton"></button>
|
||||
</div>
|
||||
|
||||
<div id="content" class="codeMirrorContainer codeMirrorBreakAll"></div>
|
||||
|
||||
|
|
77
src/css/asset-viewer.css
Normal file
77
src/css/asset-viewer.css
Normal file
|
@ -0,0 +1,77 @@
|
|||
/**
|
||||
uBlock Origin - a browser extension to block requests.
|
||||
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
|
||||
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
|
||||
*/
|
||||
|
||||
body {
|
||||
border: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
width: 100vw;
|
||||
}
|
||||
#subscribe {
|
||||
background-color: var(--bg-transient-notice);
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
padding: 4px;
|
||||
justify-content: space-between;
|
||||
max-height: 6em;
|
||||
}
|
||||
#subscribe.hide {
|
||||
display: none;
|
||||
}
|
||||
.logo {
|
||||
flex-shrink: 0;
|
||||
width: 2em;
|
||||
}
|
||||
#subscribePrompt {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
padding: 0 0.5em;
|
||||
}
|
||||
#subscribePrompt > span {
|
||||
font-weight: bold;
|
||||
}
|
||||
#subscribePrompt > a {
|
||||
font-size: 14px;
|
||||
word-break: break-all;
|
||||
}
|
||||
#subscribe > button {
|
||||
align-self: center;
|
||||
}
|
||||
#subscribe > .fa-icon {
|
||||
font-size: 20px;
|
||||
}
|
||||
body.loading #subscribe > button,
|
||||
body:not(.loading) #subscribe > .fa-icon {
|
||||
display: none;
|
||||
}
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
body.loading #subscribe > .fa-icon > svg {
|
||||
animation: spin 1s steps(8) infinite;
|
||||
}
|
||||
#content {
|
||||
flex-grow: 1;
|
||||
}
|
|
@ -243,6 +243,16 @@ select {
|
|||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
align-items: center;
|
||||
display: inline-flex;
|
||||
padding: 0 0.5em;
|
||||
width: 1.25em;
|
||||
}
|
||||
.logo > img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ubo-icon {
|
||||
align-items: center;
|
||||
background-color: transparent;
|
||||
|
|
|
@ -21,15 +21,6 @@ html, body {
|
|||
width: 100%;
|
||||
z-index: 10;
|
||||
}
|
||||
#dashboard-nav .logo {
|
||||
align-items: center;
|
||||
display: inline-flex;
|
||||
padding: 0 0.5em;
|
||||
width: 1.25em;
|
||||
}
|
||||
#dashboard-nav .logo > img {
|
||||
width: 100%;
|
||||
}
|
||||
.tabButton {
|
||||
border: 0;
|
||||
border-bottom: 3px solid var(--bg-1);
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
<body>
|
||||
<div id="dashboard-nav">
|
||||
<span class="logo" ><img data-i18n-title="extName" src="img/ublock.svg"></span><!--
|
||||
<span class="logo"><img data-i18n-title="extName" src="img/ublock.svg"></span><!--
|
||||
--><span class="tabButton" data-pane="settings.html" data-i18n="settingsPageName"></span><!--
|
||||
--><span class="tabButton" data-pane="3p-filters.html" data-i18n="3pPageName"></span><!--
|
||||
--><span class="tabButton" data-pane="1p-filters.html" data-i18n="1pPageName"></span><!--
|
||||
|
|
|
@ -26,10 +26,24 @@
|
|||
/******************************************************************************/
|
||||
|
||||
(async ( ) => {
|
||||
const params = new URL(document.location).searchParams;
|
||||
const assetKey = params.get('url');
|
||||
const subscribeURL = new URL(document.location);
|
||||
const subscribeParams = subscribeURL.searchParams;
|
||||
const assetKey = subscribeParams.get('url');
|
||||
if ( assetKey === null ) { return; }
|
||||
|
||||
const subscribeElem = subscribeParams.get('subscribe') !== null
|
||||
? document.getElementById('subscribe')
|
||||
: null;
|
||||
if ( subscribeElem !== null && subscribeURL.hash !== '#subscribed' ) {
|
||||
const title = subscribeParams.get('title');
|
||||
const promptElem = document.getElementById('subscribePrompt');
|
||||
promptElem.children[0].textContent = title;
|
||||
const a = promptElem.children[1];
|
||||
a.textContent = assetKey;
|
||||
a.setAttribute('href', assetKey);
|
||||
subscribeElem.classList.remove('hide');
|
||||
}
|
||||
|
||||
const cmEditor = new CodeMirror(document.getElementById('content'), {
|
||||
autofocus: true,
|
||||
foldGutter: true,
|
||||
|
@ -59,9 +73,30 @@
|
|||
url: assetKey,
|
||||
});
|
||||
cmEditor.setValue(details && details.content || '');
|
||||
|
||||
if ( subscribeElem !== null ) {
|
||||
document.getElementById('subscribeButton').addEventListener(
|
||||
'click',
|
||||
( ) => {
|
||||
subscribeElem.classList.add('hide');
|
||||
vAPI.messaging.send('scriptlets', {
|
||||
what: 'applyFilterListSelection',
|
||||
toImport: assetKey,
|
||||
}).then(( ) => {
|
||||
vAPI.messaging.send('scriptlets', {
|
||||
what: 'reloadAllFilters'
|
||||
});
|
||||
});
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
}
|
||||
|
||||
if ( details.sourceURL ) {
|
||||
const a = document.querySelector('.cm-search-widget .sourceURL');
|
||||
a.setAttribute('href', details.sourceURL);
|
||||
a.setAttribute('title', details.sourceURL);
|
||||
}
|
||||
|
||||
document.body.classList.remove('loading');
|
||||
})();
|
||||
|
|
|
@ -716,6 +716,9 @@ api.get = async function(assetKey, options = {}) {
|
|||
contentURLs = [ assetDetails.contentURL ];
|
||||
} else if ( Array.isArray(assetDetails.contentURL) ) {
|
||||
contentURLs = assetDetails.contentURL.slice(0);
|
||||
} else if ( reIsExternalPath.test(assetKey) ) {
|
||||
assetDetails.content = 'filters';
|
||||
contentURLs = [ assetKey ];
|
||||
}
|
||||
|
||||
for ( const contentURL of contentURLs ) {
|
||||
|
|
|
@ -56,10 +56,10 @@ const onMessage = function(request, sender, callback) {
|
|||
switch ( request.what ) {
|
||||
case 'getAssetContent':
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/417
|
||||
µb.assets.get(
|
||||
request.url,
|
||||
{ dontCache: true, needSourceURL: true }
|
||||
).then(result => {
|
||||
µb.assets.get(request.url, {
|
||||
dontCache: true,
|
||||
needSourceURL: true,
|
||||
}).then(result => {
|
||||
callback(result);
|
||||
});
|
||||
return;
|
||||
|
@ -1611,10 +1611,6 @@ const onMessage = function(request, sender, callback) {
|
|||
logCosmeticFilters(tabId, request);
|
||||
break;
|
||||
|
||||
case 'reloadAllFilters':
|
||||
µb.loadFilterLists();
|
||||
return;
|
||||
|
||||
case 'securityPolicyViolation':
|
||||
response = logCSPViolations(pageStore, request);
|
||||
break;
|
||||
|
@ -1625,10 +1621,16 @@ const onMessage = function(request, sender, callback) {
|
|||
}
|
||||
break;
|
||||
|
||||
case 'subscriberData':
|
||||
response = {
|
||||
confirmStr: vAPI.i18n('subscriberConfirm')
|
||||
};
|
||||
case 'subscribeTo':
|
||||
const url = encodeURIComponent(request.location);
|
||||
const title = encodeURIComponent(request.title);
|
||||
const hash = µb.availableFilterLists[request.location] !== undefined
|
||||
? '#subscribed'
|
||||
: '';
|
||||
vAPI.tabs.open({
|
||||
url: `/asset-viewer.html?url=${url}&title=${title}&subscribe=1${hash}`,
|
||||
select: true,
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -31,91 +31,49 @@
|
|||
/******************************************************************************/
|
||||
|
||||
(( ) => {
|
||||
// >>>>> start of local scope
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/464
|
||||
if ( document instanceof HTMLDocument === false ) {
|
||||
//console.debug('subscriber.js > not a HTLMDocument');
|
||||
return;
|
||||
}
|
||||
if ( document instanceof HTMLDocument === false ) { return; }
|
||||
|
||||
// Because in case
|
||||
if ( typeof vAPI !== 'object' ) {
|
||||
//console.debug('subscriber.js > vAPI not found');
|
||||
return;
|
||||
}
|
||||
// Maybe uBO has gone away meanwhile.
|
||||
if ( typeof vAPI !== 'object' || vAPI === null ) { return; }
|
||||
|
||||
/******************************************************************************/
|
||||
// https://github.com/easylist/EasyListHebrew/issues/89
|
||||
// Ensure trusted events only.
|
||||
|
||||
const processSubscription = async function(location, title) {
|
||||
const details = await vAPI.messaging.send('scriptlets', {
|
||||
what: 'subscriberData',
|
||||
});
|
||||
const onMaybeSubscriptionLinkClicked = function(ev) {
|
||||
if ( ev.button !== 0 || ev.isTrusted === false ) { return; }
|
||||
|
||||
const confirmStr = details.confirmStr
|
||||
.replace('{{url}}', location)
|
||||
.replace('{{title}}', title);
|
||||
if ( window.confirm(confirmStr) === false ) { return; }
|
||||
const target = ev.target.closest('a');
|
||||
if ( target instanceof HTMLAnchorElement === false ) { return; }
|
||||
|
||||
await vAPI.messaging.send('scriptlets', {
|
||||
what: 'applyFilterListSelection',
|
||||
toImport: location,
|
||||
});
|
||||
|
||||
vAPI.messaging.send('scriptlets', {
|
||||
what: 'reloadAllFilters',
|
||||
});
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const onMaybeAbpLinkClicked = function(ev) {
|
||||
if ( ev.button !== 0 ) { return; }
|
||||
// This addresses https://github.com/easylist/EasyListHebrew/issues/89
|
||||
// Also, as per feedback to original fix:
|
||||
// https://github.com/gorhill/uBlock/commit/99a3d9631047d33dc7a454296ab3dd0a1e91d6f1
|
||||
const target = ev.target;
|
||||
if (
|
||||
ev.isTrusted === false ||
|
||||
target instanceof HTMLAnchorElement === false
|
||||
) {
|
||||
if ( vAPI instanceof Object === false ) {
|
||||
document.removeEventListener('click', onMaybeSubscriptionLinkClicked);
|
||||
return;
|
||||
}
|
||||
|
||||
const href = target.href || '';
|
||||
if ( href === '' ) { return; }
|
||||
const matches = /^(?:abp|ubo):\/*subscribe\/*\?location=([^&]+).*title=([^&]+)/.exec(href);
|
||||
if ( matches === null ) { return; }
|
||||
|
||||
let matches = /^(?:abp|ubo):\/*subscribe\/*\?location=([^&]+).*title=([^&]+)/.exec(href);
|
||||
if ( matches === null ) {
|
||||
matches = /^https?:\/\/.*?[&?]location=([^&]+).*?&title=([^&]+)/.exec(href);
|
||||
if ( matches === null ) { return; }
|
||||
}
|
||||
|
||||
const location = decodeURIComponent(matches[1]);
|
||||
const title = decodeURIComponent(matches[2]);
|
||||
|
||||
processSubscription(location, title);
|
||||
vAPI.messaging.send('scriptlets', {
|
||||
what: 'subscribeTo',
|
||||
location: decodeURIComponent(matches[1]),
|
||||
title: decodeURIComponent(matches[2]),
|
||||
});
|
||||
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Only if at least one subscribe link exists on the page.
|
||||
|
||||
setTimeout(function() {
|
||||
if (
|
||||
document.querySelector('link[rel="canonical"][href="https://filterlists.com/"]') !== null ||
|
||||
document.querySelector('a[href^="abp:"],a[href^="ubo:"],a[href^="https://subscribe.adblockplus.org/?"]') !== null
|
||||
) {
|
||||
document.addEventListener('click', onMaybeAbpLinkClicked);
|
||||
}
|
||||
}, 997);
|
||||
document.addEventListener('click', onMaybeSubscriptionLinkClicked);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// <<<<< end of local scope
|
||||
})();
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue