more tweaking to server consent flow and changing servers on preview
This commit is contained in:
parent
4d57b3c5da
commit
aa62f1fedc
11 changed files with 88 additions and 32 deletions
|
@ -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;
|
||||||
|
|
11
src/Link.js
11
src/Link.js
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
this._localStorage.setItem("consented_servers", JSON.stringify(homeservers));
|
if (persist) {
|
||||||
|
this._localStorage.setItem("consented_servers", JSON.stringify(homeservers));
|
||||||
|
this.emit("canClear");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clear() {
|
clear() {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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"),
|
||||||
|
]),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,18 +32,22 @@ 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.serverConsentViewModel = new ServerConsentViewModel(this.childOptions({
|
this._showServerConsent();
|
||||||
servers: this._link.servers,
|
|
||||||
done: () => {
|
|
||||||
this.serverConsentViewModel = null;
|
|
||||||
this._showLink();
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
} else {
|
} else {
|
||||||
this._showLink();
|
this._showLink();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_showServerConsent() {
|
||||||
|
this.serverConsentViewModel = new ServerConsentViewModel(this.childOptions({
|
||||||
|
servers: this._link.servers,
|
||||||
|
done: () => {
|
||||||
|
this.serverConsentViewModel = null;
|
||||||
|
this._showLink();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
async _showLink() {
|
async _showLink() {
|
||||||
const preferredClient = this.preferences.clientId ? this._clients.find(c => c.id === this.preferences.clientId) : null;
|
const preferredClient = this.preferences.clientId ? this._clients.find(c => c.id === this.preferences.clientId) : null;
|
||||||
this.clientsViewModel = preferredClient ? new ClientListViewModel(this.childOptions({
|
this.clientsViewModel = preferredClient ? new ClientListViewModel(this.childOptions({
|
||||||
|
@ -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({
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
25
src/utils/unique.js
Normal 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;
|
||||||
|
}
|
Loading…
Reference in a new issue