📝 Added entire config directory for backup purposes
This commit is contained in:
parent
4b38e59bb6
commit
9b946e2d14
11091 changed files with 1440953 additions and 0 deletions
|
|
@ -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;
|
||||
|
||||
})();
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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"> </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>
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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);
|
||||
}
|
||||
})();
|
||||
|
|
@ -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
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
@ -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>
|
||||
|
|
@ -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}`;
|
||||
})();
|
||||
|
|
@ -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%;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue