Merge branch 'develop'

This commit is contained in:
Alice Gaudon 2020-07-14 11:11:10 +02:00
commit dea6c43573
10 changed files with 209 additions and 135 deletions

View File

@ -3,6 +3,7 @@
"files": "ts/files.ts",
"layout": "sass/layout.scss",
"index": "sass/index.scss",
"error": "sass/error.scss",
"service-settings": "sass/service-settings.scss"
}
}

22
frontend/error.html Normal file
View File

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>An error occured</title>
<meta http-equiv="Content-Security-Policy"
content="style-src 'self' 'unsafe-inline' https://use.fontawesome.com; font-src 'self' https://use.fontawesome.com; script-src 'self'">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.2/css/all.css"
integrity="sha384-oS3vJWv+0UjzBfQzYUhtDYW+Pj2yciDJxpsK1OYPAYjqT085Qq/1cq5FLXAZQ7Ay" crossorigin="anonymous">
<link rel="stylesheet" href="css/layout.css">
<link rel="stylesheet" href="css/error.css">
</head>
<body>
<h1>Oops</h1>
<p>An error has occurred while loading this document.</p>
<p>Please check your internet connection and this service's URL.</p>
<p>If you can load the actual URL in your favorite web browser, please file us a bug report.</p>
</body>
</html>

9
frontend/sass/error.scss Normal file
View File

@ -0,0 +1,9 @@
html, body {
height: 100%;
}
body {
display: flex;
flex-direction: column;
justify-content: center;
align-self: center;
}

View File

@ -7,6 +7,16 @@ body {
flex-direction: row;
}
#service-buttons {
flex-grow: 1;
overflow: hidden auto;
}
*:focus {
outline-color: rgb(118, 93, 176);
}
#navigation {
display: flex;
flex-direction: column;
@ -16,72 +26,12 @@ body {
body.fullscreen & {
display: none;
}
}
#navigation > :not(#service-buttons) {
> :not(#service-buttons) {
flex-shrink: 0;
}
}
#service-buttons {
flex-grow: 1;
overflow: hidden auto;
}
#service-selector {
display: block;
margin: 0;
padding: 0;
list-style: none;
}
#service-selector::-webkit-scrollbar {
width: 6px;
}
#service-selector [draggable] {
user-select: none;
background-color: rgb(43, 43, 43);
}
#service-selector [draggable] img {
-webkit-user-drag: none;
user-drag: none;
}
#service-selector .drag-target button::after,
#service-last-drag-position.drag-target {
content: "";
height: 4px;
transform: translateY(-50%);
border: 0;
box-sizing: border-box;
background: #fff9;
}
#service-selector .drag-target-self button::after {
height: var(--nav-width);
border: 1px dashed #fff;
transform: none;
}
#service-selector .drag-target button::after {
position: absolute;
left: 0;
top: 0;
width: 100%;
}
#service-selector .drag-target::after {
top: 75% !important;
}
*:focus {
outline-color: rgb(118, 93, 176);
}
#navigation button {
button {
position: relative;
display: block;
width: var(--nav-width);
@ -94,35 +44,51 @@ body {
background: transparent;
cursor: pointer;
}
border-radius: 0;
#navigation button:focus {
&:focus {
outline: none;
background: #fff3 !important;
}
}
#navigation button img {
width: calc(var(--nav-width) / 2);
}
&:hover {
background-color: #fff3;
}
#navigation button i {
i {
font-size: calc(var(--nav-width) / 2);
}
img {
width: calc(var(--nav-width) / 2);
}
}
}
#service-selector li {
#service-selector {
display: block;
margin: 0;
padding: 0;
list-style: none;
&::-webkit-scrollbar {
width: 6px;
}
li {
position: relative;
}
#service-selector li button,
#navigation > button {
button {
border-radius: 0;
}
}
#service-selector li.active button {
&.active button {
background-color: #fff2;
}
}
#service-selector li.loaded button::before {
&.loading, &.loaded {
button::before {
content: "";
display: block;
position: absolute;
@ -131,23 +97,60 @@ body {
transform: translateY(-50%);
height: 75%;
border-right: 4px solid #ffffff3e;
}
}
&.loading button::before {
animation: loading-button-after linear 500ms infinite alternate;
height: 45%;
@keyframes loading-button-after {
from {
opacity: 0.1;
}
to {
opacity: 0.5;
}
}
}
}
[draggable] {
user-select: none;
background-color: rgb(43, 43, 43);
img {
-webkit-user-drag: none;
user-drag: none;
}
}
.drag-target-self button::after {
height: var(--nav-width);
border: 1px dashed #fff;
transform: none;
}
.drag-target button::after {
position: absolute;
left: 0;
top: 0;
width: 100%;
}
.drag-target::after {
top: 75% !important;
}
}
/*#service-selector li.loaded::after {*/
/* content: "";*/
/* position: absolute;*/
/* top: 50%;*/
/* right: 2px;*/
/* transform: translateY(-50%);*/
/* width: 4px;*/
/* height: 4px;*/
/* background-color: #fff;*/
/* border-radius: 100%;*/
/*}*/
#navigation button:hover {
background-color: #fff3;
#service-selector .drag-target button::after,
#service-last-drag-position.drag-target {
content: "";
height: 4px;
transform: translateY(-50%);
border: 0;
box-sizing: border-box;
background: #fff9;
}
#history {

View File

@ -71,21 +71,27 @@ form {
margin: 8px;
grid-template-columns: 0fr auto 0fr;
}
.form-group > * {
&.no-expand {
display: flex;
flex-direction: row;
justify-content: center;
}
> * {
margin: 8px;
padding: 8px;
white-space: nowrap;
align-self: center;
}
}
.form-group > :first-child {
> :first-child {
justify-self: end;
}
}
.form-group > :not(:first-child) {
> :not(:first-child) {
margin-left: 8px;
}
}
label.form-group {

View File

@ -42,12 +42,19 @@
<textarea name="customCSS" id="custom-css" rows="3"></textarea>
</div>
<fieldset>
<legend>Disguise</legend>
<div class="form-group">
<label for="custom-user-agent">Custom UserAgent (i.e. google services)</label>
<input type="text" name="customUserAgent" id="custom-user-agent">
<button type="button" id="userAgentAutoFill">Auto-fill</button>
</div>
<div class="form-group no-expand">
<button type="button" id="userAgentAutoFillFirefox">Disguise as firefox</button>
<button type="button" id="userAgentAutoFillChrome">Disguise as chrome</button>
</div>
</fieldset>
<div id="icon-choice">
<div class="form-group-header">
<h2>Service icon</h2>

View File

@ -26,7 +26,7 @@ let securityButton: HTMLElement | null,
backButton: HTMLElement | null,
refreshButton: HTMLElement | null;
let addButton, settingsButton;
let emptyPage: string;
let emptyPage: string, errorPage: string;
let urlPreview: HTMLElement | null;
let serviceSelector: HTMLElement | null;
@ -128,7 +128,7 @@ function openServiceContextMenu(event: Event, serviceId: number) {
}
ipcRenderer.on('data', (event, appData, iconSets, actualSelectedService, emptyUrl, config) => {
ipcRenderer.on('data', (event, appData, iconSets, actualSelectedService, emptyUrl, errorUrl, config) => {
// App info
appInfo.title = appData.title;
@ -179,6 +179,7 @@ ipcRenderer.on('data', (event, appData, iconSets, actualSelectedService, emptyUr
// Empty
emptyPage = emptyUrl;
errorPage = errorUrl;
// Url preview element
urlPreview = document.getElementById("url-preview");
@ -212,13 +213,15 @@ ipcRenderer.on('data', (event, appData, iconSets, actualSelectedService, emptyUr
document.documentElement.style.setProperty('--nav-width', config.bigNavBar ? '64px' : '48px');
});
function removeServiceFeatures(id: number): HTMLElement | null {
function removeServiceFeatures(id: number): Element | null {
// Remove nav
const nav = document.querySelector('#service-selector');
let oldNavButton: HTMLElement | null = null;
let nextSibling: Element | null = null;
if (nav) {
oldNavButton = nav.querySelector('li:nth-of-type(' + (id + 1) + ')');
if (oldNavButton) {
nextSibling = oldNavButton.nextElementSibling;
nav.removeChild(oldNavButton);
}
}
@ -228,19 +231,21 @@ function removeServiceFeatures(id: number): HTMLElement | null {
document.querySelector('#services')?.removeChild(services[id].view);
}
return oldNavButton;
return nextSibling;
}
ipcRenderer.on('updateService', (e, id, data) => {
if (id === null) {
console.log('Adding new service');
services.push(data);
createService(services.length - 1);
} else {
const oldNavButton = removeServiceFeatures(id);
console.log('Updating existing service', id);
const nextSibling = removeServiceFeatures(id);
// Create new service
services[id] = data;
createService(id, oldNavButton ? oldNavButton.nextElementSibling : null);
createService(id, nextSibling);
if (parseInt(selectedService) === id) {
setActiveService(id);
}
@ -324,6 +329,8 @@ function createService(index: number, nextNavButton?: Element | null) {
iconProperties.faIcon.split(' ').forEach((cl: string) => {
icon.classList.add(cl);
});
} else {
icon.classList.add('fas', 'fa-circle');
}
}
@ -464,6 +471,7 @@ function loadService(serviceId: number, service: any) {
document.querySelector('#services > .loader')?.classList.remove('hidden');
service.view = document.createElement('webview');
updateNavigation(); // Start loading animation
service.view.setAttribute('enableRemoteModule', 'false');
service.view.setAttribute('partition', 'persist:service_' + service.partition);
service.view.setAttribute('autosize', 'true');
@ -473,6 +481,11 @@ function loadService(serviceId: number, service: any) {
// eventual future human mistakes.
service.view.setAttribute('webpreferences', 'contextIsolation=yes');
// Error handling
service.view.addEventListener('did-fail-load', (e: Event) => {
service.view.setAttribute('src', errorPage);
});
// Append element to DOM
document.querySelector('#services')?.appendChild(service.view);
@ -643,10 +656,16 @@ function updateNavigation() {
for (let i = 0; i < services.length; i++) {
const service = services[i];
if (!service.li) continue;
// Active?
if (parseInt(selectedService) === i) service.li.classList.add('active');
else service.li.classList.remove('active');
// Loading?
if (service.view && !service.viewReady) service.li.classList.add('loading');
else service.li.classList.remove('loading');
// Loaded?
if (service.viewReady) service.li.classList.add('loaded');
else service.li.classList.remove('loaded');

View File

@ -72,10 +72,16 @@ document.addEventListener('DOMContentLoaded', () => {
ipcRenderer.send('sync-settings');
document.getElementById('userAgentAutoFill')?.addEventListener('click', () => {
document.getElementById('userAgentAutoFillFirefox')?.addEventListener('click', () => {
let customUserAgent = document.getElementById('custom-user-agent');
if (customUserAgent) {
(<HTMLInputElement>customUserAgent).value = 'Mozilla/5.0 (X11; Linux x86_64; rv:73.0) Gecko/20100101 Firefox/73.0';
(<HTMLInputElement>customUserAgent).value = 'Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0';
}
});
document.getElementById('userAgentAutoFillChrome')?.addEventListener('click', () => {
let customUserAgent = document.getElementById('custom-user-agent');
if (customUserAgent) {
(<HTMLInputElement>customUserAgent).value = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36';
}
});
});
@ -200,7 +206,7 @@ function save() {
ipcRenderer.send('saveService', serviceId, service);
remote.getCurrentWindow().close();
};
}
function isValid() {
if (typeof service.name !== 'string' || service.name.length === 0) {

View File

@ -1,6 +1,6 @@
{
"name": "tabs",
"version": "1.1.3",
"version": "1.1.4",
"description": "Persistent and separate browser tabs in one window.",
"author": {
"name": "Alice Gaudon",

View File

@ -147,6 +147,7 @@ export default class MainWindow extends Window {
Meta.ICON_SETS,
this.activeService,
path.resolve(Meta.RESOURCES_PATH, 'empty.html'),
path.resolve(Meta.RESOURCES_PATH, 'error.html'),
this.config
);
}