Mass Tabs -> Spaces conversion
This commit is contained in:
+40
-40
@@ -18,50 +18,50 @@ import {TemplateView} from "../utils/TemplateView.js";
|
||||
import {ClientView} from "./ClientView.js";
|
||||
|
||||
export class ClientListView extends TemplateView {
|
||||
render(t, vm) {
|
||||
return t.mapView(vm => vm.clientViewModel, () => {
|
||||
if (vm.clientViewModel) {
|
||||
return new ContinueWithClientView(vm);
|
||||
} else {
|
||||
return new AllClientsView(vm);
|
||||
}
|
||||
});
|
||||
}
|
||||
render(t, vm) {
|
||||
return t.mapView(vm => vm.clientViewModel, () => {
|
||||
if (vm.clientViewModel) {
|
||||
return new ContinueWithClientView(vm);
|
||||
} else {
|
||||
return new AllClientsView(vm);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class AllClientsView extends TemplateView {
|
||||
render(t, vm) {
|
||||
return t.div({className: "ClientListView"}, [
|
||||
t.h2("Choose an app to continue"),
|
||||
t.map(vm => vm.clientList, (clientList, t) => {
|
||||
return t.div({className: "list"}, clientList.map(clientViewModel => {
|
||||
return t.view(new ClientView(clientViewModel));
|
||||
}));
|
||||
}),
|
||||
t.div(t.label([
|
||||
t.input({
|
||||
type: "checkbox",
|
||||
checked: vm.showUnsupportedPlatforms,
|
||||
onChange: evt => vm.showUnsupportedPlatforms = evt.target.checked,
|
||||
}),
|
||||
"Show apps not available on my platform"
|
||||
])),
|
||||
t.div(t.label({className: "filterOption"}, [
|
||||
t.input({
|
||||
type: "checkbox",
|
||||
checked: vm.showExperimental,
|
||||
onChange: evt => vm.showExperimental = evt.target.checked,
|
||||
}),
|
||||
"Show experimental apps"
|
||||
])),
|
||||
]);
|
||||
}
|
||||
render(t, vm) {
|
||||
return t.div({className: "ClientListView"}, [
|
||||
t.h2("Choose an app to continue"),
|
||||
t.map(vm => vm.clientList, (clientList, t) => {
|
||||
return t.div({className: "list"}, clientList.map(clientViewModel => {
|
||||
return t.view(new ClientView(clientViewModel));
|
||||
}));
|
||||
}),
|
||||
t.div(t.label([
|
||||
t.input({
|
||||
type: "checkbox",
|
||||
checked: vm.showUnsupportedPlatforms,
|
||||
onChange: evt => vm.showUnsupportedPlatforms = evt.target.checked,
|
||||
}),
|
||||
"Show apps not available on my platform"
|
||||
])),
|
||||
t.div(t.label({className: "filterOption"}, [
|
||||
t.input({
|
||||
type: "checkbox",
|
||||
checked: vm.showExperimental,
|
||||
onChange: evt => vm.showExperimental = evt.target.checked,
|
||||
}),
|
||||
"Show experimental apps"
|
||||
])),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
class ContinueWithClientView extends TemplateView {
|
||||
render(t, vm) {
|
||||
return t.div({className: "ClientListView"}, [
|
||||
t.div({className: "list"}, t.view(new ClientView(vm.clientViewModel)))
|
||||
]);
|
||||
}
|
||||
render(t, vm) {
|
||||
return t.div({className: "ClientListView"}, [
|
||||
t.div({className: "list"}, t.view(new ClientView(vm.clientViewModel)))
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,70 +20,70 @@ import {ClientViewModel} from "./ClientViewModel.js";
|
||||
import {ViewModel} from "../utils/ViewModel.js";
|
||||
|
||||
export class ClientListViewModel extends ViewModel {
|
||||
constructor(options) {
|
||||
super(options);
|
||||
const {clients, client, link} = options;
|
||||
this._clients = clients;
|
||||
this._link = link;
|
||||
this.clientList = null;
|
||||
this._showExperimental = false;
|
||||
this._showUnsupportedPlatforms = false;
|
||||
this._filterClients();
|
||||
this.clientViewModel = null;
|
||||
if (client) {
|
||||
this._pickClient(client);
|
||||
}
|
||||
}
|
||||
constructor(options) {
|
||||
super(options);
|
||||
const {clients, client, link} = options;
|
||||
this._clients = clients;
|
||||
this._link = link;
|
||||
this.clientList = null;
|
||||
this._showExperimental = false;
|
||||
this._showUnsupportedPlatforms = false;
|
||||
this._filterClients();
|
||||
this.clientViewModel = null;
|
||||
if (client) {
|
||||
this._pickClient(client);
|
||||
}
|
||||
}
|
||||
|
||||
get showUnsupportedPlatforms() {
|
||||
return this._showUnsupportedPlatforms;
|
||||
}
|
||||
get showUnsupportedPlatforms() {
|
||||
return this._showUnsupportedPlatforms;
|
||||
}
|
||||
|
||||
get showExperimental() {
|
||||
return this._showExperimental;
|
||||
}
|
||||
get showExperimental() {
|
||||
return this._showExperimental;
|
||||
}
|
||||
|
||||
set showUnsupportedPlatforms(enabled) {
|
||||
this._showUnsupportedPlatforms = enabled;
|
||||
this._filterClients();
|
||||
}
|
||||
set showUnsupportedPlatforms(enabled) {
|
||||
this._showUnsupportedPlatforms = enabled;
|
||||
this._filterClients();
|
||||
}
|
||||
|
||||
set showExperimental(enabled) {
|
||||
this._showExperimental = enabled;
|
||||
this._filterClients();
|
||||
}
|
||||
set showExperimental(enabled) {
|
||||
this._showExperimental = enabled;
|
||||
this._filterClients();
|
||||
}
|
||||
|
||||
_filterClients() {
|
||||
const clientVMs = this._clients.filter(client => {
|
||||
_filterClients() {
|
||||
const clientVMs = this._clients.filter(client => {
|
||||
const platformMaturities = this.platforms.map(p => client.getMaturity(p));
|
||||
const isStable = platformMaturities.includes(Maturity.Stable) || platformMaturities.includes(Maturity.Beta);
|
||||
const isSupported = client.platforms.some(p => this.platforms.includes(p));
|
||||
if (!this._showExperimental && !isStable) {
|
||||
return false;
|
||||
}
|
||||
if (!this._showUnsupportedPlatforms && !isSupported) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}).map(client => new ClientViewModel(this.childOptions({
|
||||
client,
|
||||
link: this._link,
|
||||
pickClient: client => this._pickClient(client)
|
||||
})));
|
||||
const isStable = platformMaturities.includes(Maturity.Stable) || platformMaturities.includes(Maturity.Beta);
|
||||
const isSupported = client.platforms.some(p => this.platforms.includes(p));
|
||||
if (!this._showExperimental && !isStable) {
|
||||
return false;
|
||||
}
|
||||
if (!this._showUnsupportedPlatforms && !isSupported) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}).map(client => new ClientViewModel(this.childOptions({
|
||||
client,
|
||||
link: this._link,
|
||||
pickClient: client => this._pickClient(client)
|
||||
})));
|
||||
const preferredClientVMs = clientVMs.filter(c => c.hasPreferredWebInstance);
|
||||
const otherClientVMs = clientVMs.filter(c => !c.hasPreferredWebInstance);
|
||||
this.clientList = preferredClientVMs.concat(otherClientVMs);
|
||||
this.emitChange();
|
||||
}
|
||||
this.emitChange();
|
||||
}
|
||||
|
||||
_pickClient(client) {
|
||||
this.clientViewModel = this.clientList.find(vm => vm.clientId === client.id);
|
||||
_pickClient(client) {
|
||||
this.clientViewModel = this.clientList.find(vm => vm.clientId === client.id);
|
||||
this.clientViewModel.pick(this);
|
||||
this.emitChange();
|
||||
}
|
||||
this.emitChange();
|
||||
}
|
||||
|
||||
showAll() {
|
||||
this.clientViewModel = null;
|
||||
this.emitChange();
|
||||
}
|
||||
showAll() {
|
||||
this.clientViewModel = null;
|
||||
this.emitChange();
|
||||
}
|
||||
}
|
||||
|
||||
+39
-39
@@ -19,11 +19,11 @@ import {copy} from "../utils/copy.js";
|
||||
import {text, tag} from "../utils/html.js";
|
||||
|
||||
function formatPlatforms(platforms) {
|
||||
return platforms.reduce((str, p, i, all) => {
|
||||
const first = i === 0;
|
||||
const last = i === all.length - 1;
|
||||
return str + (first ? "" : last ? " & " : ", ") + p;
|
||||
}, "");
|
||||
return platforms.reduce((str, p, i, all) => {
|
||||
const first = i === 0;
|
||||
const last = i === all.length - 1;
|
||||
return str + (first ? "" : last ? " & " : ", ") + p;
|
||||
}, "");
|
||||
}
|
||||
|
||||
function renderInstructions(parts) {
|
||||
@@ -38,46 +38,46 @@ function renderInstructions(parts) {
|
||||
|
||||
export class ClientView extends TemplateView {
|
||||
|
||||
render(t, vm) {
|
||||
return t.div({className: {"ClientView": true, "isPreferred": vm => vm.hasPreferredWebInstance}}, [
|
||||
render(t, vm) {
|
||||
return t.div({className: {"ClientView": true, "isPreferred": vm => vm.hasPreferredWebInstance}}, [
|
||||
... vm.hasPreferredWebInstance ? [t.div({className: "hostedBanner"}, vm.hostedByBannerLabel)] : [],
|
||||
t.div({className: "header"}, [
|
||||
t.div({className: "description"}, [
|
||||
t.h3(vm.name),
|
||||
t.p([vm.description, " ", t.a({
|
||||
t.div({className: "header"}, [
|
||||
t.div({className: "description"}, [
|
||||
t.h3(vm.name),
|
||||
t.p([vm.description, " ", t.a({
|
||||
href: vm.homepage,
|
||||
target: "_blank",
|
||||
rel: "noopener noreferrer"
|
||||
}, "Learn more")]),
|
||||
t.p({className: "platforms"}, formatPlatforms(vm.availableOnPlatformNames)),
|
||||
]),
|
||||
t.img({className: "clientIcon", src: vm.iconUrl})
|
||||
]),
|
||||
t.p({className: "platforms"}, formatPlatforms(vm.availableOnPlatformNames)),
|
||||
]),
|
||||
t.img({className: "clientIcon", src: vm.iconUrl})
|
||||
]),
|
||||
t.mapView(vm => vm.stage, stage => {
|
||||
switch (stage) {
|
||||
case "open": return new OpenClientView(vm);
|
||||
case "install": return new InstallClientView(vm);
|
||||
}
|
||||
}),
|
||||
]);
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
class OpenClientView extends TemplateView {
|
||||
render(t, vm) {
|
||||
return t.div({className: "OpenClientView"}, [
|
||||
...vm.openActions.map(a => renderAction(t, a)),
|
||||
render(t, vm) {
|
||||
return t.div({className: "OpenClientView"}, [
|
||||
...vm.openActions.map(a => renderAction(t, a)),
|
||||
showBack(t, vm),
|
||||
]);
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
class InstallClientView extends TemplateView {
|
||||
render(t, vm) {
|
||||
const children = [];
|
||||
render(t, vm) {
|
||||
const children = [];
|
||||
|
||||
const textInstructions = vm.textInstructions;
|
||||
if (textInstructions) {
|
||||
if (textInstructions) {
|
||||
const copyButton = t.button({
|
||||
className: "copy",
|
||||
title: "Copy instructions",
|
||||
@@ -91,25 +91,25 @@ class InstallClientView extends TemplateView {
|
||||
}
|
||||
}
|
||||
});
|
||||
children.push(t.p({className: "instructions"}, renderInstructions(textInstructions).concat(copyButton)));
|
||||
}
|
||||
children.push(t.p({className: "instructions"}, renderInstructions(textInstructions).concat(copyButton)));
|
||||
}
|
||||
|
||||
const actions = t.div({className: "actions"}, vm.installActions.map(a => renderAction(t, a)));
|
||||
children.push(actions);
|
||||
const actions = t.div({className: "actions"}, vm.installActions.map(a => renderAction(t, a)));
|
||||
children.push(actions);
|
||||
|
||||
if (vm.showDeepLinkInInstall) {
|
||||
const openItHere = t.a({
|
||||
rel: "noopener noreferrer",
|
||||
href: vm.openActions[0].url,
|
||||
onClick: () => vm.openActions[0].activated(),
|
||||
}, "open it here");
|
||||
children.push(t.p([`If you already have ${vm.name} installed, you can `, openItHere, "."]))
|
||||
}
|
||||
if (vm.showDeepLinkInInstall) {
|
||||
const openItHere = t.a({
|
||||
rel: "noopener noreferrer",
|
||||
href: vm.openActions[0].url,
|
||||
onClick: () => vm.openActions[0].activated(),
|
||||
}, "open it here");
|
||||
children.push(t.p([`If you already have ${vm.name} installed, you can `, openItHere, "."]))
|
||||
}
|
||||
|
||||
children.push(showBack(t, vm));
|
||||
|
||||
return t.div({className: "InstallClientView"}, children);
|
||||
}
|
||||
return t.div({className: "InstallClientView"}, children);
|
||||
}
|
||||
}
|
||||
|
||||
function showBack(t, vm) {
|
||||
|
||||
+77
-77
@@ -27,28 +27,28 @@ function getMatchingPlatforms(client, supportedPlatforms) {
|
||||
}
|
||||
|
||||
export class ClientViewModel extends ViewModel {
|
||||
constructor(options) {
|
||||
super(options);
|
||||
const {client, link, pickClient} = options;
|
||||
this._client = client;
|
||||
this._link = link;
|
||||
this._pickClient = pickClient;
|
||||
constructor(options) {
|
||||
super(options);
|
||||
const {client, link, pickClient} = options;
|
||||
this._client = client;
|
||||
this._link = link;
|
||||
this._pickClient = pickClient;
|
||||
// to provide "choose other client" button after calling pick()
|
||||
this._clientListViewModel = null;
|
||||
this._update();
|
||||
}
|
||||
}
|
||||
|
||||
_update() {
|
||||
const matchingPlatforms = getMatchingPlatforms(this._client, this.platforms);
|
||||
this._webPlatform = matchingPlatforms.find(p => isWebPlatform(p));
|
||||
this._nativePlatform = matchingPlatforms.find(p => !isWebPlatform(p));
|
||||
const matchingPlatforms = getMatchingPlatforms(this._client, this.platforms);
|
||||
this._webPlatform = matchingPlatforms.find(p => isWebPlatform(p));
|
||||
this._nativePlatform = matchingPlatforms.find(p => !isWebPlatform(p));
|
||||
const preferredPlatform = matchingPlatforms.find(p => p === this.preferences.platform);
|
||||
this._proposedPlatform = preferredPlatform || this._nativePlatform || this._webPlatform;
|
||||
this._proposedPlatform = preferredPlatform || this._nativePlatform || this._webPlatform;
|
||||
|
||||
this.openActions = this._createOpenActions();
|
||||
this.installActions = this._createInstallActions();
|
||||
this._clientCanIntercept = !!(this._nativePlatform && this._client.canInterceptMatrixToLinks(this._nativePlatform));
|
||||
this._showOpen = this.openActions.length && !this._clientCanIntercept;
|
||||
this.installActions = this._createInstallActions();
|
||||
this._clientCanIntercept = !!(this._nativePlatform && this._client.canInterceptMatrixToLinks(this._nativePlatform));
|
||||
this._showOpen = this.openActions.length && !this._clientCanIntercept;
|
||||
}
|
||||
|
||||
// these are only shown in the open stage
|
||||
@@ -93,40 +93,40 @@ export class ClientViewModel extends ViewModel {
|
||||
}
|
||||
|
||||
// these are only shown in the install stage
|
||||
_createInstallActions() {
|
||||
let actions = [];
|
||||
if (this._nativePlatform) {
|
||||
const nativeActions = (this._client.getInstallLinks(this._nativePlatform) || []).map(installLink => {
|
||||
return {
|
||||
label: installLink.getDescription(this._nativePlatform),
|
||||
url: installLink.createInstallURL(this._link),
|
||||
kind: installLink.channelId,
|
||||
primary: true,
|
||||
activated: () => this.preferences.setClient(this._client.id, this._nativePlatform),
|
||||
};
|
||||
});
|
||||
actions.push(...nativeActions);
|
||||
}
|
||||
if (this._webPlatform) {
|
||||
const webDeepLink = this._client.getDeepLink(this._webPlatform, this._link);
|
||||
if (webDeepLink) {
|
||||
_createInstallActions() {
|
||||
let actions = [];
|
||||
if (this._nativePlatform) {
|
||||
const nativeActions = (this._client.getInstallLinks(this._nativePlatform) || []).map(installLink => {
|
||||
return {
|
||||
label: installLink.getDescription(this._nativePlatform),
|
||||
url: installLink.createInstallURL(this._link),
|
||||
kind: installLink.channelId,
|
||||
primary: true,
|
||||
activated: () => this.preferences.setClient(this._client.id, this._nativePlatform),
|
||||
};
|
||||
});
|
||||
actions.push(...nativeActions);
|
||||
}
|
||||
if (this._webPlatform) {
|
||||
const webDeepLink = this._client.getDeepLink(this._webPlatform, this._link);
|
||||
if (webDeepLink) {
|
||||
const webLabel = this.hasPreferredWebInstance ?
|
||||
`Open on ${this._client.getPreferredWebInstance(this._link)}` :
|
||||
`Continue in your browser`;
|
||||
actions.push({
|
||||
label: webLabel,
|
||||
url: webDeepLink,
|
||||
kind: "open-in-web",
|
||||
activated: () => {
|
||||
actions.push({
|
||||
label: webLabel,
|
||||
url: webDeepLink,
|
||||
kind: "open-in-web",
|
||||
activated: () => {
|
||||
if (!this.hasPreferredWebInstance) {
|
||||
this.preferences.setClient(this._client.id, this._webPlatform);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
|
||||
get hasPreferredWebInstance() {
|
||||
// also check there is a web platform that matches the platforms the user is on (mobile or desktop web)
|
||||
@@ -150,17 +150,17 @@ export class ClientViewModel extends ViewModel {
|
||||
return this._client.homepage;
|
||||
}
|
||||
|
||||
get identifier() {
|
||||
return this._link.identifier;
|
||||
}
|
||||
get identifier() {
|
||||
return this._link.identifier;
|
||||
}
|
||||
|
||||
get description() {
|
||||
return this._client.description;
|
||||
}
|
||||
get description() {
|
||||
return this._client.description;
|
||||
}
|
||||
|
||||
get clientId() {
|
||||
return this._client.id;
|
||||
}
|
||||
get clientId() {
|
||||
return this._client.id;
|
||||
}
|
||||
|
||||
get name() {
|
||||
return this._client.name;
|
||||
@@ -174,44 +174,44 @@ export class ClientViewModel extends ViewModel {
|
||||
return this._showOpen ? "open" : "install";
|
||||
}
|
||||
|
||||
get textInstructions() {
|
||||
get textInstructions() {
|
||||
let instructions = this._client.getLinkInstructions(this._proposedPlatform, this._link);
|
||||
if (instructions && !Array.isArray(instructions)) {
|
||||
instructions = [instructions];
|
||||
}
|
||||
return instructions;
|
||||
}
|
||||
return instructions;
|
||||
}
|
||||
|
||||
get copyString() {
|
||||
return this._client.getCopyString(this._proposedPlatform, this._link);
|
||||
}
|
||||
|
||||
get showDeepLinkInInstall() {
|
||||
get showDeepLinkInInstall() {
|
||||
// we can assume this._nativePlatform as this._clientCanIntercept already checks it
|
||||
return this._clientCanIntercept && !!this._client.getDeepLink(this._nativePlatform, this._link);
|
||||
}
|
||||
return this._clientCanIntercept && !!this._client.getDeepLink(this._nativePlatform, this._link);
|
||||
}
|
||||
|
||||
get availableOnPlatformNames() {
|
||||
const platforms = this._client.platforms;
|
||||
const textPlatforms = [];
|
||||
const hasWebPlatform = platforms.some(p => isWebPlatform(p));
|
||||
if (hasWebPlatform) {
|
||||
textPlatforms.push("Web");
|
||||
}
|
||||
const desktopPlatforms = platforms.filter(p => isDesktopPlatform(p));
|
||||
if (desktopPlatforms.length === 1) {
|
||||
textPlatforms.push(desktopPlatforms[0]);
|
||||
} else {
|
||||
textPlatforms.push("Desktop");
|
||||
}
|
||||
if (platforms.includes(Platform.Android)) {
|
||||
textPlatforms.push("Android");
|
||||
}
|
||||
if (platforms.includes(Platform.iOS)) {
|
||||
textPlatforms.push("iOS");
|
||||
}
|
||||
return textPlatforms;
|
||||
}
|
||||
get availableOnPlatformNames() {
|
||||
const platforms = this._client.platforms;
|
||||
const textPlatforms = [];
|
||||
const hasWebPlatform = platforms.some(p => isWebPlatform(p));
|
||||
if (hasWebPlatform) {
|
||||
textPlatforms.push("Web");
|
||||
}
|
||||
const desktopPlatforms = platforms.filter(p => isDesktopPlatform(p));
|
||||
if (desktopPlatforms.length === 1) {
|
||||
textPlatforms.push(desktopPlatforms[0]);
|
||||
} else {
|
||||
textPlatforms.push("Desktop");
|
||||
}
|
||||
if (platforms.includes(Platform.Android)) {
|
||||
textPlatforms.push("Android");
|
||||
}
|
||||
if (platforms.includes(Platform.iOS)) {
|
||||
textPlatforms.push("iOS");
|
||||
}
|
||||
return textPlatforms;
|
||||
}
|
||||
|
||||
pick(clientListViewModel) {
|
||||
this._clientListViewModel = clientListViewModel;
|
||||
|
||||
@@ -20,14 +20,14 @@ import {PreviewView} from "../preview/PreviewView.js";
|
||||
import {ServerConsentView} from "./ServerConsentView.js";
|
||||
|
||||
export class OpenLinkView extends TemplateView {
|
||||
render(t, vm) {
|
||||
return t.div({className: "OpenLinkView card"}, [
|
||||
t.mapView(vm => vm.previewViewModel, previewVM => previewVM ?
|
||||
render(t, vm) {
|
||||
return t.div({className: "OpenLinkView card"}, [
|
||||
t.mapView(vm => vm.previewViewModel, previewVM => previewVM ?
|
||||
new ShowLinkView(vm) :
|
||||
new ServerConsentView(vm.serverConsentViewModel)
|
||||
),
|
||||
]);
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
class ShowLinkView extends TemplateView {
|
||||
|
||||
@@ -23,21 +23,21 @@ import {getLabelForLinkKind} from "../Link.js";
|
||||
import {orderedUnique} from "../utils/unique.js";
|
||||
|
||||
export class OpenLinkViewModel extends ViewModel {
|
||||
constructor(options) {
|
||||
super(options);
|
||||
const {clients, link} = options;
|
||||
this._link = link;
|
||||
this._clients = clients;
|
||||
constructor(options) {
|
||||
super(options);
|
||||
const {clients, link} = options;
|
||||
this._link = link;
|
||||
this._clients = clients;
|
||||
this.serverConsentViewModel = null;
|
||||
this.previewViewModel = null;
|
||||
this.previewViewModel = null;
|
||||
this.clientsViewModel = null;
|
||||
this.previewLoading = false;
|
||||
this.previewLoading = false;
|
||||
if (this.preferences.homeservers === null) {
|
||||
this._showServerConsent();
|
||||
} else {
|
||||
this._showLink();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_showServerConsent() {
|
||||
let servers = [];
|
||||
@@ -67,24 +67,24 @@ export class OpenLinkViewModel extends ViewModel {
|
||||
link: this._link,
|
||||
consentedServers: this.preferences.homeservers
|
||||
}));
|
||||
this.previewLoading = true;
|
||||
this.emitChange();
|
||||
await this.previewViewModel.load();
|
||||
this.previewLoading = false;
|
||||
this.emitChange();
|
||||
this.previewLoading = true;
|
||||
this.emitChange();
|
||||
await this.previewViewModel.load();
|
||||
this.previewLoading = false;
|
||||
this.emitChange();
|
||||
}
|
||||
|
||||
get previewDomain() {
|
||||
return this.previewViewModel?.domain;
|
||||
}
|
||||
get previewDomain() {
|
||||
return this.previewViewModel?.domain;
|
||||
}
|
||||
|
||||
get previewFailed() {
|
||||
return this.previewViewModel?.failed;
|
||||
}
|
||||
|
||||
get showClientsLabel() {
|
||||
return getLabelForLinkKind(this._link.kind);
|
||||
}
|
||||
get showClientsLabel() {
|
||||
return getLabelForLinkKind(this._link.kind);
|
||||
}
|
||||
|
||||
changeServer() {
|
||||
this.previewViewModel = null;
|
||||
|
||||
@@ -27,7 +27,7 @@ export class ServerConsentView extends TemplateView {
|
||||
className: "text",
|
||||
onClick: () => vm.continueWithoutConsent(this._askEveryTimeChecked)
|
||||
}, "continue without a preview");
|
||||
return t.div({className: "ServerConsentView"}, [
|
||||
return t.div({className: "ServerConsentView"}, [
|
||||
t.p([
|
||||
"Preview this link using the ",
|
||||
t.strong(vm => vm.selectedServer || "…"),
|
||||
@@ -56,7 +56,7 @@ export class ServerConsentView extends TemplateView {
|
||||
])
|
||||
])
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
_onSubmit(evt) {
|
||||
evt.preventDefault();
|
||||
|
||||
@@ -22,13 +22,13 @@ import {getLabelForLinkKind} from "../Link.js";
|
||||
import {orderedUnique} from "../utils/unique.js";
|
||||
|
||||
export class ServerConsentViewModel extends ViewModel {
|
||||
constructor(options) {
|
||||
super(options);
|
||||
constructor(options) {
|
||||
super(options);
|
||||
this.servers = options.servers;
|
||||
this.done = options.done;
|
||||
this.selectedServer = this.servers[0];
|
||||
this.showSelectServer = false;
|
||||
}
|
||||
}
|
||||
|
||||
setShowServers() {
|
||||
this.showSelectServer = true;
|
||||
|
||||
+47
-47
@@ -15,7 +15,7 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
import {Maturity, Platform, LinkKind,
|
||||
FDroidLink, AppleStoreLink, PlayStoreLink, WebsiteLink} from "../types.js";
|
||||
FDroidLink, AppleStoreLink, PlayStoreLink, WebsiteLink} from "../types.js";
|
||||
|
||||
const trustedWebInstances = [
|
||||
"app.element.io", // first one is the default one
|
||||
@@ -29,69 +29,69 @@ const trustedWebInstances = [
|
||||
* Information on how to deep link to a given matrix client.
|
||||
*/
|
||||
export class Element {
|
||||
get id() { return "element.io"; }
|
||||
get id() { return "element.io"; }
|
||||
|
||||
get platforms() {
|
||||
return [
|
||||
Platform.Android, Platform.iOS,
|
||||
Platform.Windows, Platform.macOS, Platform.Linux,
|
||||
Platform.DesktopWeb
|
||||
];
|
||||
}
|
||||
get platforms() {
|
||||
return [
|
||||
Platform.Android, Platform.iOS,
|
||||
Platform.Windows, Platform.macOS, Platform.Linux,
|
||||
Platform.DesktopWeb
|
||||
];
|
||||
}
|
||||
|
||||
get icon() { return "images/client-icons/element.svg"; }
|
||||
get appleAssociatedAppId() { return "7J4U792NQT.im.vector.app"; }
|
||||
get name() {return "Element"; }
|
||||
get description() { return 'Fully-featured Matrix client, used by millions.'; }
|
||||
get homepage() { return "https://element.io"; }
|
||||
get author() { return "Element"; }
|
||||
getMaturity(platform) { return Maturity.Stable; }
|
||||
get name() {return "Element"; }
|
||||
get description() { return 'Fully-featured Matrix client, used by millions.'; }
|
||||
get homepage() { return "https://element.io"; }
|
||||
get author() { return "Element"; }
|
||||
getMaturity(platform) { return Maturity.Stable; }
|
||||
|
||||
getDeepLink(platform, link) {
|
||||
let fragmentPath;
|
||||
switch (link.kind) {
|
||||
case LinkKind.User:
|
||||
fragmentPath = `user/${link.identifier}`;
|
||||
break;
|
||||
case LinkKind.Room:
|
||||
fragmentPath = `room/${link.identifier}`;
|
||||
break;
|
||||
case LinkKind.Group:
|
||||
fragmentPath = `group/${link.identifier}`;
|
||||
break;
|
||||
case LinkKind.Event:
|
||||
fragmentPath = `room/${link.identifier}/${link.eventId}`;
|
||||
break;
|
||||
}
|
||||
getDeepLink(platform, link) {
|
||||
let fragmentPath;
|
||||
switch (link.kind) {
|
||||
case LinkKind.User:
|
||||
fragmentPath = `user/${link.identifier}`;
|
||||
break;
|
||||
case LinkKind.Room:
|
||||
fragmentPath = `room/${link.identifier}`;
|
||||
break;
|
||||
case LinkKind.Group:
|
||||
fragmentPath = `group/${link.identifier}`;
|
||||
break;
|
||||
case LinkKind.Event:
|
||||
fragmentPath = `room/${link.identifier}/${link.eventId}`;
|
||||
break;
|
||||
}
|
||||
const isWebPlatform = platform === Platform.DesktopWeb || platform === Platform.MobileWeb;
|
||||
if (isWebPlatform || platform === Platform.iOS) {
|
||||
if (isWebPlatform || platform === Platform.iOS) {
|
||||
let instanceHost = trustedWebInstances[0];
|
||||
// we use app.element.io which iOS will intercept, but it likely won't intercept any other trusted instances
|
||||
// so only use a preferred web instance for true web links.
|
||||
if (isWebPlatform && trustedWebInstances.includes(link.webInstances[this.id])) {
|
||||
instanceHost = link.webInstances[this.id];
|
||||
}
|
||||
return `https://${instanceHost}/#/${fragmentPath}`;
|
||||
} else if (platform === Platform.Linux || platform === Platform.Windows || platform === Platform.macOS) {
|
||||
return `element://vector/webapp/#/${fragmentPath}`;
|
||||
} else {
|
||||
return `https://${instanceHost}/#/${fragmentPath}`;
|
||||
} else if (platform === Platform.Linux || platform === Platform.Windows || platform === Platform.macOS) {
|
||||
return `element://vector/webapp/#/${fragmentPath}`;
|
||||
} else {
|
||||
return `element://${fragmentPath}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getLinkInstructions(platform, link) {}
|
||||
getLinkInstructions(platform, link) {}
|
||||
getCopyString(platform, link) {}
|
||||
getInstallLinks(platform) {
|
||||
switch (platform) {
|
||||
case Platform.iOS: return [new AppleStoreLink('vector', 'id1083446067')];
|
||||
case Platform.Android: return [new PlayStoreLink('im.vector.app'), new FDroidLink('im.vector.app')];
|
||||
default: return [new WebsiteLink("https://element.io/get-started")];
|
||||
}
|
||||
}
|
||||
getInstallLinks(platform) {
|
||||
switch (platform) {
|
||||
case Platform.iOS: return [new AppleStoreLink('vector', 'id1083446067')];
|
||||
case Platform.Android: return [new PlayStoreLink('im.vector.app'), new FDroidLink('im.vector.app')];
|
||||
default: return [new WebsiteLink("https://element.io/get-started")];
|
||||
}
|
||||
}
|
||||
|
||||
canInterceptMatrixToLinks(platform) {
|
||||
return platform === Platform.Android;
|
||||
}
|
||||
canInterceptMatrixToLinks(platform) {
|
||||
return platform === Platform.Android;
|
||||
}
|
||||
|
||||
getPreferredWebInstance(link) {
|
||||
const idx = trustedWebInstances.indexOf(link.webInstances[this.id])
|
||||
|
||||
+10
-10
@@ -20,22 +20,22 @@ import {Maturity, Platform, LinkKind, FlathubLink} from "../types.js";
|
||||
* Information on how to deep link to a given matrix client.
|
||||
*/
|
||||
export class Fractal {
|
||||
get id() { return "fractal"; }
|
||||
get name() { return "Fractal"; }
|
||||
get id() { return "fractal"; }
|
||||
get name() { return "Fractal"; }
|
||||
get icon() { return "images/client-icons/fractal.png"; }
|
||||
get author() { return "Daniel Garcia Moreno"; }
|
||||
get homepage() { return "https://gitlab.gnome.org/GNOME/fractal"; }
|
||||
get platforms() { return [Platform.Linux]; }
|
||||
get description() { return 'Fractal is a Matrix Client written in Rust.'; }
|
||||
getMaturity(platform) { return Maturity.Beta; }
|
||||
getDeepLink(platform, link) {}
|
||||
canInterceptMatrixToLinks(platform) { return false; }
|
||||
get platforms() { return [Platform.Linux]; }
|
||||
get description() { return 'Fractal is a Matrix Client written in Rust.'; }
|
||||
getMaturity(platform) { return Maturity.Beta; }
|
||||
getDeepLink(platform, link) {}
|
||||
canInterceptMatrixToLinks(platform) { return false; }
|
||||
|
||||
getLinkInstructions(platform, link) {
|
||||
getLinkInstructions(platform, link) {
|
||||
if (link.kind === LinkKind.User || link.kind === LinkKind.Room) {
|
||||
return "Click the '+' button in the top right and paste the identifier";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getCopyString(platform, link) {
|
||||
if (link.kind === LinkKind.User || link.kind === LinkKind.Room) {
|
||||
@@ -43,7 +43,7 @@ export class Fractal {
|
||||
}
|
||||
}
|
||||
|
||||
getInstallLinks(platform) {
|
||||
getInstallLinks(platform) {
|
||||
if (platform === Platform.Linux) {
|
||||
return [new FlathubLink("org.gnome.Fractal")];
|
||||
}
|
||||
|
||||
+39
-39
@@ -20,49 +20,49 @@ import {Maturity, Platform, LinkKind, FlathubLink, style} from "../types.js";
|
||||
* Information on how to deep link to a given matrix client.
|
||||
*/
|
||||
export class Nheko {
|
||||
get id() { return "nheko"; }
|
||||
get name() { return "Nheko"; }
|
||||
get id() { return "nheko"; }
|
||||
get name() { return "Nheko"; }
|
||||
get icon() { return "images/client-icons/nheko.svg"; }
|
||||
get author() { return "mujx, red_sky, deepbluev7, Konstantinos Sideris"; }
|
||||
get homepage() { return "https://github.com/Nheko-Reborn/nheko"; }
|
||||
get platforms() { return [Platform.Windows, Platform.macOS, Platform.Linux]; }
|
||||
get description() { return 'A native desktop app for Matrix that feels more like a mainstream chat app.'; }
|
||||
getMaturity(platform) { return Maturity.Beta; }
|
||||
getDeepLink(platform, link) {
|
||||
if (platform === Platform.Linux || platform === Platform.Windows) {
|
||||
let identifier = encodeURIComponent(link.identifier.substring(1));
|
||||
let isRoomid = link.identifier.substring(0, 1) === '!';
|
||||
let fragmentPath;
|
||||
switch (link.kind) {
|
||||
case LinkKind.User:
|
||||
fragmentPath = `u/${identifier}?action=chat`;
|
||||
break;
|
||||
case LinkKind.Room:
|
||||
case LinkKind.Event:
|
||||
if (isRoomid)
|
||||
fragmentPath = `roomid/${identifier}`;
|
||||
else
|
||||
fragmentPath = `r/${identifier}`;
|
||||
get platforms() { return [Platform.Windows, Platform.macOS, Platform.Linux]; }
|
||||
get description() { return 'A native desktop app for Matrix that feels more like a mainstream chat app.'; }
|
||||
getMaturity(platform) { return Maturity.Beta; }
|
||||
getDeepLink(platform, link) {
|
||||
if (platform === Platform.Linux || platform === Platform.Windows) {
|
||||
let identifier = encodeURIComponent(link.identifier.substring(1));
|
||||
let isRoomid = link.identifier.substring(0, 1) === '!';
|
||||
let fragmentPath;
|
||||
switch (link.kind) {
|
||||
case LinkKind.User:
|
||||
fragmentPath = `u/${identifier}?action=chat`;
|
||||
break;
|
||||
case LinkKind.Room:
|
||||
case LinkKind.Event:
|
||||
if (isRoomid)
|
||||
fragmentPath = `roomid/${identifier}`;
|
||||
else
|
||||
fragmentPath = `r/${identifier}`;
|
||||
|
||||
if (link.kind === LinkKind.Event)
|
||||
fragmentPath += `/e/${encodeURIComponent(link.eventId.substring(1))}`;
|
||||
fragmentPath += '?action=join';
|
||||
fragmentPath += link.servers.map(server => `&via=${encodeURIComponent(server)}`).join('');
|
||||
break;
|
||||
case LinkKind.Group:
|
||||
return;
|
||||
}
|
||||
return `matrix:${fragmentPath}`;
|
||||
}
|
||||
}
|
||||
canInterceptMatrixToLinks(platform) { return false; }
|
||||
if (link.kind === LinkKind.Event)
|
||||
fragmentPath += `/e/${encodeURIComponent(link.eventId.substring(1))}`;
|
||||
fragmentPath += '?action=join';
|
||||
fragmentPath += link.servers.map(server => `&via=${encodeURIComponent(server)}`).join('');
|
||||
break;
|
||||
case LinkKind.Group:
|
||||
return;
|
||||
}
|
||||
return `matrix:${fragmentPath}`;
|
||||
}
|
||||
}
|
||||
canInterceptMatrixToLinks(platform) { return false; }
|
||||
|
||||
getLinkInstructions(platform, link) {
|
||||
switch (link.kind) {
|
||||
case LinkKind.User: return [`Type `, style.code(`/invite ${link.identifier}`)];
|
||||
case LinkKind.Room: return [`Type `, style.code(`/join ${link.identifier}`)];
|
||||
}
|
||||
}
|
||||
getLinkInstructions(platform, link) {
|
||||
switch (link.kind) {
|
||||
case LinkKind.User: return [`Type `, style.code(`/invite ${link.identifier}`)];
|
||||
case LinkKind.Room: return [`Type `, style.code(`/join ${link.identifier}`)];
|
||||
}
|
||||
}
|
||||
|
||||
getCopyString(platform, link) {
|
||||
switch (link.kind) {
|
||||
@@ -71,7 +71,7 @@ export class Nheko {
|
||||
}
|
||||
}
|
||||
|
||||
getInstallLinks(platform) {
|
||||
getInstallLinks(platform) {
|
||||
if (platform === Platform.Linux) {
|
||||
return [new FlathubLink("io.github.NhekoReborn.Nheko")];
|
||||
}
|
||||
|
||||
+14
-14
@@ -20,23 +20,23 @@ import {Maturity, Platform, LinkKind, WebsiteLink, style} from "../types.js";
|
||||
* Information on how to deep link to a given matrix client.
|
||||
*/
|
||||
export class Weechat {
|
||||
get id() { return "weechat"; }
|
||||
get name() { return "Weechat"; }
|
||||
get id() { return "weechat"; }
|
||||
get name() { return "Weechat"; }
|
||||
get icon() { return "images/client-icons/weechat.svg"; }
|
||||
get author() { return "Poljar"; }
|
||||
get homepage() { return "https://github.com/poljar/weechat-matrix"; }
|
||||
get platforms() { return [Platform.Windows, Platform.macOS, Platform.Linux]; }
|
||||
get description() { return 'Command-line Matrix interface using Weechat.'; }
|
||||
getMaturity(platform) { return Maturity.Beta; }
|
||||
getDeepLink(platform, link) {}
|
||||
canInterceptMatrixToLinks(platform) { return false; }
|
||||
get platforms() { return [Platform.Windows, Platform.macOS, Platform.Linux]; }
|
||||
get description() { return 'Command-line Matrix interface using Weechat.'; }
|
||||
getMaturity(platform) { return Maturity.Beta; }
|
||||
getDeepLink(platform, link) {}
|
||||
canInterceptMatrixToLinks(platform) { return false; }
|
||||
|
||||
getLinkInstructions(platform, link) {
|
||||
switch (link.kind) {
|
||||
case LinkKind.User: return [`Type `, style.code(`/invite ${link.identifier}`)];
|
||||
case LinkKind.Room: return [`Type `, style.code(`/join ${link.identifier}`)];
|
||||
}
|
||||
}
|
||||
getLinkInstructions(platform, link) {
|
||||
switch (link.kind) {
|
||||
case LinkKind.User: return [`Type `, style.code(`/invite ${link.identifier}`)];
|
||||
case LinkKind.Room: return [`Type `, style.code(`/join ${link.identifier}`)];
|
||||
}
|
||||
}
|
||||
|
||||
getCopyString(platform, link) {
|
||||
switch (link.kind) {
|
||||
@@ -45,7 +45,7 @@ export class Weechat {
|
||||
}
|
||||
}
|
||||
|
||||
getInstallLinks(platform) {}
|
||||
getInstallLinks(platform) {}
|
||||
|
||||
getPreferredWebInstance(link) {}
|
||||
}
|
||||
|
||||
@@ -23,13 +23,13 @@ import {Tensor} from "./Tensor.js";
|
||||
import {Fluffychat} from "./Fluffychat.js";
|
||||
|
||||
export function createClients() {
|
||||
return [
|
||||
new Element(),
|
||||
new Weechat(),
|
||||
new Nheko(),
|
||||
new Fractal(),
|
||||
new Quaternion(),
|
||||
new Tensor(),
|
||||
new Fluffychat(),
|
||||
];
|
||||
return [
|
||||
new Element(),
|
||||
new Weechat(),
|
||||
new Nheko(),
|
||||
new Fractal(),
|
||||
new Quaternion(),
|
||||
new Tensor(),
|
||||
new Fluffychat(),
|
||||
];
|
||||
}
|
||||
|
||||
+5
-5
@@ -21,8 +21,8 @@ export {Platform} from "../Platform.js";
|
||||
|
||||
export class AppleStoreLink {
|
||||
constructor(org, appId) {
|
||||
this._org = org;
|
||||
this._appId = appId;
|
||||
this._org = org;
|
||||
this._appId = appId;
|
||||
}
|
||||
|
||||
createInstallURL(link) {
|
||||
@@ -40,7 +40,7 @@ export class AppleStoreLink {
|
||||
|
||||
export class PlayStoreLink {
|
||||
constructor(appId) {
|
||||
this._appId = appId;
|
||||
this._appId = appId;
|
||||
}
|
||||
|
||||
createInstallURL(link) {
|
||||
@@ -58,7 +58,7 @@ export class PlayStoreLink {
|
||||
|
||||
export class FDroidLink {
|
||||
constructor(appId) {
|
||||
this._appId = appId;
|
||||
this._appId = appId;
|
||||
}
|
||||
|
||||
createInstallURL(link) {
|
||||
@@ -94,7 +94,7 @@ export class FlathubLink {
|
||||
|
||||
export class WebsiteLink {
|
||||
constructor(url) {
|
||||
this._url = url;
|
||||
this._url = url;
|
||||
}
|
||||
|
||||
createInstallURL(link) {
|
||||
|
||||
Reference in New Issue
Block a user