Port part of the settings functionality to vue.

This commit is contained in:
Richard Lewis 2019-03-03 17:19:48 +02:00 committed by Pavel Djundik
parent 08635beb61
commit 6c10a2a6cf
6 changed files with 197 additions and 147 deletions

View file

@ -15,7 +15,6 @@
class="container"
method="post"
action=""
:data-event="defaults.uuid ? 'network:edit' : 'network:new'"
@submit.prevent="onSubmit"
>
<div class="row">

View file

@ -11,13 +11,19 @@
aria-label="Toggle channel list"
/>
</div>
<div class="container">
<form
ref="settingsForm"
class="container"
@change="onChange"
@submit.prevent
>
<h1 class="title">Settings</h1>
<div class="row">
<div class="col-sm-6">
<label class="opt">
<input
v-model="$root.serverConfiguration.advanced"
type="checkbox"
name="advanced"
>
@ -28,9 +34,9 @@
<div class="row">
<div
v-if="canRegisterProtocol"
id="native-app"
class="col-sm-12"
hidden
>
<h2>Native app</h2>
<button
@ -43,13 +49,13 @@
id="make-default-client"
type="button"
class="btn"
@click.prevent="registerProtocol"
>Open irc:// URLs with The Lounge</button>
</div>
<div
v-if="!this.$root.serverConfiguration.public"
v-if="!$root.serverConfiguration.public && $root.serverConfiguration.advanced"
class="col-sm-12"
data-advanced
>
<h2>
Settings synchronisation
@ -65,14 +71,28 @@
</h2>
<label class="opt">
<input
v-model="$root.settings.syncSettings"
type="checkbox"
name="syncSettings"
>
Synchronize settings with other clients.
</label>
<p class="sync-warning-override"><strong>Warning</strong> Checking this box will override the settings of this client with those stored on the server.</p>
<p class="sync-warning-base"><strong>Warning</strong> No settings have been synced before. Enabling this will sync all settings of this client as the base for other clients.</p>
<div class="opt force-sync-button">
<p
v-if="!$root.settings.syncSettings"
class="sync-warning-override"
>
<strong>Warning</strong> Checking this box will override the settings of this client with those stored on the server.
</p>
<p
v-if="!$root.settings.syncSettings"
class="sync-warning-base"
>
<strong>Warning</strong> No settings have been synced before. Enabling this will sync all settings of this client as the base for other clients.
</p>
<div
v-if="$root.settings.syncSettings"
class="opt force-sync-button"
>
<button
type="button"
class="btn"
@ -88,6 +108,7 @@
<div class="col-sm-6">
<label class="opt">
<input
v-model="$root.settings.motd"
type="checkbox"
name="motd"
>
@ -97,6 +118,7 @@
<div class="col-sm-6">
<label class="opt">
<input
v-model="$root.settings.showSeconds"
type="checkbox"
name="showSeconds"
>
@ -120,6 +142,7 @@
<div class="col-sm-12">
<label class="opt">
<input
v-model="$root.settings.statusMessages"
type="radio"
name="statusMessages"
value="shown"
@ -128,6 +151,7 @@
</label>
<label class="opt">
<input
v-model="$root.settings.statusMessages"
type="radio"
name="statusMessages"
value="condensed"
@ -136,6 +160,7 @@
</label>
<label class="opt">
<input
v-model="$root.settings.statusMessages"
type="radio"
name="statusMessages"
value="hidden"
@ -149,6 +174,7 @@
<div class="col-sm-12">
<label class="opt">
<input
v-model="$root.settings.coloredNicks"
type="checkbox"
name="coloredNicks"
>
@ -156,6 +182,7 @@
</label>
<label class="opt">
<input
v-model="$root.settings.autocomplete"
type="checkbox"
name="autocomplete"
>
@ -163,8 +190,8 @@
</label>
</div>
<div
v-if="$root.serverConfiguration.advanced"
class="col-sm-12"
data-advanced
>
<label class="opt">
<label
@ -173,6 +200,7 @@
>Nick autocomplete postfix (e.g. <code>, </code>)</label>
<input
id="nickPostfix"
v-model="$root.settings.nickPostfix"
type="text"
name="nickPostfix"
class="input"
@ -191,11 +219,12 @@
>Theme</label>
<select
id="theme-select"
v-model="$root.settings.theme"
name="theme"
class="input"
>
<option
v-for="theme in this.$root.serverConfiguration.themes"
v-for="theme in $root.serverConfiguration.themes"
:key="theme.name"
>
{{ theme.displayName }}
@ -203,7 +232,7 @@
</select>
</div>
<template v-if="this.$root.serverConfiguration.prefetch">
<template v-if="$root.serverConfiguration.prefetch">
<div class="col-sm-12">
<h2>Link previews</h2>
</div>
@ -219,6 +248,7 @@
<div class="col-sm-6">
<label class="opt">
<input
v-model="$root.settings.links"
type="checkbox"
name="links"
>
@ -227,7 +257,7 @@
</div>
</template>
<template v-if="!this.$root.serverConfiguration.public">
<template v-if="!$root.serverConfiguration.public">
<div class="col-sm-12">
<h2>Push Notifications</h2>
</div>
@ -240,14 +270,14 @@
data-text-alternate="Unsubscribe from push notifications"
>Subscribe to push notifications</button>
<div
v-if="this.$root.pushNotificationState === 'nohttps'"
v-if="$root.pushNotificationState === 'nohttps'"
class="error"
>
<strong>Warning</strong>:
Push notifications are only supported over HTTPS connections.
</div>
<div
v-if="this.$root.pushNotificationState === 'unsupported'"
v-if="$root.pushNotificationState === 'unsupported'"
class="error"
>
<strong>Warning</strong>:
@ -261,6 +291,7 @@
</div>
<div class="col-sm-12">
<label class="opt">
<!-- TODO: handle enabling/disabling notifications -->
<input
id="desktopNotifications"
type="checkbox"
@ -268,14 +299,14 @@
>
Enable browser notifications<br>
<div
v-if="this.$root.desktopNotificationState === 'unsupported'"
v-if="$root.desktopNotificationState === 'unsupported'"
class="error"
>
<strong>Warning</strong>:
Notifications are not supported by your browser.
</div>
<div
v-if="this.$root.desktopNotificationState === 'blocked'"
v-if="$root.desktopNotificationState === 'blocked'"
id="warnBlockedDesktopNotifications"
class="error"
>
@ -287,6 +318,7 @@
<div class="col-sm-12">
<label class="opt">
<input
v-model="$root.settings.notification"
type="checkbox"
name="notification"
>
@ -295,16 +327,20 @@
</div>
<div class="col-sm-12">
<div class="opt">
<button id="play">Play sound</button>
<button
id="play"
@click.prevent="playNotification"
>Play sound</button>
</div>
</div>
<div
v-if="$root.serverConfiguration.advanced"
class="col-sm-12"
data-advanced
>
<label class="opt">
<input
v-model="$root.settings.notifyAllMessages"
type="checkbox"
name="notifyAllMessages"
>
@ -313,8 +349,8 @@
</div>
<div
v-if="$root.serverConfiguration.advanced"
class="col-sm-12"
data-advanced
>
<label class="opt">
<label
@ -323,6 +359,7 @@
>Custom highlights (comma-separated keywords)</label>
<input
id="highlights"
v-model="$root.settings.highlights"
type="text"
name="highlights"
class="input"
@ -332,76 +369,87 @@
</div>
<div
v-if="!this.$root.serverConfiguration.public && !this.$root.serverConfiguration.ldapEnabled"
v-if="!$root.serverConfiguration.public && !$root.serverConfiguration.ldapEnabled"
id="change-password"
>
<form
action=""
method="post"
data-event="change-password"
>
<div class="col-sm-12">
<h2>Change password</h2>
</div>
<div class="col-sm-12 password-container">
<!-- TODO: use revealPassword -->
<label
for="old_password_input"
class="sr-only"
>Enter current password</label>
<div class="col-sm-12">
<h2>Change password</h2>
</div>
<div class="col-sm-12 password-container">
<label
for="old_password_input"
class="sr-only"
>Enter current password</label>
<RevealPassword v-slot:default="slotProps">
<input
id="old_password_input"
type="password"
:type="slotProps.isVisible ? 'text' : 'password'"
name="old_password"
class="input"
placeholder="Enter current password"
>
</div>
<div class="col-sm-12 password-container">
<label
for="new_password_input"
class="sr-only"
>Enter desired new password</label>
</RevealPassword>
</div>
<div class="col-sm-12 password-container">
<label
for="new_password_input"
class="sr-only"
>Enter desired new password</label>
<RevealPassword v-slot:default="slotProps">
<input
id="new_password_input"
type="password"
:type="slotProps.isVisible ? 'text' : 'password'"
name="new_password"
class="input"
placeholder="Enter desired new password"
>
</div>
<div class="col-sm-12 password-container">
<label
for="verify_password_input"
class="sr-only"
>Repeat new password</label>
</RevealPassword>
</div>
<div class="col-sm-12 password-container">
<label
for="verify_password_input"
class="sr-only"
>Repeat new password</label>
<RevealPassword v-slot:default="slotProps">
<input
id="verify_password_input"
type="password"
:type="slotProps.isVisible ? 'text' : 'password'"
name="verify_password"
class="input"
placeholder="Repeat new password"
>
</div>
<div class="col-sm-12 feedback" />
<div class="col-sm-12">
<button
type="submit"
class="btn"
>Change password</button>
</div>
</form>
</RevealPassword>
</div>
<div
v-if="passwordChangeStatus && passwordChangeStatus.success"
class="col-sm-12 feedback success"
>
Successfully updated your password
</div>
<div
v-else-if="passwordChangeStatus && passwordChangeStatus.error"
class="col-sm-12 feedback error"
>
{{ passwordErrors[passwordChangeStatus.error] }}
</div>
<div class="col-sm-12">
<button
type="submit"
class="btn"
@click.prevent="changePassword"
>Change password</button>
</div>
</div>
<div
v-if="$root.serverConfiguration.advanced"
class="col-sm-12"
data-advanced
>
<h2>Custom Stylesheet</h2>
</div>
<div
v-if="$root.serverConfiguration.advanced"
class="col-sm-12"
data-advanced
>
<label
for="user-specified-css-input"
@ -418,10 +466,11 @@
</div>
<div
v-if="!this.$root.serverConfiguration.public"
v-if="!$root.serverConfiguration.public"
class="session-list"
>
<h2>Sessions</h2>
<!-- TODO: Sessions -->
<h3>Current session</h3>
<div id="session-current" />
@ -429,13 +478,13 @@
<h3>Other sessions</h3>
<div id="session-list" />
</div>
</div>
</form>
</div>
</template>
<script>
const storage = require("../../js/localStorage");
// const storage = require("../../js/localStorage"); // TODO: use this
import socket from "../../js/socket";
import RevealPassword from "../RevealPassword.vue";
@ -446,30 +495,95 @@ export default {
},
data() {
return {
inFlight: false,
errorShown: false,
canRegisterProtocol: false,
passwordChangeStatus: null,
passwordErrors: {
missing_fields: "Please enter a new password",
password_mismatch: "Both new password fields must match",
password_incorrect: "The current password field does not match your account password",
update_failed: "Failed to update your password",
},
};
},
mounted() {
// Enable protocol handler registration if supported
if (window.navigator.registerProtocolHandler) {
this.canRegisterProtocol = true;
}
},
methods: {
onSubmit(event) {
event.preventDefault();
onChange(event) {
const ignore = [
"old_password",
"new_password",
"verify_password",
];
this.inFlight = true;
this.errorShown = false;
const name = event.target.name;
const values = {
user: this.$refs.username.value,
password: this.$refs.password.value,
if (ignore.includes(name)) {
return;
}
let value;
if (event.target.type === "checkbox") {
value = event.target.checked;
} else {
value = event.target.value;
}
this.storeSetting(name, value);
},
storeSetting(name, value) {
// TODO: port logic from options.js
socket.emit("setting:set", {name, value});
},
changePassword() {
const allFields = new FormData(this.$refs.settingsForm);
const data = {
old_password: allFields.get("old_password"),
new_password: allFields.get("new_password"),
verify_password: allFields.get("verify_password"),
};
storage.set("user", values.user);
if (!data.old_password || !data.new_password || !data.verify_password) {
this.passwordChangeStatus = {
success: false,
error: "missing_fields",
};
return;
}
socket.emit("auth", values);
if (data.new_password !== data.verify_password) {
this.passwordChangeStatus = {
success: false,
error: "password_mismatch",
};
return;
}
socket.once("change-password", (response) => {
this.passwordChangeStatus = response;
});
socket.emit("change-password", data);
},
onForceSyncClick() {
const options = require("../../js/options");
options.syncAllSettings(true);
},
registerProtocol() {
const uri = document.location.origin + document.location.pathname + "?uri=%s";
window.navigator.registerProtocolHandler("irc", uri, "The Lounge");
window.navigator.registerProtocolHandler("ircs", uri, "The Lounge");
},
playNotification() {
const pop = new Audio();
pop.src = "audio/pop.wav";
pop.play();
},
},
};
</script>

View file

@ -116,8 +116,6 @@ function applySetting(name, value) {
if (("Notification" in window) && value && Notification.permission !== "granted") {
Notification.requestPermission(updateDesktopNotificationStatus);
}
} else if (name === "advanced") {
$("#settings [data-advanced]").toggle(settings[name]);
}
}
@ -219,6 +217,7 @@ function initialize() {
vueApp.desktopNotificationState = "unsupported";
}
/*
$settings.on("change", "input, select, textarea", function(e) {
// We only want to trigger on human triggered changes.
if (e.originalEvent) {
@ -238,27 +237,10 @@ function initialize() {
}
}
});
*/
// Local init is done, let's sync
// We always ask for synced settings even if it is disabled.
// Settings can be mandatory to sync and it is used to determine sync base state.
socket.emit("setting:get");
// Protocol handler
const defaultClientButton = $("#make-default-client");
if (window.navigator.registerProtocolHandler) {
defaultClientButton.on("click", function() {
const uri = document.location.origin + document.location.pathname + "?uri=%s";
window.navigator.registerProtocolHandler("irc", uri, "The Lounge");
window.navigator.registerProtocolHandler("ircs", uri, "The Lounge");
return false;
});
$("#native-app").prop("hidden", false);
} else {
defaultClientButton.hide();
}
}

View file

@ -1,31 +0,0 @@
"use strict";
const $ = require("jquery");
const socket = require("../socket");
socket.on("change-password", function(data) {
const passwordForm = $("#change-password");
if (data.error || data.success) {
const message = data.success ? data.success : data.error;
const feedback = passwordForm.find(".feedback");
if (data.success) {
feedback.addClass("success").removeClass("error");
} else {
feedback.addClass("error").removeClass("success");
}
feedback.text(message).show();
feedback.closest("form").one("submit", function() {
feedback.hide();
});
}
passwordForm
.find("input")
.val("")
.end()
.find(".btn")
.prop("disabled", false);
});

View file

@ -39,12 +39,6 @@ socket.on("configuration", function(data) {
socket.emit("sessions:get");
});
$("#play").on("click", () => {
const pop = new Audio();
pop.src = "audio/pop.wav";
pop.play();
});
if (data.fileUpload) {
upload.initialize(data.fileUploadMaxFileSize);
}
@ -62,6 +56,7 @@ socket.on("configuration", function(data) {
document.querySelector('meta[name="theme-color"]').content = currentTheme.themeColor;
}
/*
function handleFormSubmit() {
const form = $(this);
const event = form.data("event");
@ -79,10 +74,9 @@ socket.on("configuration", function(data) {
return false;
}
*/
$("#change-password form").on("submit", handleFormSubmit);
connect.on("submit", "form", handleFormSubmit);
// TODO: move to component (this mirrors the nick to the username field if the username is empty)
connect.on("show", function() {
connect
.html(templates.windows.connect(data))

View file

@ -423,16 +423,9 @@ function initializeClient(socket, client, token, lastMessage, openChannel) {
const p1 = data.new_password;
const p2 = data.verify_password;
if (typeof p1 === "undefined" || p1 === "") {
if (typeof p1 === "undefined" || p1 === "" || p1 !== p2) {
socket.emit("change-password", {
error: "Please enter a new password",
});
return;
}
if (p1 !== p2) {
socket.emit("change-password", {
error: "Both new password fields must match",
error: "",
});
return;
}
@ -442,8 +435,7 @@ function initializeClient(socket, client, token, lastMessage, openChannel) {
.then((matching) => {
if (!matching) {
socket.emit("change-password", {
error:
"The current password field does not match your account password",
error: "password_incorrect",
});
return;
}
@ -454,9 +446,9 @@ function initializeClient(socket, client, token, lastMessage, openChannel) {
const obj = {};
if (success) {
obj.success = "Successfully updated your password";
obj.success = true;
} else {
obj.error = "Failed to update your password";
obj.error = "update_failed";
}
socket.emit("change-password", obj);