📝 Added entire config directory for backup purposes

This commit is contained in:
z3rOR0ne 2022-11-03 00:09:22 -07:00
parent 4b38e59bb6
commit 9b946e2d14
11091 changed files with 1440953 additions and 0 deletions

View file

@ -0,0 +1,142 @@
/*
* NoScript - a Firefox extension for whitelist driven safe JavaScript execution
*
* Copyright (C) 2005-2021 Giorgio Maone <https://maone.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* 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 <https://www.gnu.org/licenses/>.
*/
var Prompts = (() => {
var promptData;
var backlog = [];
class WindowManager {
async open(data) {
promptData = data;
this.close();
let {width, height} = data.features;
let options = {
url: browser.runtime.getURL("ui/prompt.html"),
type: "panel",
width,
height,
};
if (UA.isMozilla) {
options.allowScriptsToClose = true;
}
if (!("windows" in browser)) {
// Android, most likely
this.currentTab = await browser.tabs.create({url: options.url});
return;
}
this.currentWindow = await browser.windows.create(options);
// work around for https://bugzilla.mozilla.org/show_bug.cgi?id=1330882
let {left, top, width: cw, height: ch} = this.currentWindow;
if (width && height && cw !== width || ch !== height) {
left += Math.round((cw - width) / 2);
top += Math.round((ch - height) / 2);
for (let attempts = 2; attempts-- > 0;) // top gets set only 2nd time, moz bug?
await browser.windows.update(this.currentWindow.id,
{left, top, width, height});
}
}
async close() {
if (this.currentWindow) {
try {
await browser.windows.remove(this.currentWindow.id);
} catch (e) {
debug(e);
}
this.currentWindow = null;
} else if (this.currentTab) {
await browser.tabs.remove(this.currentTab.id);
}
}
async focus() {
if (this.currentWindow) {
try {
await browser.windows.update(this.currentWindow.id,
{
focused: true,
}
);
} catch (e) {
error(e, "Focusing popup window");
}
}
}
}
var winMan = new WindowManager();
var Prompts = {
DEFAULTS: {
title: "",
message: "Proceed?",
options: [],
checks: [],
buttons: [_("Ok"), _("Cancel")],
multiple: "close", // or "queue", or "focus"
width: 500,
height: 400,
alwaysOnTop: true,
},
async prompt(features) {
features = Object.assign({}, this.DEFAULTS, features || {});
return new Promise((resolve, reject) => {
let data = {
features,
result: {
button: -1,
checks: [],
option: null,
},
done() {
this.done = () => {};
winMan.close();
resolve(this.result);
if (promptData === this) {
promptData = null;
if (backlog.length) {
winMan.open(backlog.shift());
}
}
}
};
if (promptData) {
backlog.push(data);
switch(promptData.features.multiple) {
case "focus":
winMan.focus();
case "queue":
break;
default:
promptData.done();
}
} else {
winMan.open(data);
}
});
},
get promptData() {
return promptData;
}
}
return Prompts;
})();

View file

@ -0,0 +1,172 @@
/*
* Copyright (C) 2005-2022 Giorgio Maone <https://maone.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
@import url(../common/themes.css);
body {
background-color: var(--bg-color2);
color: var(--text-color);
font-size: 12px;
font-family: sistem-ui, sans-serif;
font: use-system-font;
}
html.mobile > body {
font-family: Inter, sans-serif;
font-size: 4mm;
}
html.mobile .desktop {
display: none !important;
}
html:not(.tor) .tor, html.tor .not-tor {
display: none;
}
html.tor .tor, html:not(.tor) .not-tor {
display: initial;
}
a, a:visited {
color: var(--accent-color);
}
button, .button {
appearance: none;
background: var(--form-color1);
border: 1px solid var(--fg-color1);
border-radius: .5em;
color: var(--text-color);
font-weight: bold;
padding: .6em;
cursor: pointer;
text-decoration: none;
}
input[type="text"], textarea, select {
color: var(--text-color);
background-color: var(--bg-color2);
border: 1px solid var(--fg-color1);
border-radius: .4em;
padding: 0.5em;
margin: 0.5em;
}
input[type="checkbox"]:not(.https-only, .temp) {
-webkit-appearance: none;
appearance: none;
margin: .4em;
font: inherit;
color: currentColor;
width: 1.2em;
height: 1.2em;
min-width: 1.2em;
border: 0.15em solid currentColor;
border-radius: 0.3em;
transform: translateY(-0.075em);
display: grid;
place-content: center;
background-color: var(--form-color1);
}
input[type="checkbox"]:not(.https-only, .temp)::before {
content: "";
width: 0.7em;
height: 0.7em;
clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
transform: scale(0);
transform-origin: bottom left;
transition: 120ms transform ease-in-out;
box-shadow: inset 1em 1em var(--form-check-color);
}
input[type="checkbox"]:not(.https-only, .temp):checked::before {
transform: scale(1);
}
input[type="checkbox"]:not(.https-only, .temp):checked {
background-color: var(--form-check-bg-color);
border-color: var(--form-check-bg-color);
}
input[type="radio"]:not(.preset) {
-webkit-appearance: none;
appearance: none;
background-color: var(--form-color1);
margin: .4em;
font: inherit;
color: currentColor;
width: 1.2em;
height: 1.2em;
min-width: 1.2em;
border: 0.15em solid currentColor;
border-radius: 50%;
transform: translateY(-0.075em);
display: grid;
place-content: center;
}
input[type="radio"]:not(.preset)::before {
content: "";
width: 0.7em;
height: 0.7em;
border-radius: 50%;
transform: scale(0);
transition: 120ms transform ease-in-out;
box-shadow: inset 1em 1em var(--form-radio-color);
background-color: CanvasText;
}
input[type="radio"]:not(.preset):checked::before {
transform: scale(1);
}
input[type="radio"]:not(.preset):checked {
background-color: var(--form-radio-bg-color);
}
input:disabled, button:disabled, select:disabled {
filter: grayscale(100%) contrast(33%) !important;
opacity: .7;
}
:disabled {
cursor: not-allowed !important;
}
:focus-visible, :is(.cap.needed, .switch):focus-within {
outline: 0;
filter:
drop-shadow(1px 1px 1px var(--focus-color))
drop-shadow(-1px -1px 1px var(--focus-color))
drop-shadow(1px -1px 1px var(--focus-color))
drop-shadow(-1px -1px 1px var(--focus-color)) !important;
}
:is(label, .full-address, .full-address *):is(:focus, :focus-visible) {
text-shadow: 0 0 .1em var(--focus-color);
filter: none !important;
}
.donate {
color: var(--text-color1) !important;
border-color: transparent;
background-color: transparent;
transform: scale(1.2);
transition: all .5s ease-in-out;
text-transform: uppercase;
}
.donate:hover {
transform: scale(1.8);
}
.donate:before {
content: "♥";
color: var(--accent-color);
padding: 0 .2em 0 .5em;
text-shadow: 0.04em 0.04em 0.04em #0004;
}

View file

@ -0,0 +1,240 @@
/*
* Copyright (C) 2005-2021 Giorgio Maone <https://maone.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
@import url(slider.css);
body {
background: var(--img-noscript-options) no-repeat fixed top right;
background-size: 7em;
padding: 0 2em 0 0;
margin: 0.5em 0.5em 0.5em 0.5em;
}
#header {
display: flex;
flex-flow: row wrap;
padding: 0;
margin: 0 6em 0 0;
align-items: center;
justify-content: space-between;
}
#header h1 {
color: var(--accent-color);
text-shadow: 0.06em 0.06em 0.06em #0008;
font-size: 2em;
padding: 0;
margin: 0;
text-align: right;
}
#version {
color: var(--text-color);
font-size: 0.75em;
padding: 0;
margin: 0 0 0.5em;
display: block;
text-align: right;
}
.buttons {
display: flex;
flex-flow: row wrap;
justify-content: flex-end;
margin: 0 0 1em 0;
}
.buttons :is(button, .button) {
margin: .5em;
}
#sect-general {
display: flex;
flex-direction: column;
justify-content: space-around;
font-size: 1em;
}
section fieldset {
margin: 1em 0;
padding: .5em 1em;
}
section > form {
padding: 0 .5em;
}
fieldset:disabled {
opacity: .5;
}
.sect-sites form {
display: flex;
align-items: baseline;
flex-wrap: wrap;
justify-content: space-between;
}
.sect-sites form > label {
white-space: nowrap;
}
#newsite {
flex: 2 2;
}
#policy {
display: block;
margin-top: .5em;
min-height: 20em;
width: 90%;
}
.hide, body:not(.debug) div.debug {
display: none;
}
#debug-tools {
padding-left: 2.5em;
font-weight: bold;
}
.error {
background: #ff8;
color: red;
}
#policy-error {
background: red;
color: #ff8;
padding: 0;
margin: 0;
font-weight: bold;
}
input, button {
font-size: 1em;
}
button.add {
font-size: 1.4em;
padding: .2em .4em;
}
#import-container {
position: relative;
display: flex;
}
#file-import {
position: absolute;
top: 0;
left: 0;
opacity: 0;
width: 100%;
padding: 0;
margin: 0;
border: none;
-moz-appearance: none;
appearance: none;
}
#xssFaq {
white-space: nowrap;
}
#clearclick-options {
display: none;
}
.flextabs__tab {
/* shift all tabs to appear before content */
order: -1;
/* let tabs scale to fit multiple on each row */
width: auto;
margin: 0;
}
.flextabs__content--active {
/* ignore states activated for multi (accordion) toggle view */
display: none;
}
.flextabs__content--active--last {
/* show the last activated item */
display: block;
}
.flextabs__content, .flextabs__toggle[aria-expanded="true"] {
background-color: var(--tab-color2) !important;
border: 0 solid var(--fg--color1);
}
.flextabs__toggle {
-moz-appearance: none;
border-width: 0 !important;
margin: 0 4px 0 0;
background-color: var(--tab-color1);
outline-width: 0 !important;
border-radius: 1em 1em 0 0;
padding: .4em .8em;
}
@media (max-width: 630px) {
body {
background-size: 8em ;
padding: 0;
margin: 0;
}
#header {
margin: .5em 8em 0 .5em;
}
}
@media (max-width: 440px) {
.flextabs__toggle {
border-radius: 1em;
margin: -1em 0 0 0;
}
.flextabs__toggle[aria-expanded="true"] {
font-weight: bold;
box-shadow: 1px 1px 1px inset;
z-index: 1;
position: relative;
}
body {
background-size: 6em;
}
#header {
margin: 0;
}
#header > .title {
margin-right: 6em;
}
}
.flextabs__content {
padding: .5em;
}
#xss-options {
display: none;
}
.mozwebext #xss-options {
display: block;
}
#vintageTheme-opt {
background: url(/img/logo.svg) no-repeat center left, url(/img/vintage/logo.svg) no-repeat center right;
background-size: 2em auto, 2em auto;
}
label[for="opt-vintageTheme"] {
text-indent: -5000px;
padding: 0 1.2em;
}
.hc #vintageTheme-opt {
background: none;
}
.hc label[for="opt-vintageTheme"] {
display: none !important;
}

View file

@ -0,0 +1,187 @@
<!--
Copyright (C) 2005-2021 Giorgio Maone <https://maone.net>
SPDX-License-Identifier: GPL-3.0-or-later
-->
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>NoScript Settings</title>
<meta charset="utf-8">
<link rel="icon" href="/img/noscript-options.png">
<link rel="stylesheet" href="/lib/flextabs.css" />
<link rel="stylesheet" href="options.css" />
<link rel="stylesheet" href="whirlpool.css" />
<link rel="stylesheet" href="ui.css" />
<script src="/nscl/lib/browser-polyfill.js"></script>
<script src="/nscl/common/UA.js"></script>
<script src="/nscl/common/include.js"></script>
<script src="/nscl/common/log.js"></script>
<script src="/nscl/common/locale.js"></script>
<script src="/common/themes.js"></script>
<script src="/lib/flextabs.js"></script>
<script src="/ui/ui.js"></script>
</head>
<body id="noscript-options">
<div id="header">
<div class="title">
<h1>__MSG_OptionsLong__</h1>
<span id="version">&nbsp;</span>
</div>
<div class="buttons">
<div id="import-container">
<input id="file-import" type="file" name="file-import" tabindex="-1" accept=".txt,.json"/>
<button id="btn-import" accesskey="__MSG_Import_accesskey__">__MSG_Import__</button>
</div>
<button id="btn-export" accesskey="__MSG_Export_accesskey__">__MSG_Export__</button>
<button id="btn-reset" accesskey="__MSG_Reset_accesskey__">__MSG_Reset__</button>
<a class="donate button" href="https://noscript.net/donate" title="__MSG_DonateLong__">__MSG_DonateShort__</a>
</div>
</div>
<div id="main-tabs" class="flextabs">
<h3 class="flextabs__tab"><button class="flextabs__toggle">__MSG_SectionGeneral__</button></h3>
<div class="flextabs__content flextabs__content--active--last">
<section id="sect-general">
<div class="opt-group">
<span id="global-opt">
<input type="checkbox" id="opt-global"><label for="opt-global" id="lbl-global">__MSG_NoEnforcement__</label>
</span>
<span id="enforceOnRestart-opt">
<input type="checkbox" id="opt-enforceOnRestart"><label for="opt-enforceOnRestart" id="lbl-enforceOnRestart">__MSG_EnforceOnRestart__</label>
</span>
</div>
<div class="opt-group">
<span id="auto-opt">
<input type="checkbox" class="enforcement_required" id="opt-auto"><label for="opt-auto" id="lbl-auto">__MSG_AutoAllowTopLevel__</label>
</span>
</div>
<div class="opt-group">
<span id="cascadeRestrictions-opt">
<input type="checkbox" class="enforcement_required" id="opt-cascadeRestrictions"><label for="opt-cascadeRestrictions" id="lbl-cascadeRestrictions">__MSG_CascadeRestrictions__</label>
</span>
</div>
</section>
<section id="sect-presets">
<fieldset class="enforcement_required">
<legend accesskey="__MSG_CustomizePresets_accesskey__">__MSG_CustomizePresets__</legend>
<div id="presets"></div>
</fieldset>
</section>
</div>
<h3 class="flextabs__tab"><button class="flextabs__toggle enforcement_required">__MSG_SectionSitePermissions__</button></h3>
<div class="flextabs__content">
<section class="sect-sites">
<form id="form-newsite" class="browser-style" >
<label id="newsite-label" for="newsite" accesskey="__MSG_WebAddress_accesskey__">__MSG_WebAddress__</label><input name="newsite" id="newsite" type="text" placeholder="[https://]noscript.net"
><button class="add">+</button>
</form>
<div id="sites">
<div class="cssload-container">
<div class="cssload-whirlpool"></div>
</div>
</div>
</section>
</div>
<h3 class="flextabs__tab appearance_tab"><button class="flextabs__toggle">__MSG_SectionAppearance__</button></h3>
<div class="flextabs__content appearance_tab">
<div class="opt-group">
<span id="showCtxMenuItem-opt">
<input type="checkbox" id="opt-showCtxMenuItem">
<label for="opt-showCtxMenuItem" id="lbl-showCtxMenuItem">__MSG_ShowCtxMenuItem__</label>
</span>
</div>
<div class="opt-group">
<span id="showCountBadge-opt">
<input type="checkbox" id="opt-showCountBadge">
<label for="opt-showCountBadge" id="lbl-showCountBadge">__MSG_ShowCountBadge__</label>
</span>
</div>
<div class="opt-group">
<span id="showFullAddresses-opt">
<input type="checkbox" id="opt-showFullAddresses">
<label for="opt-showFullAddresses" id="lbl-showFullAddresses">__MSG_ShowFullAddresses__</label>
</span>
</div>
<section id="sect-themes">
<fieldset id="themes">
<legend>__MSG_settingsThemeLabel__</legend>
<div class="opt-group">
<span id="theme-choice">
<input id="theme-dark" type="radio" name="theme" value="dark" /><label for="theme-dark">__MSG_themeDark__</label>
<input id="theme-light" type="radio" name="theme" value="light"/><label for="theme-light">__MSG_themeLight__</label>
<input id="theme-auto" type="radio" name="theme" value="auto" checked="checked"/><label for="theme-auto">__MSG_themeAuto__</label>
</span>
<span id="vintageTheme-opt" title="__MSG_toVintageBlue__">
<label for="opt-vintageTheme" title="__MSG_ModernRed__">>__MSG_ModernRed__</label>
<label class="switch">
<input type="checkbox" id="opt-vintageTheme">
<span class="slider round"></span>
<span class="inner-label">__MSG_toVintageBlue__</span>
</label>
<label for="opt-vintageTheme" title="__MSG_VintageBlue__">__MSG_VintageBlue__</label>
</span>
<span id="highContrast-opt">
<input type="checkbox" id="opt-highContrast">
<label for="opt-highContrast" id="lbl-highContrast">__MSG_HighContrast__</label>
</span>
</div>
</fieldset>
</section>
</div>
<h3 class="flextabs__tab"><button class="flextabs__toggle">__MSG_SectionAdvanced__</button></h3>
<div class="flextabs__content">
<div id="tb-options" class="opt-group">
<span id="overrideTorBrowserPolicy-opt">
<input type="checkbox" id="opt-overrideTorBrowserPolicy">
<label for="opt-overrideTorBrowserPolicy" id="lbl-opt-overrideTorBrowserPolicy"
><span class="tor">__MSG_OptOverrideTorBrowserPolicy__</span><span class="not-tor">__MSG_OptIncognitoPerm__</span></label>
</span>
</div>
<div id="xss-options" class="opt-group">
<span id="xss-opt">
<input type="checkbox" id="opt-xss">
<label for="opt-xss" id="lbl-xss">__MSG_OptFilterXGet__
<span id="xssFaq">(<a href="https://noscript.net/faq#xss" title="https://noscript.net/faq#xss">__MSG_XssFaq__</a>)
</label>
</span>
<div id="xssChoices">
</div>
</div>
<div id="clearclick-options" class="opt-group">
<input type="checkbox" id="opt-clearclick"><label for="opt-clearclick" id="lbl-clearclick">ClearClick</label>
</div>
<div id="update-options" class="opt-group">
<span id="amnesticUpdates-opt">
<input type="checkbox" id="opt-amnesticUpdates">
<label for="opt-amnesticUpdates" id="lbl-opt-amnesticUpdates">__MSG_OptAmnesticUpdates__</label>
</span>
</div>
<section id="debug" class="browser-style">
<div class="opt-group">
<span><input type="checkbox" id="opt-debug"><label id="label-debug" for="opt-debug">Debug</label></span>
</div>
</section>
<div id="debug-tools" class="debug">
<label for="policy">Policy:</label>
<div id="policy-error"></div>
<textarea id="policy" class="browser-style">
</textarea>
</div>
</div>
</div>
<script src="/nscl/service/persistent-tabs.js"></script>
<script src="options.js"></script>
</body>
</html>

View file

@ -0,0 +1,252 @@
/*
* NoScript - a Firefox extension for whitelist driven safe JavaScript execution
*
* Copyright (C) 2005-2021 Giorgio Maone <https://maone.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* 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 <https://www.gnu.org/licenses/>.
*/
'use strict';
document.querySelector("#version").textContent = _("Version",
browser.runtime.getManifest().version);
(async () => {
await UI.init();
let policy = UI.policy;
// simple general options
let opt = UI.wireOption;
opt("global", o => {
if (o) {
policy.enforced = !o.checked;
UI.updateSettings({policy});
}
let {enforced} = policy;
let disabled = !enforced;
for (let e of document.querySelectorAll(".enforcement_required")) {
e.disabled = disabled;
}
return disabled;
});
opt("enforceOnRestart", "local");
opt("auto", o => {
if (o) {
policy.autoAllowTop = o.checked;
UI.updateSettings({policy});
}
return policy.autoAllowTop;
});
opt("cascadeRestrictions");
opt("xss");
opt("overrideTorBrowserPolicy");
opt("amnesticUpdates", "local");
{
document.querySelector("#btn-reset").addEventListener("click", async ev => {
if (confirm(_("reset_warning"))) {
ev.target.disabled = true;
document.querySelector("#main-tabs").style.visibility = "hidden";
await UI.updateSettings({local: null, sync: null, xssUserChoices: {}});
}
});
let fileInput = document.querySelector("#file-import");
fileInput.onchange = () => {
let fr = new FileReader();
fr.onload = async () => {
try {
await UI.importSettings(fr.result);
} catch (e) {
error(e, "Importing settings %s", fr.result);
alert(e);
return;
}
location.reload();
}
fr.readAsText(fileInput.files[0]);
}
document.querySelector("#btn-import").addEventListener("click", async e => {
fileInput.focus();
fileInput.click();
e.target.focus();
});
document.querySelector("#btn-export").addEventListener("click", async e => {
let button = e.target;
button.disabled = true;
let settings = await UI.exportSettings();
let id = "noscriptExportFrame";
let f = document.getElementById(id);
if (f) f.remove();
f = document.createElement("iframe");
f.id = id;
f.srcdoc = `<a download="noscript_data.txt" target="_blank">NoScript Export</a>`;
f.style.position = "fixed";
f.style.top = "-999px";
f.style.height = "1px";
f.onload = () => {
let w = f.contentWindow;
let a = w.document.querySelector("a");
a.href = w.URL.createObjectURL(new w.Blob([settings], {
type: "text/plain"
}));
a.click();
setTimeout(() => {
button.disabled = false;
}, 1000);
};
document.body.appendChild(f);
});
}
{
let a = document.querySelector("#xssFaq a");
a.onclick = e => {
e.preventDefault();
browser.tabs.create({
url: a.href
});
}
}
opt("clearclick");
opt("debug", "local", o => {
let {checked} = o;
document.body.classList.toggle("debug", checked);
if (checked) updateRawPolicyEditor();
});
// Appearance
opt("showCountBadge", "local");
opt("showCtxMenuItem", "local");
opt("showFullAddresses", "local");
UI.wireChoice("theme", o => Themes.setup(o && o.value) );
opt("vintageTheme", async o => await (o ? Themes.setVintage(o.checked) : Themes.isVintage()));
// PRESET CUSTOMIZER
{
let parent = document.getElementById("presets");
let presetsUI = new UI.Sites(parent,
{"DEFAULT": true, "TRUSTED": true, "UNTRUSTED": true});
presetsUI.render([""]);
window.setTimeout(() => {
let def = parent.querySelector('input.preset[value="DEFAULT"]');
def.checked = true;
def.click();
}, 10);
}
// SITES UI
let sitesUI = new UI.Sites(document.getElementById("sites"));
UI.onSettings = () => {
policy = UI.policy;
sitesUI.render(policy.sites);
}
{
sitesUI.onChange = () => {
if (UI.local.debug) {
updateRawPolicyEditor();
}
};
sitesUI.render(policy.sites);
let newSiteForm = document.querySelector("#form-newsite");
let newSiteInput = newSiteForm.newsite;
let button = newSiteForm.querySelector("button");
let canAdd = s => {
let match = policy.get(s).siteMatch;
return match === null || s.length > match.length;
}
let validate = () => {
let site = newSiteInput.value.trim();
button.disabled = !(Sites.isValid(site) && canAdd(site));
sitesUI.filterSites(site);
}
validate();
newSiteInput.addEventListener("input", validate);
newSiteForm.addEventListener("submit", e => {
e.preventDefault();
e.stopPropagation();
let site = newSiteInput.value.trim();
let valid = Sites.isValid(site);
if (valid && canAdd(site)) {
policy.set(site, policy.TRUSTED);
UI.updateSettings({policy});
newSiteInput.value = "";
sitesUI.render(policy.sites);
sitesUI.hilite(site);
sitesUI.onChange();
}
}, true);
}
window.setTimeout(() => {
// focus and/or hilite elements based on query string
let params = new URLSearchParams(location.search);
let el = key => {
let selector = params.get(key);
return selector && document.querySelector(selector);
}
let focusElement = el("focus");
if (focusElement) focusElement.focus();
let hiliteElement = el("hilite");
if (hiliteElement) UI.hilite(hiliteElement);
}, 1000);
// UTILITY FUNCTIONS
function updateRawPolicyEditor() {
if (!UI.local.debug) return;
// RAW POLICY EDITING (debug only)
let policyEditor = document.getElementById("policy");
policyEditor.value = JSON.stringify(policy.dry(true), null, 2);
if (!policyEditor.onchange) policyEditor.onchange = (e) => {
let ed = e.currentTarget
try {
UI.policy = policy = new Policy(JSON.parse(ed.value));
UI.updateSettings({policy});
sitesUI.render(policy.sites);
ed.className = "";
document.getElementById("policy-error").textContent = "";
} catch (e) {
error(e);
ed.className = "error";
document.getElementById("policy-error").textContent = e.message;
}
}
}
})();

View file

@ -0,0 +1,300 @@
/*
* Copyright (C) 2005-2021 Giorgio Maone <https://maone.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
html:not(.mobile) {
overflow: hidden;
}
body {
margin: 0.5em;
padding: 0;
}
html:not(.mobile) > body {
width: var(--popup-size);
padding: 0;
}
html:not(.mobile) #scrollable {
overflow: auto;
max-height: 550px;
}
#top {
font-size: 1em;
position: relative;
padding: 0 0 .3em 0;
margin: 0;
min-width: 18.75em;
display: flex;
-moz-user-select: none;
user-select: none;
background: linear-gradient(to bottom, transparent 0, transparent 95%, var(--form-color1) 100%) no-repeat;
}
.icon {
appearance: none !important;
-webkit-appearance: none !important;
-moz-appearance: none !important;
cursor: pointer;
color: var(--accent-color);
background: transparent no-repeat left;
padding-left: 1.6em;
border: none;
font-size: 1.2em;
background-size: 1.2em;
margin: 0 1.2em 0 1.2em;
}
#top .icon {
width: var(--icon-size);
height: var(--icon-size);
margin: 0.25em;
cursor: pointer;
font-size: 1em;
font-family: sans-serif;
font-weight: bold;
background-size: contain;
background-position: center;
transform: unset;
transition: transform 0.3s;
border: none;
display: block;
top: 0;
padding: 0;
align-items: center;
line-height: 1em;
position: relative;
border-radius: 0;
}
#top .icon > div {
position: absolute;
width: 100%;
height: 100%;
background: transparent;
top: 0;
left: 0;
}
.icon:after {
content: attr(title);
}
#top > .spacer {
flex-grow: 1;
display: block;
cursor: pointer;
}
#top > .hider.open ~ .spacer {
display: none;
}
.hider {
background: var(--form-color1);
box-shadow: inset 0 1px 3px #444;
color: var(--text-color);
border-radius: 1em 1em 0 0;
display: none;
position: relative;
margin: .25em 1.5em;
padding: 0;
height: var(--icon-size);
overflow: hidden;
opacity: .5;
}
.hider.open {
display: flex;
flex-grow: 1;
opacity: 1;
padding-left: 2em;
}
.hider:hover {
opacity: 1;
}
.hider:not(.open):not(.empty) {
display: block;
text-align: right;
line-height: 1em;
overflow: hidden;
width: 2em;
}
.hider-close, .reveal {
-webkit-appearance: none;
-moz-appearance: none;
border: none;
border-radius: 0;
background: transparent;
color: var(--fg--color1);
font-weight: bold;
display: block;
}
.hider-close:hover, .reveal:hover {
color: var(--accent-color);
text-shadow: 0 0 4px var(--focus-color);
cursor: pointer;
}
#top .hider .reveal {
font-size: 1.2em;
padding: .2em;
text-align: center;
margin: 0;
}
.hider-close {
padding: 0;
position: absolute;
left: .2em;
top: 0;
font-size: 1.5em;
z-index: 100;
vertical-align: middle;
padding: .2em;
}
.hider.open > .reveal, .hider:not(.open) > :not(.reveal) {
display: none !important;
}
.hider-label {
position: absolute;
z-index: 100;
top: .5em;
right: .5em;
text-align: right;
vertical-align: middle;
line-height: 100%;
font-size: 1em;
font-weight: bold;
pointer-events: none;
}
.hider > .icon {
opacity: .7;
margin: 0 .25em;
padding: 0;
}
#top .icon:hover:not(:disabled), #top > #top > .icon:active:not(:disabled) {
outline: 0;
filter: none;
transform: scale(1.2);
}
#top .icon {
text-indent: -500em;
color: transparent;
}
#top .icon.drag, #top .drag > .icon {
filter: none !important;
opacity: 0.6 !important;
}
#revoke-temp {
background-image: var(--img-ui-revoke-temp) !important;
}
#temp-trust-page {
background-image: var(--img-ui-temp-all) !important;
}
#enforce-tab {
background-image: var(--img-ui-tab-no) !important;
}
#enforce-tab[aria-pressed="true"] {
background-image: var(--img-ui-tab) !important;;
}
#enforce {
background-image: var(--img-ui-global-no) !important;
}
#enforce[aria-pressed="true"] {
background-image: var(--img-ui-global) !important;
}
#options {
background-image: var(--img-noscript-options) !important;
}
#close {
background-image: var(--img-ui-close) !important;
}
#reload {
background-image: var(--img-ui-reload) !important;;
}
#sites {
margin: 0;
}
#content {
text-align: center;
}
#buttons {
text-align: center;
margin: 0.5em;
display: flex;
justify-content: space-around;
}
#buttons button {
flex-grow: 1;
margin: .5em 2em;
}
.disabled .toggle.icon, .toggle.icon:disabled {
opacity: .4;
pointer-events: none;
}
#message {
height: auto;
margin: 1.5em 1em;
padding: .8em 0 0.8em 3em;
background-color: var(--bg-color1);
background-size: 2em;
background-position: .5em center;
background-repeat: no-repeat;
min-height: 2em;
font-size: 1.2em;
vertical-align: middle;
white-space: normal;
border-radius: 1em;
box-shadow: 0 0 3px 3px var(--hilite-color);
}
#message.hidden {
display: none;
height: 0;
min-height: 0;
overflow: hidden;
}
.warning {
background-image: var(--img-warning);
}
.error {
background-image: var(--img-error);
}
#incognito-ui-chooser, html.incognito #message:not(.hidden) ~ #incognito-ui-chooser {
display: none;
}
html.incognito #incognito-ui-chooser {
display: initial;
}
#incognito-ui-chooser label {
white-space: pre-wrap;
}
#incognito-ui-chooser input:checked + label {
background: var(--bg-color1);
color: var(--accent-color);
}

View file

@ -0,0 +1,66 @@
<!--
Copyright (C) 2005-2021 Giorgio Maone <https://maone.net>
SPDX-License-Identifier: GPL-3.0-or-later
-->
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta charset="utf-8">
<title>NoScript Settings</title>
<meta charset="utf-8">
<link rel="stylesheet" href="ui.css" />
<link rel="stylesheet" href="popup.css" />
<script src="/nscl/lib/browser-polyfill.js"></script>
<script src="/nscl/common/UA.js"></script>
<script src="/nscl/common/include.js"></script>
<script src="/nscl/common/log.js"></script>
<script src="/nscl/common/locale.js"></script>
<script src="/common/themes.js"></script>
<script src="/ui/ui.js"></script>
</head>
<body tabindex="-1" id="noscript-popup">
<div id="top">
<button aria-role="button" id="close" class="close icon" title="__MSG_Close__"></button>
<button aria-role="button" id="reload" class="reload icon" title="__MSG_Reload__"></button>
<button aria-role="button" id="options" class="options icon" title="__MSG_Options__"></button>
<div class="hider empty">
<button aria-role="button" class="reveal" title="__MSG_Reveal__"></button>
<div class="hider-label">__MSG_Hider__</div>
<a class="hider-close">×</a>
</div>
<div class="spacer"></div>
<button aria-role="button" id="enforce" class="toggle icon"></button>
<button aria-role="button" id="enforce-tab" class="toggle icon"></button>
<button aria-role="button" id="temp-trust-page" class="toggle icon" title="__MSG_TempTrustPage__"></button>
<button aria-role="button" id="revoke-temp" class="toggle icon" title="__MSG_RevokeTemp__"></button>
</div>
<div id="scrollable">
<div id="message" class="hidden"></div>
<div id="high-contrast-chooser" class="opt-group">
<span id="highContrast-opt">
<input type="checkbox" id="opt-highContrast">
<label for="opt-highContrast" id="lbl-highContrast">__MSG_HighContrast__</label>
</span>
</div>
<div id="incognito-ui-chooser" class="opt-group">
<span id="overrideTorBrowserPolicy-opt">
<input type="checkbox" id="opt-overrideTorBrowserPolicy">
<label for="opt-overrideTorBrowserPolicy" id="lbl-opt-overrideTorBrowserPolicy"
><span class="tor">__MSG_OptOverrideTorBrowserPolicy__</span><span class="not-tor">__MSG_OptIncognitoPerm__</span></label>
</span>
</div>
<div id="xssChoices">
</div>
<div id="content"></div>
<div id="sites"></div>
<div id="buttons"></div>
</div>
<script src="popup.js"></script>
</body>
</html>

View file

@ -0,0 +1,423 @@
/*
* NoScript - a Firefox extension for whitelist driven safe JavaScript execution
*
* Copyright (C) 2005-2022 Giorgio Maone <https://maone.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* 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 <https://www.gnu.org/licenses/>.
*/
'use strict';
var sitesUI;
var port;
addEventListener("unload", e => {
if (!UI.initialized) {
Messages.send("openStandalonePopup");
}
});
(async () => {
function messageBox(className, message, extraUI = null) {
let el = document.getElementById("message");
if (className === "hidden" && el._lastMessage !== message) return;
el._lastMessage = el.textContent = message;
el.className = className;
if (extraUI) {
el.appendChild(extraUI);
if (typeof extraUI.focus === "function") {
extraUI.focus();
}
}
el.scrollIntoView();
}
try {
let tabId;
UI.isBrowserAction = true;
let optionsClosed = false;
let tabFlags = {active: true};
if (browser.windows) tabFlags.currentWindow = true; // Desktop browsers only
let tab = (await browser.tabs.query(tabFlags))[0] ||
// work-around for Firefox "forgetting" tabs on Android
(await browser.tabs.query({url: ["*://*/*", "file:///*", "ftp://*/*"]}))[0];
let pageTab = tab;
if (!tab || tab.id === -1) {
log("No tab found to open the UI for");
close();
}
if (tab.url === document.URL) {
UI.isBrowserAction = false;
try {
tabId = parseInt(document.URL.match(/#.*\btab(\d+)/)[1]);
pageTab = await browser.tabs.get(tabId);
} catch (e) {
close();
}
addEventListener("blur", close);
} else {
tabId = tab.id;
}
addEventListener("keydown", e => {
if (e.code === "Enter") {
let focused = document.activeElement;
if (focused.closest(".sites")) {
close();
}
}
})
port = browser.runtime.connect({name: "noscript.popup"});
await UI.init(pageTab);
function pendingReload(b) {
try {
port.postMessage({tabId, pendingReload: b});
} catch (e) {
debug(e);
}
}
if (UI.isBrowserAction) {
browser.tabs.onActivated.addListener(e => {
if (e.tabId !== tabId) close();
});
}
await include("/ui/toolbar.js");
UI.toolbarInit();
{
let handlers = {
"options": e => {
if (UA.mobile) { // Fenix fails on openOptionsPage
browser.tabs.create({url: browser.runtime.getManifest().options_ui.page});
} else {
browser.runtime.openOptionsPage();
}
close();
},
"close": close,
"reload": reload,
"temp-trust-page": e => sitesUI.tempTrustAll(),
"revoke-temp": e => {
UI.revokeTemp(sitesUI && sitesUI.hasTemp);
close();
}
};
for (let b of document.querySelectorAll("#top .icon")) {
b.tabIndex = 0;
if (b.id in handlers) {
let h = handlers[b.id];
b.onclick = h;
}
}
let keyHandlers = {
"r": "reload",
"o": "options",
"p": "temp-trust-page",
"f": "revoke-temp",
"G": "enforce",
"T": "enforce-tab",
};
window.addEventListener("keydown", e => {
let buttonId = keyHandlers[e.key];
if (buttonId) document.getElementById(buttonId).click();
}, true);
let navigate = e => {
let sel = e.code === "ArrowUp" ? ":last-child" : "";
document.querySelector(`.sites tr.site${sel} input.preset:checked`).focus();
e.preventDefault();
e.stopPropagation();
}
document.querySelector("#top").addEventListener("keydown", e => {
switch(e.code) {
case "Space":
case "Enter":
e.target.click();
e.preventDefault();
break;
case "ArrowDown":
case "ArrowUp":
navigate(e);
break;
case "ArrowLeft":
case "ArrowRight":
{
let focused = document.activeElement;
let all = [...focused.parentNode.querySelectorAll(".icon")];
let index = all.indexOf(focused);
if (index === -1) return;
index += e.code === "ArrowRight" ? 1 : -1;
if (index >= all.length) index = 0;
else if (index < 0) index = all.length -1;
all[index].focus();
break;
}
}
}, true);
}
let originallyEnforced = UI.policy.enforced;
let enforcementWarning = button => {
if (button) {
let clone = button.cloneNode(true);
clone.onclick = button.onclick;
button = clone;
}
messageBox(button ? "warning" : "hidden", _("NotEnforced"), button);
};
let setupEnforcement = () => {
let policy = UI.policy;
let pressed = policy.enforced;
let button = document.getElementById("enforce");
button.setAttribute("aria-pressed", pressed);
button.title = _(pressed ? "NoEnforcement" : "Enforce");
button.onclick = async () => {
this.disabled = true;
policy.enforced = !pressed;
await UI.updateSettings({policy, reloadAffected: false});
if (policy.enforced !== originallyEnforced &&
(policy.enforced || UI.local.immediateUnrestrict)) {
reload();
close();
return;
}
setupEnforcement();
pendingReload(true);
};
button.disabled = false;
enforcementWarning(!policy.enforced && button);
setupTabEnforcement();
};
let setupTabEnforcement = () => {
let pressed = !UI.unrestrictedTab;
let button = document.getElementById("enforce-tab");
button.setAttribute("aria-pressed", pressed);
button.title = _(pressed ? "NoEnforcementForTab" : "EnforceForTab");
if (UI.policy.enforced) {
button.onclick = async () => {
this.disabled = true;
await UI.updateSettings({
unrestrictedTab: pressed,
reloadAffected: false,
});
UI.unrestrictedTab = pressed;
if (!(UI.unrestrictedTab && UI.local.stickyUnrestrictedTab)) {
reload();
close();
return;
}
setupEnforcement();
pendingReload(true);
}
button.disabled = false;
enforcementWarning(UI.unrestrictedTab && button);
} else {
button.disabled = true;
}
};
setupEnforcement();
let mainFrame = UI.seen && UI.seen.find(thing => thing.request.type === "main_frame");
debug("Seen: %o", UI.seen);
if (!mainFrame) {
let isHttp = /^https?:/.test(pageTab.url);
try {
await browser.tabs.executeScript(tabId, { code: "" });
if (isHttp) {
document.body.classList.add("disabled");
messageBox("warning", _("freshInstallReload"));
let buttons = document.querySelector("#buttons");
let b = document.createElement("button");
b.textContent = _("OK");
b.onclick = document.getElementById("reload").onclick = () => {
reload();
close();
}
buttons.appendChild(b).focus();
b = document.createElement("button");
b.textContent = _("Cancel");
b.onclick = () => close();
buttons.appendChild(b);
return;
}
} catch (e) {
error(e, "Could not run scripts on %s: privileged page?", pageTab.url);
}
await include("/nscl/common/restricted.js");
let isRestricted = isRestrictedURL(pageTab.url);
if (!isHttp || isRestricted) {
messageBox("warning", _("privilegedPage"));
let tempTrust = document.getElementById("temp-trust-page");
tempTrust.disabled = true;
return;
}
if (!UI.seen) {
if (!isHttp) return;
let {url} = pageTab;
UI.seen = [
mainFrame = {
request: { url, documentUrl: url, type: "main_frame" }
}
];
}
}
let justDomains = !UI.local.showFullAddresses;
sitesUI = new UI.Sites(document.getElementById("sites"));
sitesUI.onChange = (row) => {
pendingReload(sitesUI.anyPermissionsChanged());
if (optionsClosed) return;
browser.tabs.query({
url: browser.runtime.getURL(
browser.runtime.getManifest().options_ui.page)
}).then(tabs => {
browser.tabs.remove(tabs.map(t => t.id));
});
optionsClosed = true;
};
initSitesUI();
UI.onSettings = initSitesUI;
if (UI.incognito) {
UI.wireOption("overrideTorBrowserPolicy", "sync", o => {
let {checked} = o;
if (UI.forceIncognito !== !checked) {
UI.forceIncognito = !checked;
sitesUI.render();
}
});
}
function initSitesUI() {
pendingReload(false);
let {
typesMap
} = sitesUI;
typesMap.clear();
let policySites = UI.policy.sites;
let domains = new Map();
let protocols = new Set();
function urlToLabel(url) {
let origin = Sites.origin(url);
let match = policySites.match(url);
if (match) {
if (match === url.protocol) {
protocols.add(match);
} else {
return match;
}
}
if (domains.has(origin)) {
if (justDomains) return domains.get(origin);
} else {
let domain = tld.getDomain(url.hostname);
if (domain) {
domain = url.protocol === "https:" ? Sites.secureDomainKey(domain) : domain;
} else {
domain = url.protocol;
}
domains.set(origin, domain);
if (justDomains) return domain;
}
return origin;
}
let seen = UI.seen;
let parsedSeen = seen.map(thing => Object.assign({
type: thing.policyType
}, Sites.parse(thing.request.url)))
.filter(parsed => parsed.url && (
parsed.url.origin !== "null" || parsed.url.protocol === "file:"));
let sitesSet = new Set(
parsedSeen.map(parsed => parsed.label = urlToLabel(parsed.url))
);
if (!justDomains) {
for (let domain of domains.values()) sitesSet.add(domain);
}
for (let protocol of protocols) sitesSet.add(protocol);
let sites = [...sitesSet];
for (let parsed of parsedSeen) {
sites.filter(s => parsed.label === s || domains.get(Sites.origin(parsed.url)) === s).forEach(m => {
let siteTypes = typesMap.get(m);
if (!siteTypes) typesMap.set(m, siteTypes = new Set());
siteTypes.add(parsed.type);
});
}
sitesUI.mainUrl = new URL(mainFrame.request.url)
sitesUI.mainSite = urlToLabel(sitesUI.mainUrl);
sitesUI.mainDomain = tld.getDomain(sitesUI.mainUrl.hostname);
sitesUI.render(sites);
sitesUI.focus();
window.scrollTo(0, 0);
}
function reload() {
if (sitesUI) sitesUI.clear();
browser.tabs.reload(tabId);
pendingReload(false);
}
function close() {
if (UI.isBrowserAction) {
window.close();
} else {
browser.tabs.remove(tab.id);
}
}
let {
onCompleted
} = browser.webNavigation;
let loadSnapshot = sitesUI.snapshot;
let onCompletedListener = navigated => {
if (navigated.tabId === tabId) {
setTimeout(() => UI.pullSettings(), 500);
}
};
onCompleted.addListener(onCompletedListener, {
url: [{
hostContains: sitesUI.mainDomain
}]
});
addEventListener("blur", e => {
onCompleted.removeListener(onCompletedListener);
port.disconnect(); // otherwise Vivaldi keeps it after closing
});
} catch (e) {
error(e, "Can't open popup");
close();
}
})();

View file

@ -0,0 +1,124 @@
/*
* Copyright (C) 2005-2021 Giorgio Maone <https://maone.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
@import url("./common.css");
html {
background: linear-gradient(to bottom, var(--form-color1) 0, var(--bg-color2) 41%, var(--bg-color1) 94%, var(--hilite-color) 100%) no-repeat;
background-color: var(--bg-color1);
}
body {
bottom: .8em;
margin: 0px;
padding: .8em;
background-color: transparent;
}
html.mobile > body {
font-family: Inter, sans-serif;
font-size: 4vmin;
min-width: auto;
min-height: 90vh;
padding-bottom: 72px; /* clear Fenix's navbar */
}
#header {
text-align: left;
margin: 0;
line-height: 2em;
color: var(--accent-color);
z-index: 500;
padding: .8em .8em 0 .8em;
display: block;
background: var(--img-logo) no-repeat top right;
background-size: contain;
min-height: 5em;
}
#title {
margin-right: 4em;
text-shadow: 0.06em 0.06em 0.06em rgba(0,0,0,.5);
font-size: 2em;
bottom: 0;
top: 0;
}
#main {
display: flex;
flex-direction: column;
align-items: stretch;
padding: 0 1.6em;
top: 0;
left: 0;
right:0;
bottom: 0;
justify-content: center;
overflow: auto;
}
#message {
flex-grow: 1;
max-height: 28em;
padding: .8em;
text-align: center;
}
#message.multiline {
overflow: auto;
font-size: 1em;
text-align: justify;
margin-bottom: 1.2em;
background: var(--focus-color);
}
#message.multiline p {
margin: .1em;
padding: 0;
}
#options {
display: flex;
flex-grow: 2;
flex-direction: column;
text-align: left;
align-items:baseline;
justify-content: center;
}
#checks {
display: flex;
flex-direction: column;
flex-grow: 1;
text-align: left;
}
.choices div {
display: flex;
flex-direction: row;
align-items: baseline;
}
.choices label {
display: block;
word-break: break-all;
}
#buttons {
display: flex;
flex-grow: 0;
flex-direction: row;
align-items: center;
margin: .8em;
justify-content: space-around;
}
#buttons button {
min-width: 6em;
font-size: 1em;
}
input[type="checkbox"], input[type="radio"] {
min-width: 1em;
min-height: 1em;
font-size: 1em;
}

View file

@ -0,0 +1,41 @@
<!--
Copyright (C) 2005-2021 Giorgio Maone <https://maone.net>
SPDX-License-Identifier: GPL-3.0-or-later
-->
<!DOCTYPE html>
<html class="__NoScript_Theme__">
<head>
<meta charset="utf-8">
<title></title>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="prompt.css" />
<script src="/nscl/lib/browser-polyfill.js"></script>
<script src="/nscl/common/UA.js"></script>
<script src="/nscl/common/include.js"></script>
<script src="/nscl/common/log.js"></script>
<script src="/nscl/common/locale.js"></script>
<script src="/ui/resize_hack.js"></script>
<script src="/common/themes.js"></script>
</head>
<body>
<div id="header">
<h1 id="title"></h1>
</div>
<div id="main">
<div id="message">
</div>
<div id="options" class="choices">
<input type="radio">
</div>
<div id="checks" class="choices">
<input type="checkbox">
</div>
<div id="buttons">
<button id="button0" type="submit">OK</button><button id="button1">Cancel</button>
</div>
</div>
<script src="prompt.js"></script>
</body>
</html>

View file

@ -0,0 +1,150 @@
/*
* NoScript - a Firefox extension for whitelist driven safe JavaScript execution
*
* Copyright (C) 2005-2021 Giorgio Maone <https://maone.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* 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 <https://www.gnu.org/licenses/>.
*/
(async () => {
document.documentElement.classList.toggle("mobile", !!UA.mobile);
window.bg = await browser.runtime.getBackgroundPage();
["Prompts"]
.forEach(p => window[p] = bg[p]);
let data = Prompts.promptData;
debug(data);
if (!data) {
error("Missing promptData");
window.close();
return;
}
let {title, message, options, checks, buttons} = data.features;
function labelFor(el, text) {
let label = document.createElement("label");
label.setAttribute("for", el.id);
label.textContent = text;
return label;
}
function createInput(container, {label, type, name, checked}, count) {
let input = document.createElement("input");
input.type = type;
input.value = count;
input.name = name;
input.checked = checked;
input.id = `${name}-${count}`;
let sub = document.createElement("div");
sub.appendChild(input);
sub.appendChild(labelFor(input, label));
container.appendChild(sub);
}
function createButton(container, label, count) {
let button = document.createElement("button");
if (count === 0) button.type = "submit";
button.id = `${button}-${count}`;
button.value = count;
button.textContent = label;
container.appendChild(button);
}
function renderInputs(container, dataset, type, name) {
if (typeof container === "string") {
container = document.querySelector(container);
}
if (typeof dataset === "string") {
container.innerHTML = dataset;
return;
}
container.innerHTML = "";
let count = 0;
if (dataset && dataset[Symbol.iterator]) {
let create = type === "button" ? createButton : createInput;
for (let data of dataset) {
data.type = type;
data.name = name;
create(container, data, count++);
}
}
}
if (title) {
document.title = title;
document.querySelector("#title").textContent = title;
}
if (message) {
let lines = message.split(/\n/);
let container = document.querySelector("#message");
container.classList.toggle("multiline", lines.length > 1);
message.innerHTML = "";
for (let l of lines) {
let p = document.createElement("p");
p.textContent = l;
container.appendChild(p);
}
}
renderInputs("#options", options, "radio", "opt");
renderInputs("#checks", checks, "checkbox", "flag");
renderInputs("#buttons", buttons, "button", "button");
addEventListener("unload", e => {
data.done();
});
let buttonClicked = e => {
let {result} = data;
result.button = parseInt(e.currentTarget.value);
let option = document.querySelector('#options [type="radio"]:checked');
result.option = option && parseInt(option.value);
result.checks = [...document.querySelectorAll('#checks [type="checkbox"]:checked')]
.map(c => parseInt(c.value));
data.done();
};
for (let b of document.querySelectorAll("#buttons button")) {
b.addEventListener("click", buttonClicked);
}
addEventListener("keydown", e => {
if (e.ctrlKey || e.metaKey || e.shiftKey) return;
switch(e.code) {
case "Escape":
window.close();
return;
case "Enter":
let defButton = document.querySelector("#buttons button[type=submit]");
if (defButton) defButton.click();
return;
}
});
let resize = async e => {
if (!("windows" in browser)) {
// tabbed (mobile?) - ensure buttons are visible
document.querySelector("#buttons").scrollIntoView();
return;
}
let win = await browser.windows.getCurrent();
let delta = document.documentElement.offsetHeight - window.innerHeight;
let geometry = {
width: win.width, height: win.height + delta,
left: win.left, top: win.top - Math.round(delta / 2)
};
for (let j = 2; j-- > 0;) await browser.windows.update(win.id, geometry);
}
if (document.readyState === "complete") {
resize();
} else {
window.addEventListener("load", resize);
}
})();

View file

@ -0,0 +1,35 @@
/*
* NoScript - a Firefox extension for whitelist driven safe JavaScript execution
*
* Copyright (C) 2005-2021 Giorgio Maone <https://maone.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* 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 <https://www.gnu.org/licenses/>.
*/
if ("windows" in browser) document.addEventListener("DOMContentLoaded", async e => {
// Fix for Fx57 bug where bundled page loaded using
// browser.windows.create won't show contents unless resized.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1402110
let win = await browser.windows.getCurrent({populate: true});
if (win.tabs[0].url === document.URL) {
debug("Resize hack");
await browser.windows.update(win.id, {
width: win.width + 1
});
await browser.windows.update(win.id, {
width: win.width
});
}
});

View file

@ -0,0 +1,13 @@
<!--
Copyright (C) 2005-2021 Giorgio Maone <https://maone.net>
SPDX-License-Identifier: GPL-3.0-or-later
-->
<!DOCTYPE html>
<meta charset="utf-8">
<script src="/nscl/lib/browser-polyfill.js"></script>
<script src="/nscl/common/UA.js"></script>
<script src="/nscl/common/include.js"></script>
<script src="/nscl/common/log.js"></script>
<script src="siteInfo.js"></script>

View file

@ -0,0 +1,43 @@
/*
* NoScript - a Firefox extension for whitelist driven safe JavaScript execution
*
* Copyright (C) 2005-2021 Giorgio Maone <https://maone.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* 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 <https://www.gnu.org/licenses/>.
*/
(async () => {
let [domain, tabId] = decodeURIComponent(location.hash.replace("#", "")).split(";");
const BASE = "https://noscript.net";
await include([
'/nscl/lib/punycode.js',
'/nscl/common/Storage.js'
]);
let {siteInfoConsent} = await Storage.get("sync", "siteInfoConsent");
if (!siteInfoConsent) {
await include('/nscl/common/locale.js');
siteInfoConsent = confirm(_("siteInfo_confirm", [domain, BASE]));
if (siteInfoConsent) {
await Storage.set("sync", {siteInfoConsent});
} else {
let current = await browser.tabs.getCurrent();
await browser.tabs.update(parseInt(tabId), {active: true});
await browser.tabs.remove(current.id);
return;
}
}
let ace = punycode.toASCII(domain);
location.href = `${BASE}/about/${domain};${ace}`;
})();

View file

@ -0,0 +1,76 @@
.switch {
position: relative;
display: inline-block;
width: 2.4em;
height: 1.4em;
margin: .2em;
}
.hc .switch {
position: static;
padding: 0 !important;
margin: 0;
}
:root:not(.hc) .switch input {
opacity: 0;
width: 0;
height: 0;
}
.hc .slider {
display: none;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: var(--form-color1);
transition: .4s;
border: .1em solid currentColor;
}
.switch .inner-label {
display: none;
}
.hc .switch .inner-label {
display: inline;
padding: 0 .5em 0 0;
}
.slider:before {
position: absolute;
content: "";
height: 1em;
width: 1em;
left: .15em;
bottom: .15em;
background-color: currentColor;
transition: .4s;
}
input:checked + .slider {
background-color: var(--form-radio-bg-color);
}
input:checked + .slider:before {
transform: translateX(1em);
background-color: var(--form-radio-color);
}
/* Rounded sliders */
.slider.round {
border-radius: 1.5em;
}
.slider.round:before {
border-radius: 50%;
}

View file

@ -0,0 +1,167 @@
/*
* NoScript - a Firefox extension for whitelist driven safe JavaScript execution
*
* Copyright (C) 2005-2021 Giorgio Maone <https://maone.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* 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 <https://www.gnu.org/licenses/>.
*/
UI.toolbarInit = () => {
if (UI.toolbarInit.done || UI.highContrast || UI.local.highContrast)
return;
UI.toolbarInit.done = true;
let toolbar = document.getElementById("top");
let spacer = toolbar.querySelector(".spacer");
let hider = toolbar.querySelector(".hider");
if (UI.local.toolbarLayout) {
let {left, right, hidden} = UI.local.toolbarLayout;
for (let id of left) {
toolbar.insertBefore(document.getElementById(id), hider);
}
for (let id of right) {
toolbar.appendChild(document.getElementById(id));
}
for (let id of hidden) {
hider.appendChild(document.getElementById(id));
}
}
let makeDraggable = b => {
// work-around for dragging disabled buttons
let wrapper = document.createElement("div");
b.replaceWith(wrapper);
// work-around for dragging empty (padding only) elements
b.innerHTML = "<div></div>";
wrapper.appendChild(b);
b = wrapper;
b.setAttribute("draggable", "true");
}
let toggleHider = b => {
let cl = hider.classList;
cl.toggle("open", b);
cl.toggle("empty", !hider.querySelector(".icon"));
}
hider.querySelector(".hider-close").onclick = e => {
toggleHider(false);
};
toggleHider(false);
let dnd = {
dragstart(ev) {
if (hider.querySelectorAll(".icon").length) {
toggleHider(true);
}
let button = ev.target.querySelector(".icon");
if (!button) {
ev.preventDefault();
return;
}
// work-around for Firefox unable to drag buttons, https://bugzilla.mozilla.org/show_bug.cgi?id=568313
let placeHolder = document.createElement("div");
let {style} = placeHolder;
style.backgroundImage = getComputedStyle(button).backgroundImage;
style.backgroundSize = "contain";
let width = button.offsetWidth * 1.2;
let height = button.offsetHeight * 1.2;
style.width =`${width}px`;
style.height = `${height}px`
style.position = "absolute";
style.top = "-2000px";
toolbar.appendChild(placeHolder);
setTimeout(() => placeHolder.remove(), 0);
let dt = ev.dataTransfer;
dt.setData("text/plain", button.id);
dt.dropEffect = "move";
dt.setDragImage(placeHolder, width / 2, height / 2);
toggleHider(true);
this.draggedElement = ev.target; // the draggable wrapper around the button
this.draggedElement.classList.add("drag");
},
dragend(ev) {
this.draggedElement.classList.remove("drag");
this.draggedElement = null;
},
dragover(ev) {
ev.preventDefault();
},
dragenter(ev) {
},
dragleave(ev) {
},
drop(ev) {
let t = ev.target;
let d = this.draggedElement;
if (!d) return;
switch(t) {
case hider:
t.appendChild(d);
break;
default:
if (!t.closest("#top")) return; // outside the toolbar?
let stop = null;
for (let c of toolbar.children) {
if (ev.clientX < c.offsetLeft + c.offsetWidth / 2) {
stop = c;
break;
}
}
toolbar.insertBefore(d, stop);
}
let left = [], right = [];
let side = left;
for (let el of toolbar.querySelectorAll(":scope > .spacer, :scope > [draggable] > .icon")) {
if (el === spacer) {
side = right;
} else {
side.push(el.id);
}
}
UI.local.toolbarLayout = {
left, right,
hidden: Array.from(toolbar.querySelectorAll(".hider .icon")).map(el => el.id),
};
debug("%o", UI.local);
UI.updateSettings({local: UI.local});
},
click(ev) {
let el = ev.target;
if (el === spacer || el.classList.contains("reveal")) {
toggleHider(true);
}
}
};
for (let [action, handler] of Object.entries(dnd)) {
toolbar.addEventListener(action, handler, true);
}
for (let b of toolbar.querySelectorAll(".icon")) {
makeDraggable(b);
}
}

View file

@ -0,0 +1,115 @@
/*
* Copyright (C) 2005-2021 Giorgio Maone <https://maone.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
input {
transform: none !important;
width: auto !important;
min-width: auto !important;
position: static !important;
}
input[type="radio"] {
appearance: radio !important;
-webkit-appearance: radio !important;
-moz-appearance: radio !important;
padding-right: .2em !important;
}
input[type="checkbox"] {
appearance: checkbox !important;
-webkit-appearance: checkbox !important;
-moz-appearance: checkbox !important;
display: initial !important;
}
input.preset {
margin: 0 .5em !important;
padding: 0 !important;
}
button {
text-indent: 0 !important;
}
label {
display: initial !important;
position: static !important;
transform: none !important;
opacity: 1 !important;
text-indent: 0 !Important;
position: static;
width: auto !important;
padding: 4px !important;
}
.full-address {
display: block;
}
.presets {
display: flex;
flex-wrap: wrap;
}
span.preset, .url {
display: flex;
align-items: center;
}
input.temp {
position: static !important;
opacity: 1 !important;
}
.full-address {
font-size: 130%;
}
tr.site {
border-top: 1px solid #888;
display: flex;
align-items: center;
}
#top {
display: flex;
flex-flow: row;
justify-content: space-around;
height: auto;
}
#top .icon {
position: static;
width: auto;
appearance: initial !important;
-moz-appearance: initial !important;
width: auto;
height: auto;
display: inline-flex !important;
font-size: 12px !important;
font-family: sans-serif !important;
text-indent: 0;
color: var(--fg-color1) !important;
background: var(--bg-color2) !important;
background-image: none !important;
border-radius: .3em;
text-align: center;
border: 1px solid var(--fg-color1);
height: auto;
padding: .2em;
}
#top a.icon:hover {
transform: none;
}
#noscript-popup #high-contrast-chooser {
display: block;
}
:focus {
outline: max(2px, 0.15em) solid currentColor;
outline-offset: max(2px, 0.15em);
}

View file

@ -0,0 +1,591 @@
/*
* Copyright (C) 2005-2021 Giorgio Maone <https://maone.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
@import url("./common.css");
.opt-group {
display: flex;
flex-flow: row wrap;
padding: .5em 0;
}
:is(section, .opt-group) ~ :is(.opt-group, section, fieldset) {
border-top: 2px dotted var(--bg-color1);
}
.opt-group > span {
margin: 0 .5em;
display: flex;
flex-flow: row;
align-items: baseline;
}
@media (max-width: 550px) {
.sites td.url {
vertical-align: top;
}
#sites .presets {
width: 0 !important;
padding: 0 !important;
margin: 0 !important;
padding-bottom: 1em !important;
}
#presets .presets input.preset {
min-width: 28vw;
}
#sites .presets input.preset {
min-width: 0 !important;
margin-top: 0;
margin-left: 0;
margin-right: 1em;
font-weight: bold;
}
#sites .presets input.preset:checked {
filter: drop-shadow(0 0 2px var(--fg-color1));
}
#sites .site:not(.customizing) .presets input.preset {
background-color: transparent;
background-position: center;
}
#sites .customizing input.preset:checked {
margin-left: 0;
}
#presets .presets input.preset + label {
font-size: 80%;
--line-scaled: calc(var(--line-size) / 0.8);
position: absolute !important;
text-align: left;
margin: 0px !important;
display: block !important;
overflow: visible;
bottom: 0px;
}
#sites .presets input.preset:checked + label {
z-index: 1000;
font-size: 60%;
left: 0;
width: auto;
top: calc(var(--line-size) * 1.8);
margin: 0 !important;
padding: 0 !important;
text-align: center !important;
display: block !important;
position: absolute;
overflow: visible !important;
background: none !important;
}
.presets input.preset:checked ~ input.temp {
left: var(--line-size);
right: auto;
pointer-events: none;
}
.customizing input.preset:checked ~ input.temp {
pointer-events: all !important;
z-index: 1000;
padding: calc(var(--line-size) / 2);
}
#sites .customizing input.preset:checked + label {
pointer-events: none;
transition: all .2s;
}
td.presets {
white-space: nowrap !important;
vertical-align: middle;
border: 1px solid var(--fg-color2);
}
.url > span > span {
white-space: wrap;
word-break: break-all;
letter-spacing: -0.2mm;
font-size: 80%;
}
.contextual fieldset {
padding-top: 1.5em;
}
}
.site.filtered, .site.filtered + .customizer {
display: none;
}
#sites .customizing .presets {
padding-bottom: 0 !important;
margin-bottom: 0 !important;
vertical-align: bottom;
}
.capsContext, .capsContext > div {
display: flex;
align-items: center;
flex-wrap: wrap;
}
.capsContext > label {
display: block;
}
.capsContext select {
display: none;
}
.contextual .capsContext select {
display: initial;
margin: 0 1em;
}
.pageTurn {
position: absolute;
outline: 3px solid #888;
z-index: 1000;
background-color: var(--bg-color2);
transform-origin: bottom center;
transition: transform .5s;
}
.pageTurn.endgame {
transform: scale(.5, .1);
}
input[type="text"] {
border: 1px solid;
}
input[type="checkbox"] {
width: 1em;
height: 1em;
}
.presets {
-moz-user-select: none;
user-select: none;
}
.sites {
border: 0;
border-collapse: collapse;
border-spacing: 0;
width: 100%;
image-rendering: -webkit-optimize-contrast;
--extra-preset-width: 0px;
}
.vintage .sites {
image-rendering: auto;
}
.sites tr, .sites td {
margin: 0;
padding: 0;
border: none;
font-size: 1em;
vertical-align: middle;
}
html:not(.mobile) .sites > tr.site:not(.customizing):is(:focus-within) {
background-image: var(--bg-focused-row);
border-color: transparent;
}
.sites > tr.site:not(.customizing) {
border-top: var(--border-row-sep);
}
.sites > tr.site:nth-of-type(even) {
background-color: var(--bg-even-row);
}
.sites > tr.site:nth-of-type(odd) {
background-color: var(--bg-odd-row);
}
.sites > tr.site:first-of-type, tr.site:focus-within + tr, .sites > tr.customizing, .sites > tr.customizing + tr.site, .customizer, .customizer + tr.site {
border-color: transparent;
}
.site .url {
padding: 0 0 0 0.5em;
color: var(--fg-color2);
width: 80%;
}
.site .url .protocol { display: none }
.site .url .domain { cursor: help }
[data-key="host"] .full-address span .protocol,
[data-key="domain"] .full-address span .host,
[data-key="domain"] .full-address span .protocol {
border: none;
}
.site .url[data-key="domain"] .domain,
.site .url[data-key="host"] .domain,
.site .url[data-key="host"] .sub,
.site .url[data-key="unsafe"] span {
color: var(--unsafe-color)
}
.site .url[data-key="secure"] .domain,
.site .url[data-key="secure"] .sub,
.site .url[data-key="full"] span {
color: var(--fg-color2)
}
.site .url[data-key="full"] span,
.site .url[data-key="unsafe"] span {
display: initial;
}
.site .url .domain {
font-weight: bold;
}
input.https-only {
font-size: 100%;
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
background: var(--img-ui-http) no-repeat center;
background-size: 1.5em;
background-position: bottom;
width: 2em;
height: 2em;
margin: -.25em 0;
padding:0;
cursor: pointer;
}
input.https-only:checked {
background-image: var(--img-ui-https);
}
label.https-only {
display: none;
}
.preset label.preset.override {
color: var(--text-color);
}
[data-preset="UNTRUSTED"] .https-only, [data-preset="DEFAULT"] .https-only {
visibility: hidden;
}
td.presets {
font-size: 1em;
white-space: nowrap;
}
span.preset {
position: relative;
display: inline-block;
font-size: 1em;
height: var(--line-size);
top: 0.1em;
}
.preset label, .preset input, .preset button {
cursor: pointer;
}
.presets input.preset {
font-size: 1em;
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
background: transparent var(--img-ui-no) no-repeat center;
outline: 0;
opacity: .7;
margin: 0 1em 0 0;
background-position: 0;
background-size: var(--line-size);
width: var(--line-size);
height: var(--line-size);
position: relative;
z-index: 1;
}
#presets-sizer {
visibility: hidden;
position: absolute;
display: block;
width: 5000px;
height: 500px;
top: -5000px;
}
#presets-sizer span.preset {
display: block;
}
.presets input.preset:checked, #presets input.preset, #presets-sizer input.preset {
opacity: 1;
transform: none;
min-width: calc(var(--preset-label-width) + var(--line-size) * 1.5 + var(--extra-preset-width));
}
.presets input.preset:focus {
transform: none;
}
.sites input + label {
font-size: 1em;
vertical-align: baseline;
}
.presets label.preset {
letter-spacing: -0.06em;
width: 0;
overflow: hidden;
display: none;
text-transform: uppercase;
color: var(--fg-color2);
opacity: .8;
position: absolute;
left: 0;
padding: .05em 0.4em 0 0;
--line-scaled: var(--line-size);
line-height: var(--line-scaled);
padding-left: calc(var(--line-scaled) * 1.4);
}
.presets input.preset[value^="T"] + label {
text-transform: none;
}
.presets input.preset:checked + label, #presets .presets label {
opacity: 1;
display: inline-flex;
width: var(--preset-label-width);
background-color: var(--form-color2);
border-radius: 1em 1em 0 0;
}
@media (min-width: 550px) {
:not(#presets) > .sites .site:not(.customizing) .presets input.preset:checked + label.preset {
background-color: var(--bg-preset-color);
border-radius: calc(var(--line-size) / 2);
box-shadow: 0 0 1px var(--fg-color1);
}
}
#presets :is(.presets input.preset + label, .customizer-controls) {
box-shadow: 0 0 .2em var(--fg-color1);
}
#presets-sizer .presets label {
position: absolute;
display: inline;
width: auto;
overflow: visible;
padding: 0;
}
input.preset[value="T_TRUSTED"] {
background-image: var(--img-ui-temp);
}
input.preset[value="TRUSTED"] {
background-image: var(--img-ui-yes)
}
input.preset[value="UNTRUSTED"] {
background-image: var(--img-ui-black)
}
input.preset[value="CUSTOM"] {
background-image: var(--img-ui-custom)
}
input.temp {
font-size: 1em;
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
margin: 0;
padding: 0;
border: 0;
opacity: 0;
outline: 0;
background: var(--img-ui-clock) no-repeat center;
background-size: 60%;
width: 1.5em;
height: 1.5em;
transition: 0.2s all;
right: 0;
top: 0;
pointer-events: none;
position: absolute;
z-index: 100;
}
input.temp + label {
display: none;
}
input.temp + label {
display: none;
}
input.preset:checked ~ input.temp {
opacity: .7;
right: 0.4em;
pointer-events: all;
}
.presets input.preset:checked ~ input.temp:checked {
opacity: 1 !important;
background-size: 100%;
}
.customizing input.preset:checked, #presets input.preset:checked {
filter: none;
}
.customizer fieldset {
background-color: var(--form-color2);
margin: 0;
box-shadow: var(--form-color1) 0 2px 2px;
position: relative;
}
.customizing input.preset:checked {
margin: 0 0 -0.2em 0;
background-position: 0 0;
--extra-preset-width: 1em;
}
#presets span.preset {
margin-right: .8em;
max-width: 28vw;
}
#presets :is(input.preset, input.preset:checked) {
filter: none;
background-position: .2em 0;
}
#presets .site.customizing {
background-color: transparent;
}
#presets .customizing input.preset:not(:checked) + label {
margin-bottom: 0;
background-color: var(--form-color1);
}
#presets legend select, #presets legend button {
display: none;
}
.caps {
display: flex;
align-content: start;
flex-wrap: wrap;
clear: both;
padding: .5em;
}
#presets .customizer fieldset {
margin-top: 0px;
}
.customizer.closed .customizer-controls {
height: 0;
overflow: hidden;
}
span.cap {
padding: 0.3em;
margin: 0.2em;
border-radius: .4em;
font-weight: normal;
display: inline-flex;
align-items: center;
}
span.cap.needed {
font-weight: bold;
color: var(--fg-color2);
background-color: var(--hilite-color);
}
fieldset {
border: 0;
padding: 1em;
margin: 0;
}
legend {
font-weight: bold;
display: block;
}
.customizer legend {
font-size: 1em;
float: left;
}
#presets .url {
display: none;
}
#high-contrast-chooser {
display: none;
}
.hilite {
background-color: #850 !important;
}
.hilite-end {
transition: background-color 1s;
}
.hilite .url {
transform: scale(2);
transition: none;
}
.hilite-end .url {
transform: none;
transition: transform 1s;
}
#xssChoices {
padding: .5em;
display: none;
}
#xssChoices.populated {
display: block;
}
#xssChoices select {
display: block;
margin: 0 0 .5em 0;
}
#xssChoices option {
background: var(--bg-color2);
}
#xssChoices option.block {
color: var(--accent-color);
}
#xssChoices option.allow {
color: var(--text-color);
}

View file

@ -0,0 +1,50 @@
/*
* Copyright (C) 2005-2021 Giorgio Maone <https://maone.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
.cssload-container{
position:relative;
}
.cssload-whirlpool,
.cssload-whirlpool::before,
.cssload-whirlpool::after {
position: absolute;
top: 50%;
left: 50%;
border: 1px solid rgb(204,204,204);
border-left-color: rgb(0,0,0);
border-radius: 974px;
}
.cssload-whirlpool {
margin: -24px 0 0 -24px;
height: 49px;
width: 49px;
animation: cssload-rotate 1150ms linear infinite;
}
.cssload-whirlpool::before {
content: "";
margin: -22px 0 0 -22px;
height: 43px;
width: 43px;
animation: cssload-rotate 1150ms linear infinite;
}
.cssload-whirlpool::after {
content: "";
margin: -28px 0 0 -28px;
height: 55px;
width: 55px;
animation: cssload-rotate 2300ms linear infinite;
}
@keyframes cssload-rotate {
100% {
transform: rotate(360deg);
}
}