more tweaking to server consent flow and changing servers on preview

This commit is contained in:
Bruno Windels 2020-12-04 13:59:52 +01:00
parent 4d57b3c5da
commit aa62f1fedc
11 changed files with 88 additions and 32 deletions

View file

@ -179,6 +179,11 @@ input[type='text'].large {
box-sizing: border-box; box-sizing: border-box;
} }
.OpenLinkView .previewSource {
color: var(--grey);
font-size: 12px;
}
.ServerConsentView .actions { .ServerConsentView .actions {
margin-top: 24px; margin-top: 24px;
display: flex; display: flex;

View file

@ -15,6 +15,7 @@ limitations under the License.
*/ */
import {createEnum} from "./utils/enum.js"; import {createEnum} from "./utils/enum.js";
import {orderedUnique} from "./utils/unique.js";
const ROOMALIAS_PATTERN = /^#([^:]*):(.+)$/; const ROOMALIAS_PATTERN = /^#([^:]*):(.+)$/;
const ROOMID_PATTERN = /^!([^:]*):(.+)$/; const ROOMID_PATTERN = /^!([^:]*):(.+)$/;
@ -56,16 +57,6 @@ export const LinkKind = createEnum(
"Event" "Event"
) )
function orderedUnique(array) {
const copy = [];
for (let i = 0; i < array.length; ++i) {
if (i === 0 || array.lastIndexOf(array[i], i - 1) === -1) {
copy.push(array[i]);
}
}
return copy;
}
export class Link { export class Link {
static parse(fragment) { static parse(fragment) {
if (!fragment) { if (!fragment) {

View file

@ -15,9 +15,11 @@ limitations under the License.
*/ */
import {Platform} from "./Platform.js"; import {Platform} from "./Platform.js";
import {EventEmitter} from "./utils/ViewModel.js";
export class Preferences { export class Preferences extends EventEmitter {
constructor(localStorage) { constructor(localStorage) {
super();
this._localStorage = localStorage; this._localStorage = localStorage;
this.clientId = null; this.clientId = null;
// used to differentiate web from native if a client supports both // used to differentiate web from native if a client supports both
@ -41,11 +43,15 @@ export class Preferences {
platform = Platform[platform]; platform = Platform[platform];
this.platform = platform; this.platform = platform;
this._localStorage.setItem("preferred_client", JSON.stringify({id, platform})); this._localStorage.setItem("preferred_client", JSON.stringify({id, platform}));
this.emit("canClear")
} }
setHomeservers(homeservers) { setHomeservers(homeservers, persist) {
this.homeservers = homeservers; this.homeservers = homeservers;
if (persist) {
this._localStorage.setItem("consented_servers", JSON.stringify(homeservers)); this._localStorage.setItem("consented_servers", JSON.stringify(homeservers));
this.emit("canClear");
}
} }
clear() { clear() {

View file

@ -29,6 +29,9 @@ export class RootViewModel extends ViewModel {
this.openLinkViewModel = null; this.openLinkViewModel = null;
this.createLinkViewModel = null; this.createLinkViewModel = null;
this.loadServerPolicyViewModel = null; this.loadServerPolicyViewModel = null;
this.preferences.on("canClear", () => {
this.emitChange();
});
} }
_updateChildVMs(oldLink) { _updateChildVMs(oldLink) {
@ -37,7 +40,7 @@ export class RootViewModel extends ViewModel {
if (!oldLink || !oldLink.equals(this.link)) { if (!oldLink || !oldLink.equals(this.link)) {
this.openLinkViewModel = new OpenLinkViewModel(this.childOptions({ this.openLinkViewModel = new OpenLinkViewModel(this.childOptions({
link: this.link, link: this.link,
clients: createClients() clients: createClients(),
})); }));
} }
} else { } else {

View file

@ -39,7 +39,11 @@ class ShowLinkView extends TemplateView {
onClick: () => vm.showClients() onClick: () => vm.showClients()
}, vm => vm.showClientsLabel)), }, vm => vm.showClientsLabel)),
t.mapView(vm => vm.clientsViewModel, childVM => childVM ? new ClientListView(childVM) : null), t.mapView(vm => vm.clientsViewModel, childVM => childVM ? new ClientListView(childVM) : null),
t.p({className: {hidden: vm => !vm.previewDomain}}, ["Preview provided by ", vm => vm.previewDomain]), t.p({className: {previewSource: true, hidden: vm => !vm.previewDomain}}, [
vm => vm.previewFailed ? `${vm.previewDomain} did not return a preview.` : `Preview provided by ${vm.previewDomain}.`,
" ",
t.button({className: "text", onClick: () => vm.changeServer()}, "Change"),
]),
]); ]);
} }
} }

View file

@ -32,6 +32,13 @@ export class OpenLinkViewModel extends ViewModel {
this.clientsViewModel = null; this.clientsViewModel = null;
this.previewLoading = false; this.previewLoading = false;
if (this.preferences.homeservers === null) { if (this.preferences.homeservers === null) {
this._showServerConsent();
} else {
this._showLink();
}
}
_showServerConsent() {
this.serverConsentViewModel = new ServerConsentViewModel(this.childOptions({ this.serverConsentViewModel = new ServerConsentViewModel(this.childOptions({
servers: this._link.servers, servers: this._link.servers,
done: () => { done: () => {
@ -39,9 +46,6 @@ export class OpenLinkViewModel extends ViewModel {
this._showLink(); this._showLink();
} }
})); }));
} else {
this._showLink();
}
} }
async _showLink() { async _showLink() {
@ -63,13 +67,24 @@ export class OpenLinkViewModel extends ViewModel {
} }
get previewDomain() { get previewDomain() {
return this.previewViewModel.previewDomain; return this.previewViewModel?.domain;
}
get previewFailed() {
return this.previewViewModel?.failed;
} }
get showClientsLabel() { get showClientsLabel() {
return getLabelForLinkKind(this._link.kind); return getLabelForLinkKind(this._link.kind);
} }
changeServer() {
this.previewViewModel = null;
this.clientsViewModel = null;
this._showServerConsent();
this.emitChange();
}
showClients() { showClients() {
if (!this.clientsViewModel) { if (!this.clientsViewModel) {
this.clientsViewModel = new ClientListViewModel(this.childOptions({ this.clientsViewModel = new ClientListViewModel(this.childOptions({

View file

@ -50,7 +50,7 @@ export class ServerConsentView extends TemplateView {
t.form({action: "#", onSubmit: evt => this._onSubmit(evt)}, [ t.form({action: "#", onSubmit: evt => this._onSubmit(evt)}, [
t.mapView(vm => vm.showSelectServer, show => show ? new ServerOptions(vm) : null), t.mapView(vm => vm.showSelectServer, show => show ? new ServerOptions(vm) : null),
t.div({className: "actions"}, [ t.div({className: "actions"}, [
t.label([t.input({type: "checkbox", name: "persist"}), "Ask every time"]), t.label([t.input({type: "checkbox", name: "askEveryTime"}), "Ask every time"]),
t.input({type: "submit", value: "Continue", className: "primary fullwidth"}) t.input({type: "submit", value: "Continue", className: "primary fullwidth"})
]) ])
]) ])
@ -59,7 +59,8 @@ export class ServerConsentView extends TemplateView {
_onSubmit(evt) { _onSubmit(evt) {
evt.preventDefault(); evt.preventDefault();
this.value.continueWithSelection(); const {askEveryTime} = evt.target.elements;
this.value.continueWithSelection(askEveryTime.checked);
} }
} }

View file

@ -19,6 +19,7 @@ import {ClientListViewModel} from "./ClientListViewModel.js";
import {ClientViewModel} from "./ClientViewModel.js"; import {ClientViewModel} from "./ClientViewModel.js";
import {PreviewViewModel} from "../preview/PreviewViewModel.js"; import {PreviewViewModel} from "../preview/PreviewViewModel.js";
import {getLabelForLinkKind} from "../Link.js"; import {getLabelForLinkKind} from "../Link.js";
import {orderedUnique} from "../utils/unique.js";
export class ServerConsentViewModel extends ViewModel { export class ServerConsentViewModel extends ViewModel {
constructor(options) { constructor(options) {
@ -47,7 +48,7 @@ export class ServerConsentViewModel extends ViewModel {
try { try {
const domain = new URL(urlStr).hostname; const domain = new URL(urlStr).hostname;
if (/((?:[0-9a-zA-Z][0-9a-zA-Z-]{1,61}\.)+)(xn--[a-z0-9]+|[a-z]+)/.test(domain) || domain === "localhost") { if (/((?:[0-9a-zA-Z][0-9a-zA-Z-]{1,61}\.)+)(xn--[a-z0-9]+|[a-z]+)/.test(domain) || domain === "localhost") {
this.selectServer(urlStr); this.selectServer(domainOrUrl);
return true; return true;
} }
} catch (err) {} } catch (err) {}
@ -55,11 +56,11 @@ export class ServerConsentViewModel extends ViewModel {
return false; return false;
} }
continueWithSelection() { continueWithSelection(askEveryTime) {
// keep previously consented servers // keep previously consented servers
const homeservers = this.preferences.homeservers || []; const homeservers = this.preferences.homeservers || [];
homeservers.unshift(this.selectedServer); homeservers.unshift(this.selectedServer);
this.preferences.setHomeservers(homeservers); this.preferences.setHomeservers(orderedUnique(homeservers), !askEveryTime);
this.done(); this.done();
} }

View file

@ -32,13 +32,13 @@ export class PreviewViewModel extends ViewModel {
this.identifier = null; this.identifier = null;
this.memberCount = null; this.memberCount = null;
this.topic = null; this.topic = null;
this.previewDomain = null; this.domain = null;
this.failed = false;
} }
async load() { async load() {
this.loading = true; this.loading = true;
this.emitChange(); this.emitChange();
// await new Promise(r => setTimeout(r, 5000));
for (const server of this._consentedServers) { for (const server of this._consentedServers) {
try { try {
const homeserver = await resolveServer(this.request, server); const homeserver = await resolveServer(this.request, server);
@ -51,7 +51,7 @@ export class PreviewViewModel extends ViewModel {
break; break;
} }
// assume we're done if nothing threw // assume we're done if nothing threw
this.previewDomain = server; this.domain = server;
this.loading = false; this.loading = false;
this.emitChange(); this.emitChange();
return; return;
@ -59,8 +59,13 @@ export class PreviewViewModel extends ViewModel {
continue; continue;
} }
} }
this._setNoPreview(this._link); this._setNoPreview(this._link);
this.loading = false; this.loading = false;
if (this._consentedServers.length) {
this.domain = this._consentedServers[this._consentedServers.length - 1];
this.failed = true;
}
this.emitChange(); this.emitChange();
} }

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
class EventEmitter { export class EventEmitter {
constructor() { constructor() {
this._handlersByName = {}; this._handlersByName = {};
} }

25
src/utils/unique.js Normal file
View file

@ -0,0 +1,25 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
export function orderedUnique(array) {
const copy = [];
for (let i = 0; i < array.length; ++i) {
if (i === 0 || array.lastIndexOf(array[i], i - 1) === -1) {
copy.push(array[i]);
}
}
return copy;
}