mirror of
https://github.com/anticensority/runet-censorship-bypass.git
synced 2024-11-23 18:03:44 +03:00
Add js-logic to the popup's pacChooser form. Remove code related to CopyUnicodeUrls
This commit is contained in:
parent
bc75c74c8a
commit
0eb6194bc6
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "runet-censorship-bypass",
|
"name": "runet-censorship-bypass",
|
||||||
"version": "0.2.0",
|
"version": "0.0.2",
|
||||||
"description": "",
|
"description": "",
|
||||||
"homepage": "https://github.com/ilyaigpetrov/copy-unicode-urls#readme",
|
"homepage": "https://github.com/ilyaigpetrov/copy-unicode-urls#readme",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
|
@ -20,7 +20,6 @@
|
||||||
},
|
},
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"punycode": "^2.1.1"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"merge": "^2.1.1",
|
"merge": "^2.1.1",
|
||||||
|
|
|
@ -3,12 +3,8 @@ import { versions, storage } from '../lib/index.mjs';
|
||||||
globalThis.migrationPromise = new Promise(async (resolve) => {
|
globalThis.migrationPromise = new Promise(async (resolve) => {
|
||||||
console.log('Checking for migrations...');
|
console.log('Checking for migrations...');
|
||||||
const dflts = {
|
const dflts = {
|
||||||
options: [
|
// TODO: Define defaults.
|
||||||
[ 'ifToDecode', true ],
|
options: {},
|
||||||
[ 'ifToDecodeMultipleTimes', false ],
|
|
||||||
[ 'ifToEncodeUrlTerminators', true ],
|
|
||||||
],
|
|
||||||
donateUrl: 'https://rebrand.ly/ilya-donate',
|
|
||||||
};
|
};
|
||||||
const ifEmpty = await storage.isEmptyAsync();
|
const ifEmpty = await storage.isEmptyAsync();
|
||||||
if (ifEmpty) {
|
if (ifEmpty) {
|
||||||
|
@ -23,21 +19,20 @@ globalThis.migrationPromise = new Promise(async (resolve) => {
|
||||||
console.log(`Current extension version is ${versions.current}.`);
|
console.log(`Current extension version is ${versions.current}.`);
|
||||||
const oldVersion = await storage.getAsync('version');
|
const oldVersion = await storage.getAsync('version');
|
||||||
const ifNoNeedToMigrate = oldVersion === versions.current;
|
const ifNoNeedToMigrate = oldVersion === versions.current;
|
||||||
if (ifNoNeedToMigrate) {http://я.рф/яhttp://я.рф/я
|
if (ifNoNeedToMigrate) {
|
||||||
console.log('No need for migration.');
|
console.log('No need for migration.');
|
||||||
return resolve();
|
return resolve();
|
||||||
}
|
}
|
||||||
console.log(`Migrating to ${versions.current} from ${oldVersion || 'a very old version'}.`);
|
console.log(`Migrating to ${versions.current} from ${oldVersion || 'a very old version'}.`);
|
||||||
switch(true) {
|
switch(true) {
|
||||||
case !oldVersion: {
|
case !oldVersion: {
|
||||||
// Update from version <= 0.0.18.
|
// Update from version <= 0.0.1.
|
||||||
const ifSentence = await storage.getAsync('ifToEncodeSentenceTerminators');
|
const ifSentence = await storage.getAsync('SOME_KEY');
|
||||||
if (ifSentence !== undefined) {
|
if (ifSentence !== undefined) {
|
||||||
console.log('Migrating to 0.0.18.');
|
console.log('Migrating to 0.0.1.');
|
||||||
await storage.setAsync({
|
await storage.setAsync({
|
||||||
ifToEncodeUrlTerminators: ifSentence,
|
ifToEncodeUrlTerminators: ifSentence,
|
||||||
});
|
});
|
||||||
await storage.removeAsync('ifToEncodeSentenceTerminators')
|
|
||||||
}
|
}
|
||||||
}; // Fallthrough.
|
}; // Fallthrough.
|
||||||
case versions.isLeq(oldVersion, '0.0.18'): {
|
case versions.isLeq(oldVersion, '0.0.18'): {
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
import { toUnicode } from '../../node_modules/punycode/punycode.es6.js';
|
|
||||||
import { copyToClipboardAsync } from '../lib/copy-to-clipboard.mjs';
|
|
||||||
import { storage } from '../lib/index.mjs';
|
import { storage } from '../lib/index.mjs';
|
||||||
|
|
||||||
|
console.log('Main script starts...');
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const theState = await storage.getAsync();
|
||||||
|
console.log('The state is:', theState);
|
||||||
|
})();
|
||||||
|
|
||||||
|
/*
|
||||||
const ID_TO_MENU_HANDLER = {};
|
const ID_TO_MENU_HANDLER = {};
|
||||||
|
|
||||||
const createMenuEntry = (id, type, title, handler, contexts, rest) => {
|
const createMenuEntry = (id, type, title, handler, contexts, rest) => {
|
||||||
|
@ -27,63 +33,6 @@ const copyUrlInstalledPromise = (async () => {
|
||||||
console.log('Migration is finished.');
|
console.log('Migration is finished.');
|
||||||
|
|
||||||
const options = await storage.getAsync('options');
|
const options = await storage.getAsync('options');
|
||||||
const getOpt = (key) => (options.find((el) => el[0] === key)[1]);
|
|
||||||
console.log('Options are:', options);
|
|
||||||
|
|
||||||
const localizeUrl = (url) => {
|
|
||||||
console.log('Localizing url:', url);
|
|
||||||
let u;
|
|
||||||
try {
|
|
||||||
u = new URL(url);
|
|
||||||
} catch {
|
|
||||||
u = new URL(`http://${url}`);
|
|
||||||
}
|
|
||||||
let newHref = u.href;
|
|
||||||
let oldHref;
|
|
||||||
do {
|
|
||||||
oldHref = newHref;
|
|
||||||
newHref = decodeURI(
|
|
||||||
newHref
|
|
||||||
.replace(u.hostname, toUnicode(u.hostname))
|
|
||||||
/*
|
|
||||||
Don't decode `%25` to `%` because it causes errors while being put in GitHub URLs.
|
|
||||||
Test case: https://github.com/ilyaigpetrov/copy-unicode-urls/wiki/Test-%25-and-%3F
|
|
||||||
*/
|
|
||||||
.replaceAll('%25', '%2525'),
|
|
||||||
)
|
|
||||||
// Encode whitespace.
|
|
||||||
.replace(
|
|
||||||
/\s/g,
|
|
||||||
(_, index, wholeString) => encodeURIComponent(wholeString.charAt(index)),
|
|
||||||
);
|
|
||||||
} while (getOpt('ifToDecodeMultipleTimes') && oldHref !== newHref);
|
|
||||||
console.log('Localized:', newHref);
|
|
||||||
return newHref;
|
|
||||||
};
|
|
||||||
|
|
||||||
const copyUrl = async (url) => {
|
|
||||||
if (getOpt('ifToDecode')) {
|
|
||||||
url = localizeUrl(url);
|
|
||||||
}
|
|
||||||
if (getOpt('ifToEncodeUrlTerminators')) {
|
|
||||||
console.log('Encoding terminators...');
|
|
||||||
/*
|
|
||||||
Issue #7.
|
|
||||||
Thunderbird sources:
|
|
||||||
https://searchfox.org/comm-central/source/mozilla/netwerk/streamconv/converters/mozTXTToHTMLConv.cpp#281 (mozTXTToHTMLConv::FindURLEnd)
|
|
||||||
These chars terminate the URL: ><"`}{)]`
|
|
||||||
These sequence doesn't terminate the URL: //[ (e.g. http://[1080::...)
|
|
||||||
These chars are not allowed at the end of the URL: .,;!?-:'
|
|
||||||
I apply slightly more strict rules below.
|
|
||||||
**/
|
|
||||||
const toPercentCode = (char) => '%' + char.charCodeAt(0).toString(16).toUpperCase();
|
|
||||||
url = url.replace(
|
|
||||||
/(?:[<>{}()[\]"`']|[.,;:!?-]$)/g,
|
|
||||||
(matchedChar, index, wholeString) => toPercentCode(matchedChar),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
copyToClipboardAsync(url);
|
|
||||||
};
|
|
||||||
|
|
||||||
// CheckBoxes
|
// CheckBoxes
|
||||||
const capitalizeFirstLetter = (str) => str
|
const capitalizeFirstLetter = (str) => str
|
||||||
|
@ -137,12 +86,12 @@ const copyUrlInstalledPromise = (async () => {
|
||||||
'copyHighlightLink', 'normal',
|
'copyHighlightLink', 'normal',
|
||||||
chrome.i18n.getMessage('CopyUnicodeLinkToHighlight'),
|
chrome.i18n.getMessage('CopyUnicodeLinkToHighlight'),
|
||||||
(info) => {
|
(info) => {
|
||||||
copyUrl(`${info.pageUrl.replace(/#.*/g, '')}#:~:text=${info.selectionText}`);
|
copyUrl(`${info.pageUrl.replace(/#.*\/g, '')}#:~:text=${info.selectionText}`);
|
||||||
},
|
},
|
||||||
['selection'],
|
['selection'],
|
||||||
);
|
);
|
||||||
|
|
||||||
return copyUrl;
|
return Promise.resolve();
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
@ -162,5 +111,6 @@ chrome.action.onClicked.addListener(async ({ url: urlToBeCopied }) => {
|
||||||
console.log('Main waits for listeners to be installed...');
|
console.log('Main waits for listeners to be installed...');
|
||||||
const copyUrl = await copyUrlInstalledPromise;
|
const copyUrl = await copyUrlInstalledPromise;
|
||||||
console.log('Action clicked with url:', urlToBeCopied);
|
console.log('Action clicked with url:', urlToBeCopied);
|
||||||
copyUrl(urlToBeCopied);
|
//copyUrl(urlToBeCopied);
|
||||||
});
|
});
|
||||||
|
*/
|
|
@ -1,5 +1,5 @@
|
||||||
import "./00-start.mjs";
|
import './00-start.mjs';
|
||||||
import "./05-data-init-and-migrations.mjs";
|
import './05-data-init-and-migrations.mjs';
|
||||||
import "./10-main.mjs";
|
import './10-main.mjs';
|
||||||
|
|
||||||
console.log('Background script finished loading.');
|
console.log('Background script finished loading.');
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
let IF_ALREADY_PROMISE; // A global promise to avoid concurrency issues.
|
|
||||||
const OFFSCREEN_DOC_PATH = '/src/lib/offscreen-doc-for-copying.html';
|
|
||||||
|
|
||||||
export const copyToClipboardAsync = async (copyMe) => {
|
|
||||||
console.log('Going to copy this url:', copyMe);
|
|
||||||
try {
|
|
||||||
console.log('Trying `navigator.clipboard`...');
|
|
||||||
return await navigator.clipboard.writeText(copyMe);
|
|
||||||
} catch(e) {
|
|
||||||
console.log('Got error while copying attempt:', e);
|
|
||||||
if (globalThis.document) {
|
|
||||||
console.log('Trying `globalThis.document`...');
|
|
||||||
const area = document.createElement('textarea');
|
|
||||||
area.value = copyMe;
|
|
||||||
document.body.appendChild(area);
|
|
||||||
area.select();
|
|
||||||
document.execCommand('copy');
|
|
||||||
document.body.removeChild(area);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.log('Trying `chrome.offscreen`...');
|
|
||||||
|
|
||||||
async function setupOffscreenDocument(path) {
|
|
||||||
// Check all windows controlled by the service worker to see if one
|
|
||||||
// of them is the offscreen document with the given path
|
|
||||||
const offscreenUrl = chrome.runtime.getURL(path);
|
|
||||||
const existingContexts = await chrome.runtime.getContexts({
|
|
||||||
contextTypes: ['OFFSCREEN_DOCUMENT'],
|
|
||||||
documentUrls: [offscreenUrl],
|
|
||||||
});
|
|
||||||
console.log('Existing contexts:', existingContexts);
|
|
||||||
|
|
||||||
if (existingContexts.length > 0) {
|
|
||||||
console.log('Offscreen document already exists.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create offscreen document
|
|
||||||
if (IF_ALREADY_PROMISE) {
|
|
||||||
return IF_ALREADY_PROMISE;
|
|
||||||
}
|
|
||||||
console.log('Creating new offscreen document for:', path);
|
|
||||||
IF_ALREADY_PROMISE = chrome.offscreen.createDocument({
|
|
||||||
url: path,
|
|
||||||
reasons: [chrome.offscreen.Reason.CLIPBOARD],
|
|
||||||
justification: 'reason for needing the document',
|
|
||||||
});
|
|
||||||
await IF_ALREADY_PROMISE;
|
|
||||||
console.log('New offscreen document created.');
|
|
||||||
IF_ALREADY_PROMISE = null;
|
|
||||||
}
|
|
||||||
await setupOffscreenDocument(OFFSCREEN_DOC_PATH);
|
|
||||||
// Now that we have an offscreen document, we can dispatch the
|
|
||||||
// message.
|
|
||||||
chrome.runtime.sendMessage({
|
|
||||||
type: 'copy-data-to-clipboard',
|
|
||||||
target: 'offscreen-doc',
|
|
||||||
data: copyMe,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,3 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<textarea id="text"></textarea>
|
|
||||||
<script src="./offscreen-doc-for-copying.mjs" type="module"></script>
|
|
|
@ -1,74 +0,0 @@
|
||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// Once the message has been posted from the service worker, checks are made to
|
|
||||||
// confirm the message type and target before proceeding. This is so that the
|
|
||||||
// module can easily be adapted into existing workflows where secondary uses for
|
|
||||||
// the document (or alternate offscreen documents) might be implemented.
|
|
||||||
|
|
||||||
// Registering this listener when the script is first executed ensures that the
|
|
||||||
// offscreen document will be able to receive messages when the promise returned
|
|
||||||
// by `offscreen.createDocument()` resolves.
|
|
||||||
chrome.runtime.onMessage.addListener(handleMessages);
|
|
||||||
|
|
||||||
// This function performs basic filtering and error checking on messages before
|
|
||||||
// dispatching the
|
|
||||||
// message to a more specific message handler.
|
|
||||||
async function handleMessages(message) {
|
|
||||||
// Return early if this message isn't meant for the offscreen document.
|
|
||||||
if (message.target !== 'offscreen-doc') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dispatch the message to an appropriate handler.
|
|
||||||
switch (message.type) {
|
|
||||||
case 'copy-data-to-clipboard':
|
|
||||||
handleClipboardWrite(message.data);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
console.warn(`Unexpected message type received: '${message.type}'.`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We use a <textarea> element for two main reasons:
|
|
||||||
// 1. preserve the formatting of multiline text,
|
|
||||||
// 2. select the node's content using this element's `.select()` method.
|
|
||||||
const textEl = document.querySelector('#text');
|
|
||||||
|
|
||||||
// Use the offscreen document's `document` interface to write a new value to the
|
|
||||||
// system clipboard.
|
|
||||||
//
|
|
||||||
// At the time this demo was created (Jan 2023) the `navigator.clipboard` API
|
|
||||||
// requires that the window is focused, but offscreen documents cannot be
|
|
||||||
// focused. As such, we have to fall back to `document.execCommand()`.
|
|
||||||
async function handleClipboardWrite(data) {
|
|
||||||
try {
|
|
||||||
// Error if we received the wrong kind of data.
|
|
||||||
if (typeof data !== 'string') {
|
|
||||||
throw new TypeError(
|
|
||||||
`Value provided must be a 'string', got '${typeof data}'.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// `document.execCommand('copy')` works against the user's selection in a web
|
|
||||||
// page. As such, we must insert the string we want to copy to the web page
|
|
||||||
// and to select that content in the page before calling `execCommand()`.
|
|
||||||
textEl.value = data;
|
|
||||||
textEl.select();
|
|
||||||
document.execCommand('copy');
|
|
||||||
} finally {
|
|
||||||
// Job's done! Close the offscreen document.
|
|
||||||
window.close();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -40,11 +40,13 @@
|
||||||
same even after invertion. Also a flash/blink of colors
|
same even after invertion. Also a flash/blink of colors
|
||||||
during invertion must be avoided.
|
during invertion must be avoided.
|
||||||
*/
|
*/
|
||||||
|
/*
|
||||||
background-color: white; /* Not transparent. */
|
background-color: white; /* Not transparent. */
|
||||||
color: black;
|
/*color: black;
|
||||||
|
/*
|
||||||
border: 0 none white;
|
border: 0 none white;
|
||||||
outline: 0 none white;
|
outline: 0 none white;*/
|
||||||
color-scheme: light;
|
/*color-scheme: light;
|
||||||
/* COLOR INVERTION */
|
/* COLOR INVERTION */
|
||||||
filter: invert(0); /* TODO: temporary disabled. */
|
filter: invert(0); /* TODO: temporary disabled. */
|
||||||
}
|
}
|
||||||
|
@ -79,8 +81,8 @@
|
||||||
vertical-align: text-bottom;
|
vertical-align: text-bottom;
|
||||||
}
|
}
|
||||||
input[type="url"] {
|
input[type="url"] {
|
||||||
border-width: 0 0 1px 0;
|
/*border-width: 0 0 1px 0;
|
||||||
border-color: crimson;
|
border-color: crimson;*/
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
/*padding: 0 3px 0 3px;*/
|
/*padding: 0 3px 0 3px;*/
|
||||||
/*width: 100%;*/
|
/*width: 100%;*/
|
||||||
|
@ -88,6 +90,14 @@
|
||||||
input[type="radio"], label {
|
input[type="radio"], label {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
#disabled:checked + label {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.nowrap {
|
||||||
|
/* Don't break sentences on spaces. */
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
#own:checked + label:after {
|
#own:checked + label:after {
|
||||||
content: ":";
|
content: ":";
|
||||||
|
@ -96,14 +106,17 @@
|
||||||
#own ~ div {
|
#own ~ div {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
#disabled:checked + label {
|
/*
|
||||||
color: crimson;
|
input#own ~ div:has(> input#customPacUrl):after {
|
||||||
|
border: 5px solid lime;
|
||||||
|
background-color: navy;
|
||||||
|
content: "";
|
||||||
}
|
}
|
||||||
|
input#own ~ div:after:not(:empty) {
|
||||||
|
border: 5px solid pink;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
div.nowrap {
|
|
||||||
/* Don't break sentences on spaces. */
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.use-preferred-color-scheme {
|
.use-preferred-color-scheme {
|
||||||
/*background-color: violet;
|
/*background-color: violet;
|
||||||
color: darkred;*/
|
color: darkred;*/
|
||||||
|
@ -134,40 +147,53 @@
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
/*
|
||||||
|
input:invalid {
|
||||||
|
border: 5px solid red;
|
||||||
|
}*/
|
||||||
|
#customPacUrl:disabled {
|
||||||
|
/*background-color: grey;*/
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body class="use-preferred-color-scheme">
|
<body class="use-preferred-color-scheme">
|
||||||
<!--img src="./gsbg.png" class="gsbg"-->
|
<!--img src="./gsbg.png" class="gsbg"-->
|
||||||
<header>
|
<header>
|
||||||
PAC-script:
|
PAC-скрипт:
|
||||||
</header>
|
</header>
|
||||||
<nav>
|
<nav>
|
||||||
<ul>
|
<form id="pacChooserForm">
|
||||||
<li>
|
<ul>
|
||||||
<input type="radio" value="antizapret" name="pacScript" id="antizapret">
|
<li>
|
||||||
<label for="antizapret">Антизапрет</label>
|
<input type="radio" value="antizapret" name="pacScript" id="antizapret">
|
||||||
</li>
|
<label for="antizapret">Антизапрет</label>
|
||||||
<li>
|
</li>
|
||||||
<input type="radio" value="anticensority" name="pacScript" id="anticensority">
|
<li>
|
||||||
<label for="anticensority">Антицензорити</label>
|
<input type="radio" value="anticensority" name="pacScript" id="anticensority">
|
||||||
</li>
|
<label for="anticensority">Антицензорити</label>
|
||||||
<li>
|
</li>
|
||||||
<input type="radio" value="own" name="pacScript" id="own">
|
<li>
|
||||||
<label for="own">Свой:</label>
|
<input type="radio" value="own" name="pacScript" id="own" disabled>
|
||||||
<div>
|
<label for="own">Свой:</label>
|
||||||
<input type="url" placeholder="https://example.com/proxy.pac">
|
<div>
|
||||||
<button>Save</button>
|
<input id="customPacUrl" type="url" placeholder="https://example.com/proxy.pac"
|
||||||
</div>
|
size="27"
|
||||||
</li>
|
spellcheck="false" autocorrect="off" autocapitalize="off"
|
||||||
<li>
|
disabled required
|
||||||
<input type="radio" value="disabled" name="pacScript" id="disabled" checked>
|
>
|
||||||
<label for="disabled">Отключить / сброс</label>
|
<button id="editPacUrlButton" title="Редактировать">🖉</button>
|
||||||
</li>
|
</div>
|
||||||
</ul>
|
</li>
|
||||||
<div class="nowrap">
|
<li>
|
||||||
<input type="checkbox" name="reset" id="reset" checked>
|
<input type="radio" value="disabled" name="pacScript" id="disabled" checked>
|
||||||
<label for="reset">Сбрасывать перед переключением</label>
|
<label for="disabled">Отключить / сброс</label>
|
||||||
</div>
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div class="nowrap">
|
||||||
|
<input type="checkbox" name="reset" id="reset" checked>
|
||||||
|
<label for="reset">Сбрасывать перед переключением</label>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</nav>
|
</nav>
|
||||||
<footer style="text-align: center">
|
<footer style="text-align: center">
|
||||||
<a id="donate" target="_blank" data-localize="__MSG_Donate__"
|
<a id="donate" target="_blank" data-localize="__MSG_Donate__"
|
||||||
|
|
|
@ -1,3 +1,41 @@
|
||||||
|
console.log('Options page is opening...');
|
||||||
|
|
||||||
|
pacChooserForm.addEventListener('change', function (event) {
|
||||||
|
console.log('ON CHANGE:', event);
|
||||||
|
pacChooserForm.reportValidity();
|
||||||
|
});
|
||||||
|
|
||||||
|
pacChooserForm.addEventListener('formdata', (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
console.log('ON FORMDATA', event);
|
||||||
|
return false; // Prevent default action.
|
||||||
|
});
|
||||||
|
|
||||||
|
editPacUrlButton.onclick = function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
const lockUrl = () => { customPacUrl.disabled = true; };
|
||||||
|
const unlockUrl = () => { customPacUrl.disabled = false; };
|
||||||
|
const ifUrlLocked = customPacUrl.disabled;
|
||||||
|
if (ifUrlLocked) {
|
||||||
|
unlockUrl();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const ifUrlValid = customPacUrl.checkValidity();
|
||||||
|
if (ifUrlValid) {
|
||||||
|
lockUrl();
|
||||||
|
own.disabled = false;
|
||||||
|
// TODO: Save to storage.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Empty or incorrect url.
|
||||||
|
own.disabled = true; // `own.checked` doesn't matter here.
|
||||||
|
const ifUrlEmpty = !customPacUrl.value;
|
||||||
|
if (ifUrlEmpty) {
|
||||||
|
lockUrl();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
/*
|
/*
|
||||||
import { storage } from '../../lib/common-apis.mjs';
|
import { storage } from '../../lib/common-apis.mjs';
|
||||||
|
|
||||||
|
@ -18,6 +56,8 @@ options.forEach(([key, value], i) => {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
*/
|
*/
|
||||||
|
await chrome.storage.local.get('options');
|
||||||
|
|
||||||
const textElements = document.querySelectorAll('[data-localize]');
|
const textElements = document.querySelectorAll('[data-localize]');
|
||||||
textElements.forEach((e) => {
|
textElements.forEach((e) => {
|
||||||
const ref = e.dataset.localize;
|
const ref = e.dataset.localize;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user