diff --git a/src/server_manager/ui_components/app-root.html b/src/server_manager/ui_components/app-root.html
index eff677a96..57a72902e 100644
--- a/src/server_manager/ui_components/app-root.html
+++ b/src/server_manager/ui_components/app-root.html
@@ -514,7 +514,7 @@
[[localize('digitalocean-disconnect-account')]]
@@ -812,30 +812,6 @@ [[localize('digitalocean-disconnect-account')]]
this.$.shareDialog.open(accessKey, s3Url);
}
- openGetConnectedDialog(inviteUrl) {
- const dialog = this.$.getConnectedDialog;
- if (dialog.children.length > 1) {
- return; // The iframe is already loading.
- }
- // Reset the iframe's state, by replacing it with a newly constructed
- // iframe. Unfortunately the location.reload API does not work in our case due to
- // this Chrome error:
- // "Blocked a frame with origin "outline://web_app" from accessing a cross-origin frame."
- const iframe = document.createElement("iframe");
- iframe.onload = function() {
- dialog.open();
- };
- iframe.src = inviteUrl;
- dialog.insertBefore(iframe, dialog.children[0]);
- }
-
- closeGetConnectedDialog() {
- const dialog = this.$.getConnectedDialog;
- dialog.close();
- const oldIframe = dialog.children[0];
- dialog.removeChild(oldIframe);
- }
-
showMetricsDialogForNewServer() {
this.$.metricsDialog.showMetricsOptInDialog();
}
diff --git a/src/server_manager/ui_components/outline-share-dialog.html b/src/server_manager/ui_components/outline-share-dialog.html
index abcb9e885..2bd75c1d8 100644
--- a/src/server_manager/ui_components/outline-share-dialog.html
+++ b/src/server_manager/ui_components/outline-share-dialog.html
@@ -120,7 +120,7 @@ [[localize('share-title')]]
[[localize('share-invite-copied')]]
@@ -129,27 +129,16 @@ [[localize('share-title')]]
diff --git a/src/server_manager/web_app/app.spec.ts b/src/server_manager/web_app/app.spec.ts
index 7916f43c3..f606d18c6 100644
--- a/src/server_manager/web_app/app.spec.ts
+++ b/src/server_manager/web_app/app.spec.ts
@@ -257,13 +257,29 @@ enum AppRootScreen {
DIALOG
}
+class FakeElement {
+ addEventListener(event: string, handler: Function) {}
+ querySelector(query: string) {
+ return new FakeElement();
+ }
+}
+
+class FakeShareDialogElement implements polymer.Base {
+ is = 'fake-share-dialog';
+ $ = {copyButton: new FakeElement()};
+}
+
class FakePolymerAppRoot implements polymer.Base {
events = new events.EventEmitter();
backgroundScreen = AppRootScreen.NONE;
currentScreen = AppRootScreen.NONE;
serverView = {setServerTransferredData: () => {}, serverId: '', initHelpBubbles: () => {}};
serverList: DisplayServer[] = [];
- is: 'fake-polymer-app-root';
+ is = 'fake-polymer-app-root';
+ $ = {
+ shareDialog: new FakeShareDialogElement(),
+ getConnectedDialog: new FakeElement(),
+ };
private setScreen(screenId: AppRootScreen) {
this.currentScreen = screenId;
diff --git a/src/server_manager/web_app/app.ts b/src/server_manager/web_app/app.ts
index 06dc6ff85..d6e10634f 100644
--- a/src/server_manager/web_app/app.ts
+++ b/src/server_manager/web_app/app.ts
@@ -25,7 +25,9 @@ import {Surveys} from '../model/survey';
import {TokenManager} from './digitalocean_oauth';
import * as digitalocean_server from './digitalocean_server';
import {DisplayServer, DisplayServerRepository, makeDisplayServer} from './display_server';
+import {GetConnectedApp} from './get_connected_app';
import {parseManualServerConfig} from './management_urls';
+import {ShareDialogApp} from './share_dialog_app';
// The Outline DigitalOcean team's referral code:
// https://www.digitalocean.com/help/referral-program/
@@ -145,6 +147,9 @@ export class App {
private digitalOceanTokenManager: TokenManager, private surveys: Surveys) {
appRoot.setAttribute('outline-version', this.version);
+ const shareApp = new ShareDialogApp(appRoot.$.shareDialog);
+ const getConnectedApp = new GetConnectedApp(appRoot.$.getConnectedDialog);
+
appRoot.addEventListener('ConnectToDigitalOcean', (event: CustomEvent) => {
this.connectToDigitalOcean();
});
@@ -271,12 +276,11 @@ export class App {
});
appRoot.addEventListener('OpenShareDialogRequested', (event: CustomEvent) => {
- const accessKey = event.detail.accessKey;
- this.appRoot.openShareDialog(accessKey, this.getS3InviteUrl(accessKey));
+ shareApp.start(event.detail.accessKey, this.getS3InviteUrl(event.detail.accessKey));
});
appRoot.addEventListener('OpenGetConnectedDialogRequested', (event: CustomEvent) => {
- this.appRoot.openGetConnectedDialog(this.getS3InviteUrl(event.detail.accessKey, true));
+ getConnectedApp.start(this.getS3InviteUrl(event.detail.accessKey, true));
});
appRoot.addEventListener('ShowServerRequested', (event: CustomEvent) => {
diff --git a/src/server_manager/web_app/build_action.sh b/src/server_manager/web_app/build_action.sh
index d465b7221..ed16902bb 100755
--- a/src/server_manager/web_app/build_action.sh
+++ b/src/server_manager/web_app/build_action.sh
@@ -43,7 +43,7 @@ tsc
# Browserify node_modules/ (just a couple of key NPMs) and app.
pushd $OUT_DIR > /dev/null
mkdir -p browserified/server_manager/web_app
-$NODE_MODULES_BIN_DIR/browserify --require byte-size --require clipboard-polyfill -o browserified/node_modules.js
+$NODE_MODULES_BIN_DIR/browserify --require byte-size -o browserified/node_modules.js
$NODE_MODULES_BIN_DIR/browserify js/server_manager/web_app/main.js -s main -o browserified/server_manager/web_app/main.js
popd > /dev/null
diff --git a/src/server_manager/web_app/get_connected_app.ts b/src/server_manager/web_app/get_connected_app.ts
new file mode 100644
index 000000000..1d62d3238
--- /dev/null
+++ b/src/server_manager/web_app/get_connected_app.ts
@@ -0,0 +1,43 @@
+// Copyright 2020 The Outline Authors
+//
+// 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 class GetConnectedApp {
+ constructor(private dialog: polymer.Base) {
+ // Get connected is not a Polymer component, so we use `querySelector()` instead of `dialog.$`.
+ dialog.querySelector('#closeGetConnectedButton')
+ .addEventListener('tap', (event: CustomEvent) => {
+ dialog.close();
+ if (dialog.children.length > 1) {
+ const oldIframe = dialog.children[0];
+ dialog.removeChild(oldIframe);
+ }
+ });
+ }
+
+ start(inviteUrl: string) {
+ if (this.dialog.children.length > 1) {
+ return; // The iframe is already loading.
+ }
+ // Reset the iframe's state, by replacing it with a newly constructed
+ // iframe. Unfortunately the location.reload API does not work in our case due to
+ // this Chrome error:
+ // "Blocked a frame with origin "outline://web_app" from accessing a cross-origin frame."
+ const iframe = document.createElement('iframe');
+ iframe.onload = () => {
+ this.dialog.open();
+ };
+ iframe.src = inviteUrl;
+ this.dialog.insertBefore(iframe, this.dialog.children[0]);
+ }
+}
diff --git a/src/server_manager/web_app/share_dialog_app.ts b/src/server_manager/web_app/share_dialog_app.ts
new file mode 100644
index 000000000..91ea1e676
--- /dev/null
+++ b/src/server_manager/web_app/share_dialog_app.ts
@@ -0,0 +1,36 @@
+// Copyright 2020 The Outline Authors
+//
+// 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.
+
+import * as clipboard from 'clipboard-polyfill';
+
+export class ShareDialogApp {
+ constructor(private root: polymer.Base) {
+ this.root.$.copyButton.addEventListener('tap', (event: CustomEvent) => {
+ const dt = new clipboard.DT();
+ dt.setData('text/plain', this.root.$.selectableText.innerText);
+ dt.setData('text/html', this.root.$.selectableText.innerHTML);
+ clipboard.write(dt);
+ this.root.$.copyText.hidden = false;
+ });
+ }
+
+ start(accessKey: string, s3InviteUrl: string) {
+ this.root.acessKey = accessKey;
+ this.root.s3Url = s3InviteUrl;
+ // TODO(fortuna): Instead of passing a pre-made outline-share-dialog, we should create and
+ // insert it here instead. This way we don't need to reset state, which is cleaner.
+ this.root.$.copyText.setAttribute('hidden', true);
+ this.root.$.dialog.open();
+ }
+}