@jiangzhongxi0322/messagechannel 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +181 -0
- package/dist/messageChannel.d.ts +10 -0
- package/dist/{messageChennel.js → messageChannel.js} +25 -8
- package/examples/command-webview-sample/.eslintrc.js +23 -0
- package/examples/command-webview-sample/.vscode/extensions.json +9 -0
- package/examples/command-webview-sample/.vscode/launch.json +18 -0
- package/examples/command-webview-sample/.vscode/settings.json +3 -0
- package/examples/command-webview-sample/.vscode/tasks.json +20 -0
- package/examples/command-webview-sample/README.md +47 -0
- package/examples/command-webview-sample/demo.gif +0 -0
- package/examples/command-webview-sample/media/cat.gif +0 -0
- package/examples/command-webview-sample/media/jsconfig.json +22 -0
- package/examples/command-webview-sample/media/main.js +41 -0
- package/examples/command-webview-sample/media/reset.css +30 -0
- package/examples/command-webview-sample/media/vscode.css +91 -0
- package/examples/command-webview-sample/package-lock.json +2764 -0
- package/examples/command-webview-sample/package.json +51 -0
- package/examples/command-webview-sample/src/extension.ts +227 -0
- package/{src/messageChennel.ts → examples/command-webview-sample/src/messageChannel.ts} +34 -21
- package/examples/command-webview-sample/tsconfig.json +12 -0
- package/examples/publish-webview-sample/.eslintrc.js +20 -0
- package/examples/publish-webview-sample/.vscode/extensions.json +9 -0
- package/examples/publish-webview-sample/.vscode/launch.json +18 -0
- package/examples/publish-webview-sample/.vscode/settings.json +3 -0
- package/examples/publish-webview-sample/.vscode/tasks.json +20 -0
- package/examples/publish-webview-sample/README.md +24 -0
- package/examples/publish-webview-sample/media/main.css +54 -0
- package/examples/publish-webview-sample/media/main.js +100 -0
- package/examples/publish-webview-sample/media/reset.css +30 -0
- package/examples/publish-webview-sample/media/vscode.css +91 -0
- package/examples/publish-webview-sample/package-lock.json +2720 -0
- package/examples/publish-webview-sample/package.json +71 -0
- package/examples/publish-webview-sample/src/extension.ts +170 -0
- package/examples/publish-webview-sample/src/messageChannel.ts +264 -0
- package/examples/publish-webview-sample/tsconfig.json +12 -0
- package/examples/url-webview-sample/.eslintignore +1 -0
- package/examples/url-webview-sample/.eslintrc.js +20 -0
- package/examples/url-webview-sample/.vscode/extensions.json +9 -0
- package/examples/url-webview-sample/.vscode/launch.json +18 -0
- package/examples/url-webview-sample/.vscode/settings.json +3 -0
- package/examples/url-webview-sample/.vscode/tasks.json +20 -0
- package/examples/url-webview-sample/README.md +25 -0
- package/examples/url-webview-sample/documentation/example.png +0 -0
- package/examples/url-webview-sample/exampleFiles/example.cscratch +14 -0
- package/examples/url-webview-sample/exampleFiles/example.pawDraw +0 -0
- package/examples/url-webview-sample/exampleFiles/log/python-kaleido-case-api.exe.log +1 -0
- package/examples/url-webview-sample/exampleFiles/log/python-request.exe.log +1 -0
- package/examples/url-webview-sample/exampleFiles/pump/config/default.json +1 -0
- package/examples/url-webview-sample/exampleFiles/test_cases/log/output_202511181702.log +6 -0
- package/examples/url-webview-sample/media/catScratch.css +65 -0
- package/examples/url-webview-sample/media/catScratch.js +100 -0
- package/examples/url-webview-sample/media/paw-color.svg +21 -0
- package/examples/url-webview-sample/media/paw-outline.svg +21 -0
- package/examples/url-webview-sample/media/pawDraw.css +83 -0
- package/examples/url-webview-sample/media/pawDraw.js +266 -0
- package/examples/url-webview-sample/media/reset.css +30 -0
- package/examples/url-webview-sample/media/sand-dark.jpg +0 -0
- package/examples/url-webview-sample/media/sand.jpg +0 -0
- package/examples/url-webview-sample/media/vscode.css +91 -0
- package/examples/url-webview-sample/package-lock.json +2751 -0
- package/examples/url-webview-sample/package.json +64 -0
- package/examples/url-webview-sample/src/catScratchEditor.ts +215 -0
- package/examples/url-webview-sample/src/dispose.ts +37 -0
- package/examples/url-webview-sample/src/extension.ts +7 -0
- package/examples/url-webview-sample/src/messageChannel.ts +264 -0
- package/examples/url-webview-sample/src/util.ts +8 -0
- package/examples/url-webview-sample/tsconfig.json +13 -0
- package/package.json +3 -3
- package/src/messageChannel.ts +264 -0
- package/dist/messageChennel.d.ts +0 -15
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "response-url-webview-sample",
|
|
3
|
+
"displayName": "Response URL Webview Sample",
|
|
4
|
+
"description": "Custom Editor API Samples",
|
|
5
|
+
"version": "0.1.0",
|
|
6
|
+
"publisher": "walker",
|
|
7
|
+
"private": true,
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/Microsoft/vscode-extension-samples"
|
|
12
|
+
},
|
|
13
|
+
"engines": {
|
|
14
|
+
"vscode": "^1.74.0"
|
|
15
|
+
},
|
|
16
|
+
"categories": [
|
|
17
|
+
"Other"
|
|
18
|
+
],
|
|
19
|
+
"activationEvents": [],
|
|
20
|
+
"main": "./out/extension.js",
|
|
21
|
+
"contributes": {
|
|
22
|
+
"customEditors": [
|
|
23
|
+
{
|
|
24
|
+
"viewType": "catCustoms.catScratch",
|
|
25
|
+
"displayName": "Cat Scratch",
|
|
26
|
+
"selector": [
|
|
27
|
+
{
|
|
28
|
+
"filenamePattern": "*.cscratch"
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"viewType": "catCustoms.pawDraw",
|
|
34
|
+
"displayName": "Paw Draw",
|
|
35
|
+
"selector": [
|
|
36
|
+
{
|
|
37
|
+
"filenamePattern": "*.pawdraw"
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
"commands": [
|
|
43
|
+
{
|
|
44
|
+
"command": "catCustoms.pawDraw.new",
|
|
45
|
+
"title": "Create new Paw Draw Document",
|
|
46
|
+
"category": "Paw Draw"
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"vscode:prepublish": "npm run compile",
|
|
52
|
+
"compile": "tsc -p ./",
|
|
53
|
+
"lint": "eslint \"src/**/*.ts\"",
|
|
54
|
+
"watch": "tsc -w -p ./"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@types/node": "^18",
|
|
58
|
+
"@types/vscode": "^1.73.0",
|
|
59
|
+
"@typescript-eslint/eslint-plugin": "^6.7.0",
|
|
60
|
+
"@typescript-eslint/parser": "^6.7.0",
|
|
61
|
+
"eslint": "^8.26.0",
|
|
62
|
+
"typescript": "^5.4.2"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import * as vscode from 'vscode';
|
|
2
|
+
import { getNonce } from './util';
|
|
3
|
+
import MessageChannel from './messageChannel';
|
|
4
|
+
|
|
5
|
+
const mc = MessageChannel();
|
|
6
|
+
/**
|
|
7
|
+
* Provider for cat scratch editors.
|
|
8
|
+
*
|
|
9
|
+
* Cat scratch editors are used for `.cscratch` files, which are just json files.
|
|
10
|
+
* To get started, run this extension and open an empty `.cscratch` file in VS Code.
|
|
11
|
+
*
|
|
12
|
+
* This provider demonstrates:
|
|
13
|
+
*
|
|
14
|
+
* - Setting up the initial webview for a custom editor.
|
|
15
|
+
* - Loading scripts and styles in a custom editor.
|
|
16
|
+
* - Synchronizing changes between a text document and a custom editor.
|
|
17
|
+
*/
|
|
18
|
+
export class CatScratchEditorProvider implements vscode.CustomTextEditorProvider {
|
|
19
|
+
|
|
20
|
+
public static register(context: vscode.ExtensionContext): vscode.Disposable {
|
|
21
|
+
mc.initiator(CatScratchEditorProvider.viewType);
|
|
22
|
+
const provider = new CatScratchEditorProvider(context);
|
|
23
|
+
const providerRegistration = vscode.window.registerCustomEditorProvider(CatScratchEditorProvider.viewType, provider);
|
|
24
|
+
return providerRegistration;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
private static readonly viewType = 'catCustoms.catScratch';
|
|
28
|
+
|
|
29
|
+
private static readonly scratchCharacters = ['😸', '😹', '😺', '😻', '😼', '😽', '😾', '🙀', '😿', '🐱'];
|
|
30
|
+
|
|
31
|
+
constructor(
|
|
32
|
+
private readonly context: vscode.ExtensionContext
|
|
33
|
+
) { }
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Called when our custom editor is opened.
|
|
37
|
+
*
|
|
38
|
+
*
|
|
39
|
+
*/
|
|
40
|
+
public async resolveCustomTextEditor(
|
|
41
|
+
document: vscode.TextDocument,
|
|
42
|
+
webviewPanel: vscode.WebviewPanel,
|
|
43
|
+
_token: vscode.CancellationToken
|
|
44
|
+
): Promise<void> {
|
|
45
|
+
mc.setCarrier(webviewPanel.webview);
|
|
46
|
+
// Setup initial content for the webview
|
|
47
|
+
webviewPanel.webview.options = {
|
|
48
|
+
enableScripts: true,
|
|
49
|
+
};
|
|
50
|
+
webviewPanel.webview.html = this.getHtmlForWebview(webviewPanel.webview);
|
|
51
|
+
|
|
52
|
+
function updateWebview() {
|
|
53
|
+
webviewPanel.webview.postMessage({
|
|
54
|
+
type: 'update',
|
|
55
|
+
text: document.getText(),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Hook up event handlers so that we can synchronize the webview with the text document.
|
|
60
|
+
//
|
|
61
|
+
// The text document acts as our model, so we have to sync change in the document to our
|
|
62
|
+
// editor and sync changes in the editor back to the document.
|
|
63
|
+
//
|
|
64
|
+
// Remember that a single text document can also be shared between multiple custom
|
|
65
|
+
// editors (this happens for example when you split a custom editor)
|
|
66
|
+
|
|
67
|
+
const changeDocumentSubscription = vscode.workspace.onDidChangeTextDocument(e => {
|
|
68
|
+
if (e.document.uri.toString() === document.uri.toString()) {
|
|
69
|
+
updateWebview();
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Make sure we get rid of the listener when our editor is closed.
|
|
74
|
+
webviewPanel.onDidDispose(() => {
|
|
75
|
+
changeDocumentSubscription.dispose();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Receive message from the webview.
|
|
79
|
+
webviewPanel.webview.onDidReceiveMessage(e => {
|
|
80
|
+
switch (e.type) {
|
|
81
|
+
case 'add':
|
|
82
|
+
this.addNewScratch(document);
|
|
83
|
+
return;
|
|
84
|
+
|
|
85
|
+
case 'delete':
|
|
86
|
+
this.deleteScratch(document, e.id);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
updateWebview();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Get the static html used for the editor webviews.
|
|
96
|
+
*/
|
|
97
|
+
private getHtmlForWebview(webview: vscode.Webview): string {
|
|
98
|
+
// Local path to script and css for the webview
|
|
99
|
+
const scriptUri = webview.asWebviewUri(vscode.Uri.joinPath(
|
|
100
|
+
this.context.extensionUri, 'media', 'catScratch.js'));
|
|
101
|
+
|
|
102
|
+
const styleResetUri = webview.asWebviewUri(vscode.Uri.joinPath(
|
|
103
|
+
this.context.extensionUri, 'media', 'reset.css'));
|
|
104
|
+
|
|
105
|
+
const styleVSCodeUri = webview.asWebviewUri(vscode.Uri.joinPath(
|
|
106
|
+
this.context.extensionUri, 'media', 'vscode.css'));
|
|
107
|
+
|
|
108
|
+
const styleMainUri = webview.asWebviewUri(vscode.Uri.joinPath(
|
|
109
|
+
this.context.extensionUri, 'media', 'catScratch.css'));
|
|
110
|
+
|
|
111
|
+
// Use a nonce to whitelist which scripts can be run
|
|
112
|
+
const nonce = getNonce();
|
|
113
|
+
|
|
114
|
+
return /* html */`
|
|
115
|
+
<!DOCTYPE html>
|
|
116
|
+
<html lang="en">
|
|
117
|
+
<head>
|
|
118
|
+
<meta charset="UTF-8">
|
|
119
|
+
|
|
120
|
+
<!--
|
|
121
|
+
Use a content security policy to only allow loading images from https or from our extension directory,
|
|
122
|
+
and only allow scripts that have a specific nonce.
|
|
123
|
+
-->
|
|
124
|
+
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src ${webview.cspSource}; style-src ${webview.cspSource}; script-src 'nonce-${nonce}';">
|
|
125
|
+
|
|
126
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
127
|
+
|
|
128
|
+
<link href="${styleResetUri}" rel="stylesheet" />
|
|
129
|
+
<link href="${styleVSCodeUri}" rel="stylesheet" />
|
|
130
|
+
<link href="${styleMainUri}" rel="stylesheet" />
|
|
131
|
+
|
|
132
|
+
<title>Cat Scratch</title>
|
|
133
|
+
</head>
|
|
134
|
+
<body>
|
|
135
|
+
此处输入需要反馈的数据:<input style="border: 1px solid #ccc; padding: 4px; border-radius: 4px;" placeholder="请输入反馈内容"/>
|
|
136
|
+
<button>反馈</button>
|
|
137
|
+
|
|
138
|
+
<script nonce="${nonce}">
|
|
139
|
+
// 示例一
|
|
140
|
+
document.querySelector('button').addEventListener('click', (args) => {
|
|
141
|
+
const result = document.querySelector('input').value;
|
|
142
|
+
feedbackResult && feedbackResult(result);
|
|
143
|
+
});
|
|
144
|
+
window.mc = (${MessageChannel.toString()})();
|
|
145
|
+
window.mc.setCarrier();
|
|
146
|
+
window.mc.initiator();
|
|
147
|
+
</script>
|
|
148
|
+
</body>
|
|
149
|
+
</html>`;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Add a new scratch to the current document.
|
|
154
|
+
*/
|
|
155
|
+
private addNewScratch(document: vscode.TextDocument) {
|
|
156
|
+
const json = this.getDocumentAsJson(document);
|
|
157
|
+
const character = CatScratchEditorProvider.scratchCharacters[Math.floor(Math.random() * CatScratchEditorProvider.scratchCharacters.length)];
|
|
158
|
+
json.scratches = [
|
|
159
|
+
...(Array.isArray(json.scratches) ? json.scratches : []),
|
|
160
|
+
{
|
|
161
|
+
id: getNonce(),
|
|
162
|
+
text: character,
|
|
163
|
+
created: Date.now(),
|
|
164
|
+
}
|
|
165
|
+
];
|
|
166
|
+
|
|
167
|
+
return this.updateTextDocument(document, json);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Delete an existing scratch from a document.
|
|
172
|
+
*/
|
|
173
|
+
private deleteScratch(document: vscode.TextDocument, id: string) {
|
|
174
|
+
const json = this.getDocumentAsJson(document);
|
|
175
|
+
if (!Array.isArray(json.scratches)) {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
json.scratches = json.scratches.filter((note: any) => note.id !== id);
|
|
180
|
+
|
|
181
|
+
return this.updateTextDocument(document, json);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Try to get a current document as json text.
|
|
186
|
+
*/
|
|
187
|
+
private getDocumentAsJson(document: vscode.TextDocument): any {
|
|
188
|
+
const text = document.getText();
|
|
189
|
+
if (text.trim().length === 0) {
|
|
190
|
+
return {};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
try {
|
|
194
|
+
return JSON.parse(text);
|
|
195
|
+
} catch {
|
|
196
|
+
throw new Error('Could not get document as json. Content is not valid json');
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Write out the json to a given document.
|
|
202
|
+
*/
|
|
203
|
+
private updateTextDocument(document: vscode.TextDocument, json: any) {
|
|
204
|
+
const edit = new vscode.WorkspaceEdit();
|
|
205
|
+
|
|
206
|
+
// Just replace the entire document every time for this example extension.
|
|
207
|
+
// A more complete extension should compute minimal edits instead.
|
|
208
|
+
edit.replace(
|
|
209
|
+
document.uri,
|
|
210
|
+
new vscode.Range(0, 0, document.lineCount, 0),
|
|
211
|
+
JSON.stringify(json, null, 2));
|
|
212
|
+
|
|
213
|
+
return vscode.workspace.applyEdit(edit);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as vscode from 'vscode';
|
|
2
|
+
|
|
3
|
+
export function disposeAll(disposables: vscode.Disposable[]): void {
|
|
4
|
+
while (disposables.length) {
|
|
5
|
+
const item = disposables.pop();
|
|
6
|
+
if (item) {
|
|
7
|
+
item.dispose();
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export abstract class Disposable {
|
|
13
|
+
private _isDisposed = false;
|
|
14
|
+
|
|
15
|
+
protected _disposables: vscode.Disposable[] = [];
|
|
16
|
+
|
|
17
|
+
public dispose(): any {
|
|
18
|
+
if (this._isDisposed) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
this._isDisposed = true;
|
|
22
|
+
disposeAll(this._disposables);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
protected _register<T extends vscode.Disposable>(value: T): T {
|
|
26
|
+
if (this._isDisposed) {
|
|
27
|
+
value.dispose();
|
|
28
|
+
} else {
|
|
29
|
+
this._disposables.push(value);
|
|
30
|
+
}
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
protected get isDisposed(): boolean {
|
|
35
|
+
return this._isDisposed;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as vscode from 'vscode';
|
|
2
|
+
import { CatScratchEditorProvider } from './catScratchEditor';
|
|
3
|
+
|
|
4
|
+
export function activate(context: vscode.ExtensionContext) {
|
|
5
|
+
// Register our custom editor providers
|
|
6
|
+
context.subscriptions.push(CatScratchEditorProvider.register(context));
|
|
7
|
+
}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import * as vscode from 'vscode';
|
|
2
|
+
|
|
3
|
+
interface Event {
|
|
4
|
+
typename?: string;
|
|
5
|
+
key?: string;
|
|
6
|
+
channelId: string;
|
|
7
|
+
data: any;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// 每个vscode的node端和webview都分别拥有一个MessageChannel返回的对象,因为他们是不同载体
|
|
11
|
+
// 同一webview如果打开了多个文档,各个文档也应该有不同的载体
|
|
12
|
+
declare const window: any;
|
|
13
|
+
|
|
14
|
+
const MessageChannel = () => {
|
|
15
|
+
let cachedCarrier: vscode.Webview | null;
|
|
16
|
+
let dispose: vscode.Disposable;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @carrier 在vscode的webviewProvider以及webview的web内都调用这个接口,设置发送和接受事件的载体
|
|
20
|
+
* webviewProvider示例:CI.setCarrier(webviewView.webview); // 在最早获取到webview的地方
|
|
21
|
+
* webview的react项目示例:CI.setCarrier(); // 在根组件
|
|
22
|
+
* carrier如果为空,则清空之前的载体
|
|
23
|
+
*/
|
|
24
|
+
const setCarrier = (carrier?: null | vscode.Webview) => {
|
|
25
|
+
if (carrier === undefined) {
|
|
26
|
+
cachedCarrier = (window as any).acquireVsCodeApi();
|
|
27
|
+
(window as any).addEventListener('message', (event: any) => {
|
|
28
|
+
messageHandler(event.data);
|
|
29
|
+
});
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (cachedCarrier) {
|
|
33
|
+
dispose.dispose();
|
|
34
|
+
}
|
|
35
|
+
cachedCarrier = carrier;
|
|
36
|
+
if (cachedCarrier === null) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
dispose = cachedCarrier.onDidReceiveMessage((event) =>
|
|
40
|
+
messageHandler(event)
|
|
41
|
+
);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const subscribers: {
|
|
45
|
+
[i: string]: ((data: any) => void)[];
|
|
46
|
+
} = {};
|
|
47
|
+
|
|
48
|
+
const messageHandler = async (event: Event) => {
|
|
49
|
+
const { data, typename } = event;
|
|
50
|
+
const isTalkInExtension = typename && subscribers[typename];
|
|
51
|
+
if (isTalkInExtension) {
|
|
52
|
+
subscribers[typename as string].forEach((resolver) => {
|
|
53
|
+
resolver(data);
|
|
54
|
+
});
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const isTalkToExtension = typename && (data as any)?.viewType;
|
|
58
|
+
if(isTalkToExtension) {
|
|
59
|
+
const activeTargetExtension = async (extensionId: string) => {
|
|
60
|
+
const targetExtension = vscode.extensions.getExtension(extensionId);
|
|
61
|
+
if(!targetExtension ) {
|
|
62
|
+
console.warn(`Extension ${extensionId} not found`);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if(!targetExtension.isActive) {
|
|
66
|
+
await targetExtension?.activate();
|
|
67
|
+
}
|
|
68
|
+
return true;
|
|
69
|
+
};
|
|
70
|
+
if(await activeTargetExtension(typename)) {
|
|
71
|
+
const commands = await vscode.commands.getCommands();
|
|
72
|
+
const commandID = `to_${data.viewType}`;
|
|
73
|
+
if(commands.includes(commandID)) {
|
|
74
|
+
const talkToOtherExtension = async () => {
|
|
75
|
+
const result = await vscode.commands.executeCommand(commandID, data);
|
|
76
|
+
publish(typename, result);
|
|
77
|
+
if (result !== undefined) {
|
|
78
|
+
await talkToOtherExtension();
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
await talkToOtherExtension();
|
|
82
|
+
} else {
|
|
83
|
+
console.warn(`Command ${commandID} not found`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* typename: 消息类型,消息的发布和订阅都依赖这个typename
|
|
92
|
+
* subscriber:收到消息后把消息传递给subscriber
|
|
93
|
+
* once:一次性订阅,收到消息后就把订阅者移除
|
|
94
|
+
*/
|
|
95
|
+
const subscribe = (
|
|
96
|
+
typename: string,
|
|
97
|
+
subscriber: (data: any) => any,
|
|
98
|
+
once = false
|
|
99
|
+
) => {
|
|
100
|
+
if (!subscriber || !(subscriber instanceof Function)) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const resolver = (data: any) => {
|
|
104
|
+
const result = subscriber(data);
|
|
105
|
+
if (result !== undefined) {
|
|
106
|
+
if (result instanceof Promise) {
|
|
107
|
+
result.then((data) => {
|
|
108
|
+
publish(typename, data);
|
|
109
|
+
});
|
|
110
|
+
} else {
|
|
111
|
+
publish(typename, result);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (once) {
|
|
115
|
+
const subscriber = subscribers[typename];
|
|
116
|
+
if (subscriber?.length) {
|
|
117
|
+
const i = subscriber.indexOf(resolver);
|
|
118
|
+
subscriber.splice(i, 1);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
const _subscribers = subscribers;
|
|
123
|
+
if (_subscribers[typename]) {
|
|
124
|
+
_subscribers[typename].push(resolver);
|
|
125
|
+
} else {
|
|
126
|
+
_subscribers[typename] = [resolver];
|
|
127
|
+
}
|
|
128
|
+
return () => {
|
|
129
|
+
const subscriber = subscribers[typename];
|
|
130
|
+
if (subscriber?.length) {
|
|
131
|
+
const i = subscriber.indexOf(resolver);
|
|
132
|
+
subscriber.splice(i, 1);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* typename: 消息类型,消息的发布和订阅都依赖这个typename
|
|
139
|
+
* msg:消息发布时带的参数
|
|
140
|
+
*/
|
|
141
|
+
const publish = (typename: string, data?: any) => {
|
|
142
|
+
try {
|
|
143
|
+
cachedCarrier?.postMessage({
|
|
144
|
+
typename: typename,
|
|
145
|
+
data: data,
|
|
146
|
+
});
|
|
147
|
+
} catch (error) {0;}
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* 如果要唤醒其余插件的webview,则双方插件的provider、web都要调用这个函数初始化
|
|
153
|
+
* viewType:provider传递WebviewProvieder的viewType,web则不用传递参数
|
|
154
|
+
*/
|
|
155
|
+
const initiator = (viewType?: string) => {
|
|
156
|
+
// for node
|
|
157
|
+
if(viewType) {
|
|
158
|
+
vscode.commands.registerCommand(`to_${viewType}`, async (args) => {
|
|
159
|
+
const { source } = args;
|
|
160
|
+
const openWebview = async () => {
|
|
161
|
+
const commands = await vscode.commands.getCommands();
|
|
162
|
+
if(commands.includes(source)) {
|
|
163
|
+
await vscode.commands.executeCommand(source);
|
|
164
|
+
} else {
|
|
165
|
+
const uri = vscode.Uri.file(source);
|
|
166
|
+
if(!uri) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
await vscode.commands.executeCommand(
|
|
170
|
+
'vscode.openWith',
|
|
171
|
+
uri,
|
|
172
|
+
viewType,
|
|
173
|
+
vscode.ViewColumn.One
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
return new Promise((resolve) => { // 通过这个返回数据源
|
|
179
|
+
// 首次打开webview
|
|
180
|
+
subscribe('webviewRenderDone', () => {
|
|
181
|
+
pubWithSub('clickAnyElement', args, (data) => {
|
|
182
|
+
resolve(data);
|
|
183
|
+
});
|
|
184
|
+
}, true);
|
|
185
|
+
// 已经打开过webview
|
|
186
|
+
pubWithSub('clickAnyElement', args, (data) => {
|
|
187
|
+
resolve(data);
|
|
188
|
+
});
|
|
189
|
+
openWebview();
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
publish('webviewRenderDone');
|
|
195
|
+
subscribe('clickAnyElement', (data) => {
|
|
196
|
+
const clickAnyElement = async (data: any) => {
|
|
197
|
+
const selectorList = data?.selector;
|
|
198
|
+
let index = 0;
|
|
199
|
+
const timer = setInterval(() => {
|
|
200
|
+
const allDone = index >= (selectorList?.length || 0);
|
|
201
|
+
if(allDone) {
|
|
202
|
+
clearInterval(timer);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const originSelector = selectorList?.[index];
|
|
207
|
+
const i = originSelector?.split('$')[1];
|
|
208
|
+
const selector =originSelector.split('$')[0];
|
|
209
|
+
const element = (window as any).document?.querySelector(selector);
|
|
210
|
+
|
|
211
|
+
if(selector && element) {
|
|
212
|
+
element.dataset['payload'] = data?.payload;
|
|
213
|
+
element?.click();
|
|
214
|
+
index++;
|
|
215
|
+
}
|
|
216
|
+
}, 1000);
|
|
217
|
+
};
|
|
218
|
+
return new Promise((resolve) => {
|
|
219
|
+
window.feedbackResult = resolve;
|
|
220
|
+
clickAnyElement(data);
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
};
|
|
224
|
+
/**
|
|
225
|
+
* key: 唯一key,插件identifier或者消息类型
|
|
226
|
+
* args: 传递的数据
|
|
227
|
+
* {
|
|
228
|
+
* viewType: 要打开的webview的类型
|
|
229
|
+
* source: webview如果是命令打开则是命令ID,如果是则是文件的绝对路径
|
|
230
|
+
* selectorList: 要点击的元素选择器列表
|
|
231
|
+
* }
|
|
232
|
+
* subscribe?: 发布后通过订阅获取反馈数据,如果没有subscribe,则可以通过异步等待获取反馈的数据
|
|
233
|
+
*
|
|
234
|
+
*/
|
|
235
|
+
const pubWithSub = async (
|
|
236
|
+
typename: string,
|
|
237
|
+
msg: any,
|
|
238
|
+
subscriber?: (data: any) => any
|
|
239
|
+
) => {
|
|
240
|
+
publish(typename, msg);
|
|
241
|
+
|
|
242
|
+
return new Promise((resolve) => {
|
|
243
|
+
const removeSubscribe = subscribe(typename, (data: any) => {
|
|
244
|
+
if (subscriber) {
|
|
245
|
+
subscriber(data);
|
|
246
|
+
} else {
|
|
247
|
+
resolve(data);
|
|
248
|
+
}
|
|
249
|
+
removeSubscribe && removeSubscribe();
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
return {
|
|
255
|
+
publish,
|
|
256
|
+
subscribe,
|
|
257
|
+
setCarrier,
|
|
258
|
+
pubWithSub,
|
|
259
|
+
initiator,
|
|
260
|
+
getCarrier: () => cachedCarrier,
|
|
261
|
+
};
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
export default MessageChannel;
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jiangzhongxi0322/messagechannel",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
7
|
"description": "A message channel for communication between VSCode extensions and webviews.",
|
|
8
|
-
"main": "dist/
|
|
9
|
-
"types": "dist/
|
|
8
|
+
"main": "dist/messageChannel.js",
|
|
9
|
+
"types": "dist/messageChannel.d.ts",
|
|
10
10
|
"scripts": {
|
|
11
11
|
"build": "tsc",
|
|
12
12
|
"prepublishOnly": "npm run build"
|