4.21.3
This commit is contained in:
30
app/static/js/an.js
Normal file
30
app/static/js/an.js
Normal file
@ -0,0 +1,30 @@
|
||||
(function () {
|
||||
// only enable on prod
|
||||
if (!window.location.host.endsWith('simplelogin.io')) {
|
||||
console.log("Analytics should only be enabled in prod");
|
||||
return;
|
||||
}
|
||||
|
||||
if (store.get('analytics-ignore') === 't') {
|
||||
console.log("Analytics is disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("init Analytics");
|
||||
|
||||
// Add Plausible script
|
||||
// <script async defer data-domain="app.simplelogin.io,everything.simplelogin.com" src="/p.outbound.js"></script>
|
||||
var plausibleScript = document.createElement('script');
|
||||
plausibleScript.defer = 1;
|
||||
plausibleScript.async = 1;
|
||||
plausibleScript.dataset.api = "/p/api/event";
|
||||
plausibleScript.dataset.domain = "app.simplelogin.io,everything.simplelogin.com";
|
||||
plausibleScript.src = '/p.outbound.js';
|
||||
|
||||
var ins = document.getElementsByTagName('script')[0];
|
||||
ins.parentNode.insertBefore(plausibleScript, ins);
|
||||
|
||||
// allow custom event
|
||||
window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }
|
||||
|
||||
})();
|
273
app/static/js/index.js
Normal file
273
app/static/js/index.js
Normal file
@ -0,0 +1,273 @@
|
||||
$('.mailbox-select').multipleSelect();
|
||||
|
||||
function confirmDeleteAlias() {
|
||||
let that = $(this);
|
||||
let alias = that.data("alias-email");
|
||||
let aliasDomainTrashUrl = that.data("custom-domain-trash-url");
|
||||
|
||||
let message = `Maybe you want to disable the alias instead? Please note once deleted, it <b>can't</b> be restored.`;
|
||||
if (aliasDomainTrashUrl !== undefined) {
|
||||
message = `Maybe you want to disable the alias instead? When it's deleted, it's moved to the domain
|
||||
<a href="${aliasDomainTrashUrl}">trash</a>`;
|
||||
}
|
||||
|
||||
bootbox.dialog({
|
||||
title: `Delete ${alias}`,
|
||||
message: message,
|
||||
size: 'large',
|
||||
onEscape: true,
|
||||
backdrop: true,
|
||||
buttons: {
|
||||
disable: {
|
||||
label: 'Disable it',
|
||||
className: 'btn-primary',
|
||||
callback: function () {
|
||||
that.closest("form").find('input[name="form-name"]').val("disable-alias");
|
||||
that.closest("form").submit();
|
||||
}
|
||||
},
|
||||
|
||||
delete: {
|
||||
label: "Delete it, I don't need it anymore",
|
||||
className: 'btn-outline-danger',
|
||||
callback: function () {
|
||||
that.closest("form").submit();
|
||||
}
|
||||
},
|
||||
|
||||
cancel: {
|
||||
label: 'Cancel',
|
||||
className: 'btn-outline-primary'
|
||||
},
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(".enable-disable-alias").change(async function () {
|
||||
let aliasId = $(this).data("alias");
|
||||
let alias = $(this).data("alias-email");
|
||||
|
||||
await disableAlias(aliasId, alias);
|
||||
});
|
||||
|
||||
async function disableAlias(aliasId, alias) {
|
||||
let oldValue;
|
||||
try {
|
||||
let res = await fetch(`/api/aliases/${aliasId}/toggle`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
let json = await res.json();
|
||||
|
||||
if (json.enabled) {
|
||||
toastr.success(`${alias} is enabled`);
|
||||
$(`#send-email-${aliasId}`).removeClass("disabled");
|
||||
} else {
|
||||
toastr.success(`${alias} is disabled`);
|
||||
$(`#send-email-${aliasId}`).addClass("disabled");
|
||||
}
|
||||
} else {
|
||||
toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error");
|
||||
// reset to the original value
|
||||
oldValue = !$(this).prop("checked");
|
||||
$(this).prop("checked", oldValue);
|
||||
}
|
||||
} catch (e) {
|
||||
toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error");
|
||||
// reset to the original value
|
||||
oldValue = !$(this).prop("checked");
|
||||
$(this).prop("checked", oldValue);
|
||||
}
|
||||
}
|
||||
|
||||
$(".enable-disable-pgp").change(async function (e) {
|
||||
let aliasId = $(this).data("alias");
|
||||
let alias = $(this).data("alias-email");
|
||||
const oldValue = !$(this).prop("checked");
|
||||
let newValue = !oldValue;
|
||||
|
||||
try {
|
||||
let res = await fetch(`/api/aliases/${aliasId}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
disable_pgp: oldValue,
|
||||
}),
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
if (newValue) {
|
||||
toastr.success(`PGP is enabled for ${alias}`);
|
||||
} else {
|
||||
toastr.info(`PGP is disabled for ${alias}`);
|
||||
}
|
||||
} else {
|
||||
toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error");
|
||||
// reset to the original value
|
||||
$(this).prop("checked", oldValue);
|
||||
}
|
||||
} catch (err) {
|
||||
toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error");
|
||||
// reset to the original value
|
||||
$(this).prop("checked", oldValue);
|
||||
}
|
||||
});
|
||||
|
||||
$(".pin-alias").change(async function () {
|
||||
let aliasId = $(this).data("alias");
|
||||
let alias = $(this).data("alias-email");
|
||||
const oldValue = !$(this).prop("checked");
|
||||
let newValue = !oldValue;
|
||||
|
||||
try {
|
||||
let res = await fetch(`/api/aliases/${aliasId}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
pinned: newValue,
|
||||
}),
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
if (newValue) {
|
||||
toastr.success(`${alias} is pinned`);
|
||||
} else {
|
||||
toastr.info(`${alias} is unpinned`);
|
||||
}
|
||||
} else {
|
||||
toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error");
|
||||
// reset to the original value
|
||||
$(this).prop("checked", oldValue);
|
||||
}
|
||||
} catch (e) {
|
||||
toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error");
|
||||
// reset to the original value
|
||||
$(this).prop("checked", oldValue);
|
||||
}
|
||||
});
|
||||
|
||||
$(".save-note").on("click", async function () {
|
||||
let oldValue;
|
||||
let aliasId = $(this).data("alias");
|
||||
let note = $(`#note-${aliasId}`).val();
|
||||
|
||||
try {
|
||||
let res = await fetch(`/api/aliases/${aliasId}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
note: note,
|
||||
}),
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
toastr.success(`Saved`);
|
||||
} else {
|
||||
toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error");
|
||||
// reset to the original value
|
||||
oldValue = !$(this).prop("checked");
|
||||
$(this).prop("checked", oldValue);
|
||||
}
|
||||
} catch (e) {
|
||||
toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error");
|
||||
// reset to the original value
|
||||
oldValue = !$(this).prop("checked");
|
||||
$(this).prop("checked", oldValue);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
$(".save-mailbox").on("click", async function () {
|
||||
let oldValue;
|
||||
let aliasId = $(this).data("alias");
|
||||
let mailbox_ids = $(`#mailbox-${aliasId}`).val();
|
||||
|
||||
if (mailbox_ids.length === 0) {
|
||||
toastr.error("You must select at least a mailbox", "Error");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
let res = await fetch(`/api/aliases/${aliasId}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
mailbox_ids: mailbox_ids,
|
||||
}),
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
toastr.success(`Mailbox Updated`);
|
||||
} else {
|
||||
toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error");
|
||||
// reset to the original value
|
||||
oldValue = !$(this).prop("checked");
|
||||
$(this).prop("checked", oldValue);
|
||||
}
|
||||
} catch (e) {
|
||||
toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error");
|
||||
// reset to the original value
|
||||
oldValue = !$(this).prop("checked");
|
||||
$(this).prop("checked", oldValue);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
$(".save-alias-name").on("click", async function () {
|
||||
let aliasId = $(this).data("alias");
|
||||
let name = $(`#alias-name-${aliasId}`).val();
|
||||
|
||||
try {
|
||||
let res = await fetch(`/api/aliases/${aliasId}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: name,
|
||||
}),
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
toastr.success(`Alias Name Saved`);
|
||||
} else {
|
||||
toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error");
|
||||
}
|
||||
} catch (e) {
|
||||
toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error");
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
new Vue({
|
||||
el: '#filter-app',
|
||||
delimiters: ["[[", "]]"], // necessary to avoid conflict with jinja
|
||||
data: {
|
||||
showFilter: false
|
||||
},
|
||||
methods: {
|
||||
async toggleFilter() {
|
||||
let that = this;
|
||||
that.showFilter = !that.showFilter;
|
||||
store.set('showFilter', that.showFilter);
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
if (store.get("showFilter"))
|
||||
this.showFilter = true;
|
||||
}
|
||||
});
|
40
app/static/js/theme.js
Normal file
40
app/static/js/theme.js
Normal file
@ -0,0 +1,40 @@
|
||||
let setCookie = function(name, value, days) {
|
||||
if (!name || !value) return false;
|
||||
let expires = '';
|
||||
let secure = '';
|
||||
if (location.protocol === 'https:') secure = 'Secure; ';
|
||||
|
||||
if (days) {
|
||||
let date = new Date();
|
||||
date.setTime(date.getTime() + (days * 24*60*60*1000));
|
||||
expires = 'Expires=' + date.toUTCString() + '; ';
|
||||
}
|
||||
|
||||
document.cookie = name + '=' + value + '; ' +
|
||||
expires +
|
||||
secure +
|
||||
'sameSite=Lax; ' +
|
||||
'domain=' + window.location.hostname + '; ' +
|
||||
'path=/';
|
||||
return true;
|
||||
}
|
||||
|
||||
let getCookie = function(name) {
|
||||
let match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
|
||||
if (match) return match[2];
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
/** Dark mode controller */
|
||||
if (getCookie('dark-mode') === "true") {
|
||||
document.documentElement.setAttribute('data-theme', 'dark');
|
||||
}
|
||||
$('[data-toggle="dark-mode"]').on('click', function () {
|
||||
if (getCookie('dark-mode') === "true") {
|
||||
setCookie('dark-mode', 'false', 30);
|
||||
return document.documentElement.setAttribute('data-theme', 'light')
|
||||
}
|
||||
setCookie('dark-mode', 'true', 30);
|
||||
document.documentElement.setAttribute('data-theme', 'dark')
|
||||
})
|
||||
});
|
28
app/static/js/utils/drag-drop-into-text.js
Normal file
28
app/static/js/utils/drag-drop-into-text.js
Normal file
@ -0,0 +1,28 @@
|
||||
const MAX_BYTES = 10240; // 10KiB
|
||||
|
||||
function enableDragDropForPGPKeys(inputID) {
|
||||
function drop(event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
let files = event.dataTransfer.files;
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
let file = files[i];
|
||||
if(file.type !== 'text/plain'){
|
||||
toastr.warning(`File ${file.name} is not a public key file`);
|
||||
continue;
|
||||
}
|
||||
let reader = new FileReader();
|
||||
reader.onloadend = onFileLoaded;
|
||||
reader.readAsBinaryString(file);
|
||||
}
|
||||
}
|
||||
|
||||
function onFileLoaded(event) {
|
||||
const initialData = event.currentTarget.result.substr(0, MAX_BYTES);
|
||||
$(inputID).val(initialData);
|
||||
}
|
||||
|
||||
const dropArea = $(inputID).get(0);
|
||||
dropArea.addEventListener("drop", drop, false);
|
||||
}
|
Reference in New Issue
Block a user