Merge commit 'be3e8236086165e5e45a5a10783823874b3f3ebd' as 'lib/vscode'
This commit is contained in:
79
lib/vscode/src/vs/code/browser/workbench/callback.html
Normal file
79
lib/vscode/src/vs/code/browser/workbench/callback.html
Normal file
@ -0,0 +1,79 @@
|
||||
<!-- Copyright (C) Microsoft Corporation. All rights reserved. -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<!-- Disable pinch zooming -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
|
||||
|
||||
<!-- Content Security Policy -->
|
||||
<meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
content="
|
||||
default-src 'self';
|
||||
img-src 'self' https: data: blob:;
|
||||
media-src 'none';
|
||||
script-src 'self';
|
||||
style-src 'self' 'unsafe-inline';
|
||||
font-src 'self' blob:;
|
||||
">
|
||||
|
||||
<title>Visual Studio Code</title>
|
||||
|
||||
<!-- Styling -->
|
||||
<style type="text/css">
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
box-sizing: border-box;
|
||||
min-height: 100%;
|
||||
margin: 0;
|
||||
padding: 15px 30px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: white;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", system-ui, "Ubuntu", "Droid Sans", sans-serif;
|
||||
background-color: #373277;
|
||||
}
|
||||
|
||||
.branding {
|
||||
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PGRlZnM+PHN0eWxlPi5pY29uLWNhbnZhcy10cmFuc3BhcmVudHtmaWxsOiNmNmY2ZjY7b3BhY2l0eTowO30uaWNvbi13aGl0ZXtmaWxsOiNmZmY7fTwvc3R5bGU+PC9kZWZzPjx0aXRsZT5CcmFuZFZpc3VhbFN0dWRpb0NvZGUyMDE3UlRXXzI0eF93aGl0ZV8yNHg8L3RpdGxlPjxwYXRoIGNsYXNzPSJpY29uLWNhbnZhcy10cmFuc3BhcmVudCIgZD0iTTI0LDBWMjRIMFYwWiIvPjxwYXRoIGNsYXNzPSJpY29uLXdoaXRlIiBkPSJNMjQsMi41VjIxLjVMMTgsMjQsMCwxOC41di0uNTYxbDE4LDEuNTQ1VjBaTTEsMTMuMTExLDQuMzg1LDEwLDEsNi44ODlsMS40MTgtLjgyN0w1Ljg1Myw4LjY1LDEyLDNsMywxLjQ1NlYxNS41NDRMMTIsMTcsNS44NTMsMTEuMzUsMi40MTksMTMuOTM5Wk03LjY0NCwxMCwxMiwxMy4yODNWNi43MTdaIi8+PC9zdmc+");
|
||||
background-size: 24px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: left 50%;
|
||||
padding-left: 36px;
|
||||
font-size: 20px;
|
||||
letter-spacing: -0.04rem;
|
||||
font-weight: 400;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.message-container {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0 30px;
|
||||
}
|
||||
|
||||
.message {
|
||||
font-weight: 300;
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<span class="branding">
|
||||
Visual Studio Code
|
||||
</span>
|
||||
<div class="message-container">
|
||||
<div class="message">
|
||||
You can close this page now.
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
57
lib/vscode/src/vs/code/browser/workbench/workbench-dev.html
Normal file
57
lib/vscode/src/vs/code/browser/workbench/workbench-dev.html
Normal file
@ -0,0 +1,57 @@
|
||||
<!-- Copyright (C) Microsoft Corporation. All rights reserved. -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
globalThis.MonacoPerformanceMarks = globalThis.MonacoPerformanceMarks || [];
|
||||
globalThis.MonacoPerformanceMarks.push('renderer/started', Date.now());
|
||||
</script>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<!-- Disable pinch zooming -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
|
||||
|
||||
<!-- Workbench Configuration -->
|
||||
<meta id="vscode-workbench-web-configuration" data-settings="{{WORKBENCH_WEB_CONFIGURATION}}">
|
||||
|
||||
<!-- Workbench Auth Session -->
|
||||
<meta id="vscode-workbench-auth-session" data-settings="{{WORKBENCH_AUTH_SESSION}}">
|
||||
|
||||
<!-- Builtin Extensions (running out of sources) -->
|
||||
<meta id="vscode-workbench-builtin-extensions" data-settings="{{WORKBENCH_BUILTIN_EXTENSIONS}}">
|
||||
|
||||
<!-- Workbench Icon/Manifest/CSS -->
|
||||
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
</head>
|
||||
|
||||
<body aria-label="">
|
||||
</body>
|
||||
|
||||
<!-- Startup (do not modify order of script tags!) -->
|
||||
<script>
|
||||
self.require = {
|
||||
baseUrl: `${window.location.origin}/static/out`,
|
||||
recordStats: true,
|
||||
createTrustedScriptURL: value => value,
|
||||
paths: {
|
||||
'vscode-textmate': `${window.location.origin}/static/remote/web/node_modules/vscode-textmate/release/main`,
|
||||
'vscode-oniguruma': `${window.location.origin}/static/remote/web/node_modules/vscode-oniguruma/release/main`,
|
||||
'xterm': `${window.location.origin}/static/remote/web/node_modules/xterm/lib/xterm.js`,
|
||||
'xterm-addon-search': `${window.location.origin}/static/remote/web/node_modules/xterm-addon-search/lib/xterm-addon-search.js`,
|
||||
'xterm-addon-unicode11': `${window.location.origin}/static/remote/web/node_modules/xterm-addon-unicode11/lib/xterm-addon-unicode11.js`,
|
||||
'xterm-addon-webgl': `${window.location.origin}/static/remote/web/node_modules/xterm-addon-webgl/lib/xterm-addon-webgl.js`,
|
||||
'tas-client-umd': `${window.location.origin}/static/remote/web/node_modules/tas-client-umd/lib/tas-client-umd.js`,
|
||||
'iconv-lite-umd': `${window.location.origin}/static/remote/web/node_modules/iconv-lite-umd/lib/iconv-lite-umd.js`,
|
||||
'jschardet': `${window.location.origin}/static/remote/web/node_modules/jschardet/dist/jschardet.min.js`,
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<script src="./static/out/vs/loader.js"></script>
|
||||
<script>
|
||||
globalThis.MonacoPerformanceMarks.push('willLoadWorkbenchMain', Date.now());
|
||||
</script>
|
||||
<script>
|
||||
require(['vs/code/browser/workbench/workbench'], function() {});
|
||||
</script>
|
||||
</html>
|
56
lib/vscode/src/vs/code/browser/workbench/workbench.html
Normal file
56
lib/vscode/src/vs/code/browser/workbench/workbench.html
Normal file
@ -0,0 +1,56 @@
|
||||
<!-- Copyright (C) Microsoft Corporation. All rights reserved. -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
globalThis.MonacoPerformanceMarks = globalThis.MonacoPerformanceMarks || [];
|
||||
globalThis.MonacoPerformanceMarks.push('renderer/started', Date.now());
|
||||
</script>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<!-- Disable pinch zooming -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
|
||||
|
||||
<!-- Workbench Configuration -->
|
||||
<meta id="vscode-workbench-web-configuration" data-settings="{{WORKBENCH_WEB_CONFIGURATION}}">
|
||||
|
||||
<!-- Workbench Auth Session -->
|
||||
<meta id="vscode-workbench-auth-session" data-settings="{{WORKBENCH_AUTH_SESSION}}">
|
||||
|
||||
<!-- Workbench Icon/Manifest/CSS -->
|
||||
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
<link data-name="vs/workbench/workbench.web.api" rel="stylesheet" href="./static/out/vs/workbench/workbench.web.api.css">
|
||||
|
||||
</head>
|
||||
|
||||
<body aria-label="">
|
||||
</body>
|
||||
|
||||
<!-- Startup (do not modify order of script tags!) -->
|
||||
<script>
|
||||
self.require = {
|
||||
baseUrl: `${window.location.origin}/static/out`,
|
||||
recordStats: true,
|
||||
createTrustedScriptURL: value => value,
|
||||
paths: {
|
||||
'vscode-textmate': `${window.location.origin}/static/node_modules/vscode-textmate/release/main`,
|
||||
'vscode-oniguruma': `${window.location.origin}/static/node_modules/vscode-oniguruma/release/main`,
|
||||
'xterm': `${window.location.origin}/static/node_modules/xterm/lib/xterm.js`,
|
||||
'xterm-addon-search': `${window.location.origin}/static/node_modules/xterm-addon-search/lib/xterm-addon-search.js`,
|
||||
'xterm-addon-unicode11': `${window.location.origin}/static/node_modules/xterm-addon-unicode11/lib/xterm-addon-unicode11.js`,
|
||||
'xterm-addon-webgl': `${window.location.origin}/static/node_modules/xterm-addon-webgl/lib/xterm-addon-webgl.js`,
|
||||
'tas-client-umd': `${window.location.origin}/static/node_modules/tas-client-umd/lib/tas-client-umd.js`,
|
||||
'iconv-lite-umd': `${window.location.origin}/static/node_modules/iconv-lite-umd/lib/iconv-lite-umd.js`,
|
||||
'jschardet': `${window.location.origin}/static/node_modules/jschardet/dist/jschardet.min.js`,
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<script src="./static/out/vs/loader.js"></script>
|
||||
<script>
|
||||
globalThis.MonacoPerformanceMarks.push('willLoadWorkbenchMain', Date.now());
|
||||
</script>
|
||||
<script src="./static/out/vs/workbench/workbench.web.api.nls.js"></script>
|
||||
<script src="./static/out/vs/workbench/workbench.web.api.js"></script>
|
||||
<script src="./static/out/vs/code/browser/workbench/workbench.js"></script>
|
||||
</html>
|
525
lib/vscode/src/vs/code/browser/workbench/workbench.ts
Normal file
525
lib/vscode/src/vs/code/browser/workbench/workbench.ts
Normal file
@ -0,0 +1,525 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IWorkbenchConstructionOptions, create, ICredentialsProvider, IURLCallbackProvider, IWorkspaceProvider, IWorkspace, IWindowIndicator, IHomeIndicator, IProductQualityChangeHandler, ISettingsSyncOptions } from 'vs/workbench/workbench.web.api';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { streamToBuffer } from 'vs/base/common/buffer';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { request } from 'vs/base/parts/request/browser/request';
|
||||
import { isFolderToOpen, isWorkspaceToOpen } from 'vs/platform/windows/common/windows';
|
||||
import { isEqual } from 'vs/base/common/resources';
|
||||
import { isStandalone } from 'vs/base/browser/browser';
|
||||
import { localize } from 'vs/nls';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
|
||||
function doCreateUri(path: string, queryValues: Map<string, string>): URI {
|
||||
let query: string | undefined = undefined;
|
||||
|
||||
if (queryValues) {
|
||||
let index = 0;
|
||||
queryValues.forEach((value, key) => {
|
||||
if (!query) {
|
||||
query = '';
|
||||
}
|
||||
|
||||
const prefix = (index++ === 0) ? '' : '&';
|
||||
query += `${prefix}${key}=${encodeURIComponent(value)}`;
|
||||
});
|
||||
}
|
||||
|
||||
return URI.parse(window.location.href).with({ path, query });
|
||||
}
|
||||
|
||||
interface ICredential {
|
||||
service: string;
|
||||
account: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
class LocalStorageCredentialsProvider implements ICredentialsProvider {
|
||||
|
||||
static readonly CREDENTIALS_OPENED_KEY = 'credentials.provider';
|
||||
|
||||
private readonly authService: string | undefined;
|
||||
|
||||
constructor() {
|
||||
let authSessionInfo: { readonly id: string, readonly accessToken: string, readonly providerId: string, readonly canSignOut?: boolean, readonly scopes: string[][] } | undefined;
|
||||
const authSessionElement = document.getElementById('vscode-workbench-auth-session');
|
||||
const authSessionElementAttribute = authSessionElement ? authSessionElement.getAttribute('data-settings') : undefined;
|
||||
if (authSessionElementAttribute) {
|
||||
try {
|
||||
authSessionInfo = JSON.parse(authSessionElementAttribute);
|
||||
} catch (error) { /* Invalid session is passed. Ignore. */ }
|
||||
}
|
||||
|
||||
if (authSessionInfo) {
|
||||
// Settings Sync Entry
|
||||
this.setPassword(`${product.urlProtocol}.login`, 'account', JSON.stringify(authSessionInfo));
|
||||
|
||||
// Auth extension Entry
|
||||
this.authService = `${product.urlProtocol}-${authSessionInfo.providerId}.login`;
|
||||
this.setPassword(this.authService, 'account', JSON.stringify(authSessionInfo.scopes.map(scopes => ({
|
||||
id: authSessionInfo!.id,
|
||||
scopes,
|
||||
accessToken: authSessionInfo!.accessToken
|
||||
}))));
|
||||
}
|
||||
}
|
||||
|
||||
private _credentials: ICredential[] | undefined;
|
||||
private get credentials(): ICredential[] {
|
||||
if (!this._credentials) {
|
||||
try {
|
||||
const serializedCredentials = window.localStorage.getItem(LocalStorageCredentialsProvider.CREDENTIALS_OPENED_KEY);
|
||||
if (serializedCredentials) {
|
||||
this._credentials = JSON.parse(serializedCredentials);
|
||||
}
|
||||
} catch (error) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
if (!Array.isArray(this._credentials)) {
|
||||
this._credentials = [];
|
||||
}
|
||||
}
|
||||
|
||||
return this._credentials;
|
||||
}
|
||||
|
||||
private save(): void {
|
||||
window.localStorage.setItem(LocalStorageCredentialsProvider.CREDENTIALS_OPENED_KEY, JSON.stringify(this.credentials));
|
||||
}
|
||||
|
||||
async getPassword(service: string, account: string): Promise<string | null> {
|
||||
return this.doGetPassword(service, account);
|
||||
}
|
||||
|
||||
private async doGetPassword(service: string, account?: string): Promise<string | null> {
|
||||
for (const credential of this.credentials) {
|
||||
if (credential.service === service) {
|
||||
if (typeof account !== 'string' || account === credential.account) {
|
||||
return credential.password;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
async setPassword(service: string, account: string, password: string): Promise<void> {
|
||||
this.doDeletePassword(service, account);
|
||||
|
||||
this.credentials.push({ service, account, password });
|
||||
|
||||
this.save();
|
||||
|
||||
try {
|
||||
if (password && service === this.authService) {
|
||||
const value = JSON.parse(password);
|
||||
if (Array.isArray(value) && value.length === 0) {
|
||||
await this.logout(service);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
async deletePassword(service: string, account: string): Promise<boolean> {
|
||||
const result = await this.doDeletePassword(service, account);
|
||||
|
||||
if (result && service === this.authService) {
|
||||
try {
|
||||
await this.logout(service);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async doDeletePassword(service: string, account: string): Promise<boolean> {
|
||||
let found = false;
|
||||
|
||||
this._credentials = this.credentials.filter(credential => {
|
||||
if (credential.service === service && credential.account === account) {
|
||||
found = true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
if (found) {
|
||||
this.save();
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
async findPassword(service: string): Promise<string | null> {
|
||||
return this.doGetPassword(service);
|
||||
}
|
||||
|
||||
async findCredentials(service: string): Promise<Array<{ account: string, password: string }>> {
|
||||
return this.credentials
|
||||
.filter(credential => credential.service === service)
|
||||
.map(({ account, password }) => ({ account, password }));
|
||||
}
|
||||
|
||||
private async logout(service: string): Promise<void> {
|
||||
const queryValues: Map<string, string> = new Map();
|
||||
queryValues.set('logout', String(true));
|
||||
queryValues.set('service', service);
|
||||
|
||||
await request({
|
||||
url: doCreateUri('/auth/logout', queryValues).toString(true)
|
||||
}, CancellationToken.None);
|
||||
}
|
||||
}
|
||||
|
||||
class PollingURLCallbackProvider extends Disposable implements IURLCallbackProvider {
|
||||
|
||||
static readonly FETCH_INTERVAL = 500; // fetch every 500ms
|
||||
static readonly FETCH_TIMEOUT = 5 * 60 * 1000; // ...but stop after 5min
|
||||
|
||||
static readonly QUERY_KEYS = {
|
||||
REQUEST_ID: 'vscode-requestId',
|
||||
SCHEME: 'vscode-scheme',
|
||||
AUTHORITY: 'vscode-authority',
|
||||
PATH: 'vscode-path',
|
||||
QUERY: 'vscode-query',
|
||||
FRAGMENT: 'vscode-fragment'
|
||||
};
|
||||
|
||||
private readonly _onCallback = this._register(new Emitter<URI>());
|
||||
readonly onCallback = this._onCallback.event;
|
||||
|
||||
create(options?: Partial<UriComponents>): URI {
|
||||
const queryValues: Map<string, string> = new Map();
|
||||
|
||||
const requestId = generateUuid();
|
||||
queryValues.set(PollingURLCallbackProvider.QUERY_KEYS.REQUEST_ID, requestId);
|
||||
|
||||
const { scheme, authority, path, query, fragment } = options ? options : { scheme: undefined, authority: undefined, path: undefined, query: undefined, fragment: undefined };
|
||||
|
||||
if (scheme) {
|
||||
queryValues.set(PollingURLCallbackProvider.QUERY_KEYS.SCHEME, scheme);
|
||||
}
|
||||
|
||||
if (authority) {
|
||||
queryValues.set(PollingURLCallbackProvider.QUERY_KEYS.AUTHORITY, authority);
|
||||
}
|
||||
|
||||
if (path) {
|
||||
queryValues.set(PollingURLCallbackProvider.QUERY_KEYS.PATH, path);
|
||||
}
|
||||
|
||||
if (query) {
|
||||
queryValues.set(PollingURLCallbackProvider.QUERY_KEYS.QUERY, query);
|
||||
}
|
||||
|
||||
if (fragment) {
|
||||
queryValues.set(PollingURLCallbackProvider.QUERY_KEYS.FRAGMENT, fragment);
|
||||
}
|
||||
|
||||
// Start to poll on the callback being fired
|
||||
this.periodicFetchCallback(requestId, Date.now());
|
||||
|
||||
return doCreateUri('/callback', queryValues);
|
||||
}
|
||||
|
||||
private async periodicFetchCallback(requestId: string, startTime: number): Promise<void> {
|
||||
|
||||
// Ask server for callback results
|
||||
const queryValues: Map<string, string> = new Map();
|
||||
queryValues.set(PollingURLCallbackProvider.QUERY_KEYS.REQUEST_ID, requestId);
|
||||
|
||||
const result = await request({
|
||||
url: doCreateUri('/fetch-callback', queryValues).toString(true)
|
||||
}, CancellationToken.None);
|
||||
|
||||
// Check for callback results
|
||||
const content = await streamToBuffer(result.stream);
|
||||
if (content.byteLength > 0) {
|
||||
try {
|
||||
this._onCallback.fire(URI.revive(JSON.parse(content.toString())));
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
return; // done
|
||||
}
|
||||
|
||||
// Continue fetching unless we hit the timeout
|
||||
if (Date.now() - startTime < PollingURLCallbackProvider.FETCH_TIMEOUT) {
|
||||
setTimeout(() => this.periodicFetchCallback(requestId, startTime), PollingURLCallbackProvider.FETCH_INTERVAL);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class WorkspaceProvider implements IWorkspaceProvider {
|
||||
|
||||
static QUERY_PARAM_EMPTY_WINDOW = 'ew';
|
||||
static QUERY_PARAM_FOLDER = 'folder';
|
||||
static QUERY_PARAM_WORKSPACE = 'workspace';
|
||||
|
||||
static QUERY_PARAM_PAYLOAD = 'payload';
|
||||
|
||||
constructor(
|
||||
public readonly workspace: IWorkspace,
|
||||
public readonly payload: object
|
||||
) { }
|
||||
|
||||
async open(workspace: IWorkspace, options?: { reuse?: boolean, payload?: object }): Promise<void> {
|
||||
if (options?.reuse && !options.payload && this.isSame(this.workspace, workspace)) {
|
||||
return; // return early if workspace and environment is not changing and we are reusing window
|
||||
}
|
||||
|
||||
const targetHref = this.createTargetUrl(workspace, options);
|
||||
if (targetHref) {
|
||||
if (options?.reuse) {
|
||||
window.location.href = targetHref;
|
||||
} else {
|
||||
if (isStandalone) {
|
||||
window.open(targetHref, '_blank', 'toolbar=no'); // ensures to open another 'standalone' window!
|
||||
} else {
|
||||
window.open(targetHref);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private createTargetUrl(workspace: IWorkspace, options?: { reuse?: boolean, payload?: object }): string | undefined {
|
||||
|
||||
// Empty
|
||||
let targetHref: string | undefined = undefined;
|
||||
if (!workspace) {
|
||||
targetHref = `${document.location.origin}${document.location.pathname}?${WorkspaceProvider.QUERY_PARAM_EMPTY_WINDOW}=true`;
|
||||
}
|
||||
|
||||
// Folder
|
||||
else if (isFolderToOpen(workspace)) {
|
||||
targetHref = `${document.location.origin}${document.location.pathname}?${WorkspaceProvider.QUERY_PARAM_FOLDER}=${encodeURIComponent(workspace.folderUri.toString())}`;
|
||||
}
|
||||
|
||||
// Workspace
|
||||
else if (isWorkspaceToOpen(workspace)) {
|
||||
targetHref = `${document.location.origin}${document.location.pathname}?${WorkspaceProvider.QUERY_PARAM_WORKSPACE}=${encodeURIComponent(workspace.workspaceUri.toString())}`;
|
||||
}
|
||||
|
||||
// Append payload if any
|
||||
if (options?.payload) {
|
||||
targetHref += `&${WorkspaceProvider.QUERY_PARAM_PAYLOAD}=${encodeURIComponent(JSON.stringify(options.payload))}`;
|
||||
}
|
||||
|
||||
return targetHref;
|
||||
}
|
||||
|
||||
private isSame(workspaceA: IWorkspace, workspaceB: IWorkspace): boolean {
|
||||
if (!workspaceA || !workspaceB) {
|
||||
return workspaceA === workspaceB; // both empty
|
||||
}
|
||||
|
||||
if (isFolderToOpen(workspaceA) && isFolderToOpen(workspaceB)) {
|
||||
return isEqual(workspaceA.folderUri, workspaceB.folderUri); // same workspace
|
||||
}
|
||||
|
||||
if (isWorkspaceToOpen(workspaceA) && isWorkspaceToOpen(workspaceB)) {
|
||||
return isEqual(workspaceA.workspaceUri, workspaceB.workspaceUri); // same workspace
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
hasRemote(): boolean {
|
||||
if (this.workspace) {
|
||||
if (isFolderToOpen(this.workspace)) {
|
||||
return this.workspace.folderUri.scheme === Schemas.vscodeRemote;
|
||||
}
|
||||
|
||||
if (isWorkspaceToOpen(this.workspace)) {
|
||||
return this.workspace.workspaceUri.scheme === Schemas.vscodeRemote;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class WindowIndicator implements IWindowIndicator {
|
||||
|
||||
readonly onDidChange = Event.None;
|
||||
|
||||
readonly label: string;
|
||||
readonly tooltip: string;
|
||||
readonly command: string | undefined;
|
||||
|
||||
constructor(workspace: IWorkspace) {
|
||||
let repositoryOwner: string | undefined = undefined;
|
||||
let repositoryName: string | undefined = undefined;
|
||||
|
||||
if (workspace) {
|
||||
let uri: URI | undefined = undefined;
|
||||
if (isFolderToOpen(workspace)) {
|
||||
uri = workspace.folderUri;
|
||||
} else if (isWorkspaceToOpen(workspace)) {
|
||||
uri = workspace.workspaceUri;
|
||||
}
|
||||
|
||||
if (uri?.scheme === 'github' || uri?.scheme === 'codespace') {
|
||||
[repositoryOwner, repositoryName] = uri.authority.split('+');
|
||||
}
|
||||
}
|
||||
|
||||
// Repo
|
||||
if (repositoryName && repositoryOwner) {
|
||||
this.label = localize('playgroundLabelRepository', "$(remote) VS Code Web Playground: {0}/{1}", repositoryOwner, repositoryName);
|
||||
this.tooltip = localize('playgroundRepositoryTooltip', "VS Code Web Playground: {0}/{1}", repositoryOwner, repositoryName);
|
||||
}
|
||||
|
||||
// No Repo
|
||||
else {
|
||||
this.label = localize('playgroundLabel', "$(remote) VS Code Web Playground");
|
||||
this.tooltip = localize('playgroundTooltip', "VS Code Web Playground");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(function () {
|
||||
|
||||
// Find config by checking for DOM
|
||||
const configElement = document.getElementById('vscode-workbench-web-configuration');
|
||||
const configElementAttribute = configElement ? configElement.getAttribute('data-settings') : undefined;
|
||||
if (!configElement || !configElementAttribute) {
|
||||
throw new Error('Missing web configuration element');
|
||||
}
|
||||
|
||||
const config: IWorkbenchConstructionOptions & { folderUri?: UriComponents, workspaceUri?: UriComponents } = JSON.parse(configElementAttribute);
|
||||
|
||||
// Revive static extension locations
|
||||
if (Array.isArray(config.staticExtensions)) {
|
||||
config.staticExtensions.forEach(extension => {
|
||||
extension.extensionLocation = URI.revive(extension.extensionLocation);
|
||||
});
|
||||
}
|
||||
|
||||
// Find workspace to open and payload
|
||||
let foundWorkspace = false;
|
||||
let workspace: IWorkspace;
|
||||
let payload = Object.create(null);
|
||||
|
||||
const query = new URL(document.location.href).searchParams;
|
||||
query.forEach((value, key) => {
|
||||
switch (key) {
|
||||
|
||||
// Folder
|
||||
case WorkspaceProvider.QUERY_PARAM_FOLDER:
|
||||
workspace = { folderUri: URI.parse(value) };
|
||||
foundWorkspace = true;
|
||||
break;
|
||||
|
||||
// Workspace
|
||||
case WorkspaceProvider.QUERY_PARAM_WORKSPACE:
|
||||
workspace = { workspaceUri: URI.parse(value) };
|
||||
foundWorkspace = true;
|
||||
break;
|
||||
|
||||
// Empty
|
||||
case WorkspaceProvider.QUERY_PARAM_EMPTY_WINDOW:
|
||||
workspace = undefined;
|
||||
foundWorkspace = true;
|
||||
break;
|
||||
|
||||
// Payload
|
||||
case WorkspaceProvider.QUERY_PARAM_PAYLOAD:
|
||||
try {
|
||||
payload = JSON.parse(value);
|
||||
} catch (error) {
|
||||
console.error(error); // possible invalid JSON
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// If no workspace is provided through the URL, check for config attribute from server
|
||||
if (!foundWorkspace) {
|
||||
if (config.folderUri) {
|
||||
workspace = { folderUri: URI.revive(config.folderUri) };
|
||||
} else if (config.workspaceUri) {
|
||||
workspace = { workspaceUri: URI.revive(config.workspaceUri) };
|
||||
} else {
|
||||
workspace = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// Workspace Provider
|
||||
const workspaceProvider = new WorkspaceProvider(workspace, payload);
|
||||
|
||||
// Home Indicator
|
||||
const homeIndicator: IHomeIndicator = {
|
||||
href: 'https://github.com/microsoft/vscode',
|
||||
icon: 'code',
|
||||
title: localize('home', "Home")
|
||||
};
|
||||
|
||||
// Window indicator (unless connected to a remote)
|
||||
let windowIndicator: WindowIndicator | undefined = undefined;
|
||||
if (!workspaceProvider.hasRemote()) {
|
||||
windowIndicator = new WindowIndicator(workspace);
|
||||
}
|
||||
|
||||
// Product Quality Change Handler
|
||||
const productQualityChangeHandler: IProductQualityChangeHandler = (quality) => {
|
||||
let queryString = `quality=${quality}`;
|
||||
|
||||
// Save all other query params we might have
|
||||
const query = new URL(document.location.href).searchParams;
|
||||
query.forEach((value, key) => {
|
||||
if (key !== 'quality') {
|
||||
queryString += `&${key}=${value}`;
|
||||
}
|
||||
});
|
||||
|
||||
window.location.href = `${window.location.origin}?${queryString}`;
|
||||
};
|
||||
|
||||
// settings sync options
|
||||
const settingsSyncOptions: ISettingsSyncOptions | undefined = config.settingsSyncOptions ? {
|
||||
enabled: config.settingsSyncOptions.enabled,
|
||||
enablementHandler: (enablement) => {
|
||||
let queryString = `settingsSync=${enablement ? 'true' : 'false'}`;
|
||||
|
||||
// Save all other query params we might have
|
||||
const query = new URL(document.location.href).searchParams;
|
||||
query.forEach((value, key) => {
|
||||
if (key !== 'settingsSync') {
|
||||
queryString += `&${key}=${value}`;
|
||||
}
|
||||
});
|
||||
|
||||
window.location.href = `${window.location.origin}?${queryString}`;
|
||||
}
|
||||
} : undefined;
|
||||
|
||||
// Finally create workbench
|
||||
create(document.body, {
|
||||
...config,
|
||||
settingsSyncOptions,
|
||||
homeIndicator,
|
||||
windowIndicator,
|
||||
productQualityChangeHandler,
|
||||
workspaceProvider,
|
||||
urlCallbackProvider: new PollingURLCallbackProvider(),
|
||||
credentialsProvider: new LocalStorageCredentialsProvider()
|
||||
});
|
||||
})();
|
Reference in New Issue
Block a user