Add autoLoad setting to services and add running indicator to navigation
This commit is contained in:
parent
c390fc906d
commit
670e4cf6f8
146
resources/index.css
Normal file
146
resources/index.css
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
#service-selector {
|
||||||
|
flex-grow: 1;
|
||||||
|
display: block;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*:focus {
|
||||||
|
outline-color: rgb(118, 93, 176);
|
||||||
|
}
|
||||||
|
|
||||||
|
#navigation button {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
padding: 16px;
|
||||||
|
margin: 0;
|
||||||
|
height: 72px;
|
||||||
|
|
||||||
|
color: #fff;
|
||||||
|
border: 0;
|
||||||
|
background: transparent;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#navigation button img {
|
||||||
|
width: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#navigation button i {
|
||||||
|
font-size: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#service-selector li {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
#service-selector li.active button {
|
||||||
|
position: relative;
|
||||||
|
background-color: #fff2;
|
||||||
|
}
|
||||||
|
|
||||||
|
#service-selector li.active button::before {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
border-left: 4px solid #ffffff2e;
|
||||||
|
}
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
#history {
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#history button {
|
||||||
|
display: inline;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
padding: initial;
|
||||||
|
font-size: 12px;
|
||||||
|
|
||||||
|
background: #fff1;
|
||||||
|
border: 1px solid #fff4;
|
||||||
|
border-radius: 72px;
|
||||||
|
|
||||||
|
color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#history button i {
|
||||||
|
font-size: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
#history button.disabled {
|
||||||
|
color: #888;
|
||||||
|
border: transparent;
|
||||||
|
background: transparent;
|
||||||
|
cursor: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
#history button:focus,
|
||||||
|
#history button:hover {
|
||||||
|
outline: none;
|
||||||
|
border-color: #fff9;
|
||||||
|
}
|
||||||
|
|
||||||
|
#history button:hover:not(.disabled) {
|
||||||
|
outline: none;
|
||||||
|
background-color: #fff2;
|
||||||
|
}
|
||||||
|
|
||||||
|
#history button:active:not(.disabled) {
|
||||||
|
background-color: #fff4;
|
||||||
|
}
|
||||||
|
|
||||||
|
#navigation #add-button:not(:hover) {
|
||||||
|
opacity: 0.75;
|
||||||
|
}
|
||||||
|
|
||||||
|
#services {
|
||||||
|
position: relative;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#services > *:not(.loader) {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#services > :not(.active):not(.loader) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#services > .loader {
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
z-index: -1;
|
||||||
|
}
|
@ -1,144 +1,14 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
<title>Tabs</title>
|
<title>Tabs</title>
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.2/css/all.css"
|
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.2/css/all.css"
|
||||||
integrity="sha384-oS3vJWv+0UjzBfQzYUhtDYW+Pj2yciDJxpsK1OYPAYjqT085Qq/1cq5FLXAZQ7Ay" crossorigin="anonymous">
|
integrity="sha384-oS3vJWv+0UjzBfQzYUhtDYW+Pj2yciDJxpsK1OYPAYjqT085Qq/1cq5FLXAZQ7Ay" crossorigin="anonymous">
|
||||||
|
|
||||||
<link rel="stylesheet" href="layout.css">
|
<link rel="stylesheet" href="layout.css">
|
||||||
|
<link rel="stylesheet" href="index.css">
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
|
|
||||||
#service-selector {
|
|
||||||
flex-grow: 1;
|
|
||||||
display: block;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
*:focus {
|
|
||||||
outline-color: rgb(118, 93, 176);
|
|
||||||
}
|
|
||||||
|
|
||||||
#navigation button {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
padding: 16px;
|
|
||||||
margin: 0;
|
|
||||||
height: 72px;
|
|
||||||
|
|
||||||
color: #fff;
|
|
||||||
border: 0;
|
|
||||||
background: transparent;
|
|
||||||
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
#navigation button img {
|
|
||||||
width: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#navigation button i {
|
|
||||||
font-size: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#service-selector li.active button {
|
|
||||||
position: relative;
|
|
||||||
background-color: #fff2;
|
|
||||||
}
|
|
||||||
|
|
||||||
#service-selector li.active button::before {
|
|
||||||
content: "";
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
height: 100%;
|
|
||||||
border-left: 4px solid #ffffff2e;
|
|
||||||
}
|
|
||||||
|
|
||||||
#navigation button:hover {
|
|
||||||
background-color: #fff3;
|
|
||||||
}
|
|
||||||
|
|
||||||
#history {
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#history button {
|
|
||||||
display: inline;
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
padding: initial;
|
|
||||||
font-size: 12px;
|
|
||||||
|
|
||||||
background: #fff1;
|
|
||||||
border: 1px solid #fff4;
|
|
||||||
border-radius: 72px;
|
|
||||||
|
|
||||||
color: #fff;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
#history button i {
|
|
||||||
font-size: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
#history button.disabled {
|
|
||||||
color: #888;
|
|
||||||
border: transparent;
|
|
||||||
background: transparent;
|
|
||||||
cursor: initial;
|
|
||||||
}
|
|
||||||
|
|
||||||
#history button:focus,
|
|
||||||
#history button:hover {
|
|
||||||
outline: none;
|
|
||||||
border-color: #fff9;
|
|
||||||
}
|
|
||||||
|
|
||||||
#history button:hover:not(.disabled) {
|
|
||||||
outline: none;
|
|
||||||
background-color: #fff2;
|
|
||||||
}
|
|
||||||
|
|
||||||
#history button:active:not(.disabled) {
|
|
||||||
background-color: #fff4;
|
|
||||||
}
|
|
||||||
|
|
||||||
#navigation #add-button:not(:hover) {
|
|
||||||
opacity: 0.75;
|
|
||||||
}
|
|
||||||
|
|
||||||
#services {
|
|
||||||
position: relative;
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#services > *:not(.loader) {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#services > :not(.active):not(.loader) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#services > .loader {
|
|
||||||
width: 64px;
|
|
||||||
height: 64px;
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
left: 50%;
|
|
||||||
top: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
z-index: -1;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
@ -331,6 +201,10 @@
|
|||||||
} else {
|
} else {
|
||||||
nav.insertBefore(li, nextNavButton);
|
nav.insertBefore(li, nextNavButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (service.autoLoad) {
|
||||||
|
loadService(index, service);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
@ -347,34 +221,7 @@
|
|||||||
function setActiveService(serviceId) {
|
function setActiveService(serviceId) {
|
||||||
let currentService = services[serviceId];
|
let currentService = services[serviceId];
|
||||||
process.nextTick(() => {
|
process.nextTick(() => {
|
||||||
// Load service if not loaded yet
|
loadService(serviceId, currentService);
|
||||||
if (!currentService.view) {
|
|
||||||
currentService.view = document.createElement('webview');
|
|
||||||
currentService.view.setAttribute('src', currentService.url);
|
|
||||||
currentService.view.setAttribute('partition', 'persist:service_' + currentService.partition);
|
|
||||||
currentService.view.setAttribute('autosize', "true");
|
|
||||||
|
|
||||||
document.querySelector('#services').appendChild(currentService.view);
|
|
||||||
currentService.view.addEventListener('dom-ready', event => {
|
|
||||||
currentService.viewReady = true;
|
|
||||||
updateNavigation();
|
|
||||||
});
|
|
||||||
currentService.view.addEventListener('page-favicon-updated', event => {
|
|
||||||
console.debug('Loaded favicons for', currentService.name, event.favicons);
|
|
||||||
if (event.favicons.length > 0) {
|
|
||||||
ipcRenderer.send('setServiceFavicon', serviceId, event.favicons[0]);
|
|
||||||
if (currentService.useFavicon) {
|
|
||||||
const img = document.createElement('img');
|
|
||||||
img.src = event.favicons[0];
|
|
||||||
img.alt = currentService.name;
|
|
||||||
img.onload = () => {
|
|
||||||
currentService.li.button.innerHTML = '';
|
|
||||||
currentService.li.button.appendChild(img);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hide previous service
|
// Hide previous service
|
||||||
if (services[selectedService] && services[selectedService].view) {
|
if (services[selectedService] && services[selectedService].view) {
|
||||||
@ -392,6 +239,39 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function loadService(serviceId, service) {
|
||||||
|
// Load service if not loaded yet
|
||||||
|
if (!service.view) {
|
||||||
|
service.view = document.createElement('webview');
|
||||||
|
service.view.setAttribute('src', service.url);
|
||||||
|
service.view.setAttribute('partition', 'persist:service_' + service.partition);
|
||||||
|
service.view.setAttribute('autosize', "true");
|
||||||
|
|
||||||
|
document.querySelector('#services').appendChild(service.view);
|
||||||
|
service.view.addEventListener('dom-ready', () => {
|
||||||
|
service.viewReady = true;
|
||||||
|
updateNavigation();
|
||||||
|
});
|
||||||
|
service.view.addEventListener('page-favicon-updated', event => {
|
||||||
|
console.debug('Loaded favicons for', service.name, event.favicons);
|
||||||
|
if (event.favicons.length > 0) {
|
||||||
|
ipcRenderer.send('setServiceFavicon', serviceId, event.favicons[0]);
|
||||||
|
if (service.useFavicon) {
|
||||||
|
const img = document.createElement('img');
|
||||||
|
img.src = event.favicons[0];
|
||||||
|
img.alt = service.name;
|
||||||
|
img.onload = () => {
|
||||||
|
service.li.button.innerHTML = '';
|
||||||
|
service.li.button.appendChild(img);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
service.li.classList.add('loaded');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function updateNavigation() {
|
function updateNavigation() {
|
||||||
console.debug('Updating navigation');
|
console.debug('Updating navigation');
|
||||||
// Update active list element
|
// Update active list element
|
||||||
|
@ -134,6 +134,11 @@
|
|||||||
<input type="text" name="url" id="url" required>
|
<input type="text" name="url" id="url" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="auto-load">Automatically load service in the background</label>
|
||||||
|
<input type="checkbox" name="autoLoad" id="auto-load">
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="icon-choice">
|
<div id="icon-choice">
|
||||||
<h2>Service icon</h2>
|
<h2>Service icon</h2>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@ -216,27 +221,6 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function loadServiceValues() {
|
|
||||||
if (!service || !isImageCheckbox) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('name').value = service.name;
|
|
||||||
document.getElementById('url').value = service.url;
|
|
||||||
document.getElementById('use-favicon').checked = service.useFavicon;
|
|
||||||
isImageCheckbox.checked = service.isImage;
|
|
||||||
if (service.isImage) {
|
|
||||||
iconUrlField.value = service.icon;
|
|
||||||
} else {
|
|
||||||
builtInIconSearchField.value = service.icon;
|
|
||||||
updateIconSearchResults();
|
|
||||||
const icon = Array.from(iconSelect.querySelectorAll('label')).find(i => i.dataset.icon === service.icon);
|
|
||||||
if (icon) {
|
|
||||||
selectIcon(icon);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateIconSearchResults() {
|
function updateIconSearchResults() {
|
||||||
const searchStr = builtInIconSearchField.value;
|
const searchStr = builtInIconSearchField.value;
|
||||||
iconSelect.childNodes.forEach(c => {
|
iconSelect.childNodes.forEach(c => {
|
||||||
@ -298,6 +282,50 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function loadServiceValues() {
|
||||||
|
if (!service || !isImageCheckbox) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('name').value = service.name;
|
||||||
|
document.getElementById('url').value = service.url;
|
||||||
|
document.getElementById('use-favicon').checked = service.useFavicon;
|
||||||
|
document.getElementById('auto-load').checked = service.autoLoad;
|
||||||
|
isImageCheckbox.checked = service.isImage;
|
||||||
|
if (service.isImage) {
|
||||||
|
iconUrlField.value = service.icon;
|
||||||
|
} else {
|
||||||
|
builtInIconSearchField.value = service.icon;
|
||||||
|
updateIconSearchResults();
|
||||||
|
const icon = Array.from(iconSelect.querySelectorAll('label')).find(i => i.dataset.icon === service.icon);
|
||||||
|
if (icon) {
|
||||||
|
selectIcon(icon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function save() {
|
||||||
|
const formData = new FormData(document.querySelector('form'));
|
||||||
|
service.name = formData.get('name');
|
||||||
|
if (typeof service.partition !== 'string' || service.partition.length === 0) {
|
||||||
|
service.partition = service.name.replace(/ /g, '-');
|
||||||
|
service.partition = service.partition.replace(/[^a-zA-Z-_]/g, '');
|
||||||
|
}
|
||||||
|
service.url = formData.get('url');
|
||||||
|
service.isImage = formData.get('isImage') === 'on';
|
||||||
|
service.icon = formData.get('icon');
|
||||||
|
service.useFavicon = formData.get('useFavicon') === 'on';
|
||||||
|
service.autoLoad = formData.get('autoLoad') === 'on';
|
||||||
|
|
||||||
|
|
||||||
|
if (!isValid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ipcRenderer.send('saveService', serviceId, service);
|
||||||
|
remote.getCurrentWindow().close();
|
||||||
|
}
|
||||||
|
|
||||||
function isValid() {
|
function isValid() {
|
||||||
if (typeof service.name !== 'string' || service.name.length === 0) {
|
if (typeof service.name !== 'string' || service.name.length === 0) {
|
||||||
console.log('Invalid name');
|
console.log('Invalid name');
|
||||||
@ -317,27 +345,6 @@
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function save() {
|
|
||||||
const formData = new FormData(document.querySelector('form'));
|
|
||||||
service.name = formData.get('name');
|
|
||||||
if (typeof service.partition !== 'string' || service.partition.length === 0) {
|
|
||||||
service.partition = service.name.replace(/ /g, '-');
|
|
||||||
service.partition = service.partition.replace(/[^a-zA-Z-_]/g, '');
|
|
||||||
}
|
|
||||||
service.url = formData.get('url');
|
|
||||||
service.isImage = formData.get('isImage') === 'on';
|
|
||||||
service.icon = formData.get('icon');
|
|
||||||
service.useFavicon = formData.get('useFavicon') === 'on';
|
|
||||||
|
|
||||||
|
|
||||||
if (!isValid()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ipcRenderer.send('saveService', serviceId, service);
|
|
||||||
remote.getCurrentWindow().close();
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -33,6 +33,7 @@ Service.requiredProperties = {
|
|||||||
'isImage': null,
|
'isImage': null,
|
||||||
'url': null,
|
'url': null,
|
||||||
'useFavicon': true,
|
'useFavicon': true,
|
||||||
|
'autoLoad': false,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Service;
|
export default Service;
|
Loading…
Reference in New Issue
Block a user