@jiangzhongxi0322/messagechannel 1.0.0 → 1.0.1

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.
Files changed (70) hide show
  1. package/README.md +181 -0
  2. package/dist/messageChannel.d.ts +10 -0
  3. package/dist/{messageChennel.js → messageChannel.js} +25 -8
  4. package/examples/command-webview-sample/.eslintrc.js +23 -0
  5. package/examples/command-webview-sample/.vscode/extensions.json +9 -0
  6. package/examples/command-webview-sample/.vscode/launch.json +18 -0
  7. package/examples/command-webview-sample/.vscode/settings.json +3 -0
  8. package/examples/command-webview-sample/.vscode/tasks.json +20 -0
  9. package/examples/command-webview-sample/README.md +47 -0
  10. package/examples/command-webview-sample/demo.gif +0 -0
  11. package/examples/command-webview-sample/media/cat.gif +0 -0
  12. package/examples/command-webview-sample/media/jsconfig.json +22 -0
  13. package/examples/command-webview-sample/media/main.js +41 -0
  14. package/examples/command-webview-sample/media/reset.css +30 -0
  15. package/examples/command-webview-sample/media/vscode.css +91 -0
  16. package/examples/command-webview-sample/package-lock.json +2764 -0
  17. package/examples/command-webview-sample/package.json +51 -0
  18. package/examples/command-webview-sample/src/extension.ts +227 -0
  19. package/{src/messageChennel.ts → examples/command-webview-sample/src/messageChannel.ts} +34 -21
  20. package/examples/command-webview-sample/tsconfig.json +12 -0
  21. package/examples/publish-webview-sample/.eslintrc.js +20 -0
  22. package/examples/publish-webview-sample/.vscode/extensions.json +9 -0
  23. package/examples/publish-webview-sample/.vscode/launch.json +18 -0
  24. package/examples/publish-webview-sample/.vscode/settings.json +3 -0
  25. package/examples/publish-webview-sample/.vscode/tasks.json +20 -0
  26. package/examples/publish-webview-sample/README.md +24 -0
  27. package/examples/publish-webview-sample/media/main.css +54 -0
  28. package/examples/publish-webview-sample/media/main.js +100 -0
  29. package/examples/publish-webview-sample/media/reset.css +30 -0
  30. package/examples/publish-webview-sample/media/vscode.css +91 -0
  31. package/examples/publish-webview-sample/package-lock.json +2720 -0
  32. package/examples/publish-webview-sample/package.json +71 -0
  33. package/examples/publish-webview-sample/src/extension.ts +170 -0
  34. package/examples/publish-webview-sample/src/messageChannel.ts +264 -0
  35. package/examples/publish-webview-sample/tsconfig.json +12 -0
  36. package/examples/url-webview-sample/.eslintignore +1 -0
  37. package/examples/url-webview-sample/.eslintrc.js +20 -0
  38. package/examples/url-webview-sample/.vscode/extensions.json +9 -0
  39. package/examples/url-webview-sample/.vscode/launch.json +18 -0
  40. package/examples/url-webview-sample/.vscode/settings.json +3 -0
  41. package/examples/url-webview-sample/.vscode/tasks.json +20 -0
  42. package/examples/url-webview-sample/README.md +25 -0
  43. package/examples/url-webview-sample/documentation/example.png +0 -0
  44. package/examples/url-webview-sample/exampleFiles/example.cscratch +14 -0
  45. package/examples/url-webview-sample/exampleFiles/example.pawDraw +0 -0
  46. package/examples/url-webview-sample/exampleFiles/log/python-kaleido-case-api.exe.log +1 -0
  47. package/examples/url-webview-sample/exampleFiles/log/python-request.exe.log +1 -0
  48. package/examples/url-webview-sample/exampleFiles/pump/config/default.json +1 -0
  49. package/examples/url-webview-sample/exampleFiles/test_cases/log/output_202511181702.log +6 -0
  50. package/examples/url-webview-sample/media/catScratch.css +65 -0
  51. package/examples/url-webview-sample/media/catScratch.js +100 -0
  52. package/examples/url-webview-sample/media/paw-color.svg +21 -0
  53. package/examples/url-webview-sample/media/paw-outline.svg +21 -0
  54. package/examples/url-webview-sample/media/pawDraw.css +83 -0
  55. package/examples/url-webview-sample/media/pawDraw.js +266 -0
  56. package/examples/url-webview-sample/media/reset.css +30 -0
  57. package/examples/url-webview-sample/media/sand-dark.jpg +0 -0
  58. package/examples/url-webview-sample/media/sand.jpg +0 -0
  59. package/examples/url-webview-sample/media/vscode.css +91 -0
  60. package/examples/url-webview-sample/package-lock.json +2751 -0
  61. package/examples/url-webview-sample/package.json +64 -0
  62. package/examples/url-webview-sample/src/catScratchEditor.ts +215 -0
  63. package/examples/url-webview-sample/src/dispose.ts +37 -0
  64. package/examples/url-webview-sample/src/extension.ts +7 -0
  65. package/examples/url-webview-sample/src/messageChannel.ts +264 -0
  66. package/examples/url-webview-sample/src/util.ts +8 -0
  67. package/examples/url-webview-sample/tsconfig.json +13 -0
  68. package/package.json +1 -1
  69. package/src/messageChannel.ts +264 -0
  70. package/dist/messageChennel.d.ts +0 -15
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "command-webview-sample",
3
+ "description": "Cat Coding - A Webview API Sample",
4
+ "version": "0.0.5",
5
+ "publisher": "walker",
6
+ "private": true,
7
+ "license": "MIT",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/Microsoft/vscode-extension-samples"
11
+ },
12
+ "engines": {
13
+ "vscode": "^1.74.0"
14
+ },
15
+ "categories": [
16
+ "Other"
17
+ ],
18
+ "activationEvents": [
19
+ "onWebviewPanel:catCoding"
20
+ ],
21
+ "main": "./out/extension.js",
22
+ "contributes": {
23
+ "commands": [
24
+ {
25
+ "command": "catCoding.start",
26
+ "title": "Start cat coding session",
27
+ "category": "Cat Coding"
28
+ },
29
+ {
30
+ "command": "catCoding.doRefactor",
31
+ "title": "Do some refactoring",
32
+ "category": "Cat Coding"
33
+ }
34
+ ]
35
+ },
36
+ "scripts": {
37
+ "vscode:prepublish": "npm run compile",
38
+ "compile": "tsc -p ./",
39
+ "lint": "eslint \"src/**/*.ts\"",
40
+ "watch": "tsc -w -p ./"
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^18",
44
+ "@types/vscode": "^1.73.0",
45
+ "@types/vscode-webview": "^1.57.0",
46
+ "@typescript-eslint/eslint-plugin": "^6.7.0",
47
+ "@typescript-eslint/parser": "^6.7.0",
48
+ "eslint": "^8.26.0",
49
+ "typescript": "^5.4.2"
50
+ }
51
+ }
@@ -0,0 +1,227 @@
1
+ import * as vscode from 'vscode';
2
+ import MessageChannel from './messageChannel';
3
+
4
+ const mc = MessageChannel();
5
+ const cats = {
6
+ 'Coding Cat': 'https://media.giphy.com/media/JIX9t2j0ZTN9S/giphy.gif',
7
+ 'Compiling Cat': 'https://media.giphy.com/media/mlvseq9yvZhba/giphy.gif',
8
+ 'Testing Cat': 'https://media.giphy.com/media/3oriO0OEd9QIDdllqo/giphy.gif'
9
+ };
10
+
11
+ export function activate(context: vscode.ExtensionContext) {
12
+ mc.initiator(CatCodingPanel.viewType);
13
+ context.subscriptions.push(
14
+ vscode.commands.registerCommand('catCoding.start', () => {
15
+ CatCodingPanel.createOrShow(context.extensionUri);
16
+ mc.setCarrier((CatCodingPanel.currentPanel as any)._panel.webview);
17
+ })
18
+ );
19
+
20
+ if (vscode.window.registerWebviewPanelSerializer) {
21
+ // Make sure we register a serializer in activation event
22
+ vscode.window.registerWebviewPanelSerializer(CatCodingPanel.viewType, {
23
+ async deserializeWebviewPanel(webviewPanel: vscode.WebviewPanel, state: any) {
24
+ console.log(`Got state: ${state}`);
25
+ // Reset the webview options so we use latest uri for `localResourceRoots`.
26
+ webviewPanel.webview.options = getWebviewOptions(context.extensionUri);
27
+ CatCodingPanel.revive(webviewPanel, context.extensionUri);
28
+ }
29
+ });
30
+ }
31
+ }
32
+
33
+ function getWebviewOptions(extensionUri: vscode.Uri): vscode.WebviewOptions {
34
+ return {
35
+ // Enable javascript in the webview
36
+ enableScripts: true,
37
+
38
+ // And restrict the webview to only loading content from our extension's `media` directory.
39
+ localResourceRoots: [vscode.Uri.joinPath(extensionUri, 'media')]
40
+ };
41
+ }
42
+
43
+ /**
44
+ * Manages cat coding webview panels
45
+ */
46
+ class CatCodingPanel {
47
+ /**
48
+ * Track the currently panel. Only allow a single panel to exist at a time.
49
+ */
50
+ public static currentPanel: CatCodingPanel | undefined;
51
+
52
+ public static readonly viewType = 'catCoding';
53
+
54
+ private readonly _panel: vscode.WebviewPanel;
55
+ private readonly _extensionUri: vscode.Uri;
56
+ private _disposables: vscode.Disposable[] = [];
57
+
58
+ public static createOrShow(extensionUri: vscode.Uri) {
59
+ const column = vscode.window.activeTextEditor
60
+ ? vscode.window.activeTextEditor.viewColumn
61
+ : undefined;
62
+
63
+ // If we already have a panel, show it.
64
+ if (CatCodingPanel.currentPanel) {
65
+ CatCodingPanel.currentPanel._panel.reveal(column);
66
+ return;
67
+ }
68
+
69
+ // Otherwise, create a new panel.
70
+ const panel = vscode.window.createWebviewPanel(
71
+ CatCodingPanel.viewType,
72
+ 'Cat Coding',
73
+ column || vscode.ViewColumn.One,
74
+ getWebviewOptions(extensionUri),
75
+ );
76
+
77
+ CatCodingPanel.currentPanel = new CatCodingPanel(panel, extensionUri);
78
+ }
79
+
80
+ public static revive(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) {
81
+ CatCodingPanel.currentPanel = new CatCodingPanel(panel, extensionUri);
82
+ }
83
+
84
+ private constructor(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) {
85
+ this._panel = panel;
86
+ this._extensionUri = extensionUri;
87
+
88
+ // Set the webview's initial html content
89
+ this._update();
90
+
91
+ // Listen for when the panel is disposed
92
+ // This happens when the user closes the panel or when the panel is closed programmatically
93
+ this._panel.onDidDispose(() => this.dispose(), null, this._disposables);
94
+
95
+ // Update the content based on view changes
96
+ this._panel.onDidChangeViewState(
97
+ e => {
98
+ if (this._panel.visible) {
99
+ this._update();
100
+ }
101
+ },
102
+ null,
103
+ this._disposables
104
+ );
105
+
106
+ // Handle messages from the webview
107
+ this._panel.webview.onDidReceiveMessage(
108
+ message => {
109
+ switch (message.command) {
110
+ case 'alert':
111
+ vscode.window.showErrorMessage(message.text);
112
+ return;
113
+ }
114
+ },
115
+ null,
116
+ this._disposables
117
+ );
118
+ }
119
+
120
+ public doRefactor() {
121
+ // Send a message to the webview webview.
122
+ // You can send any JSON serializable data.
123
+ this._panel.webview.postMessage({ command: 'refactor' });
124
+ }
125
+
126
+ public dispose() {
127
+ CatCodingPanel.currentPanel = undefined;
128
+
129
+ // Clean up our resources
130
+ this._panel.dispose();
131
+
132
+ while (this._disposables.length) {
133
+ const x = this._disposables.pop();
134
+ if (x) {
135
+ x.dispose();
136
+ }
137
+ }
138
+ }
139
+
140
+ private _update() {
141
+ const webview = this._panel.webview;
142
+
143
+ // Vary the webview's content based on where it is located in the editor.
144
+ switch (this._panel.viewColumn) {
145
+ case vscode.ViewColumn.Two:
146
+ this._updateForCat(webview, 'Compiling Cat');
147
+ return;
148
+
149
+ case vscode.ViewColumn.Three:
150
+ this._updateForCat(webview, 'Testing Cat');
151
+ return;
152
+
153
+ case vscode.ViewColumn.One:
154
+ default:
155
+ this._updateForCat(webview, 'Coding Cat');
156
+ return;
157
+ }
158
+ }
159
+
160
+ private _updateForCat(webview: vscode.Webview, catName: keyof typeof cats) {
161
+ this._panel.title = catName;
162
+ this._panel.webview.html = this._getHtmlForWebview(webview, cats[catName]);
163
+ }
164
+
165
+ private _getHtmlForWebview(webview: vscode.Webview, catGifPath: string) {
166
+ // Local path to main script run in the webview
167
+ const scriptPathOnDisk = vscode.Uri.joinPath(this._extensionUri, 'media', 'main.js');
168
+
169
+ // And the uri we use to load this script in the webview
170
+ const scriptUri = webview.asWebviewUri(scriptPathOnDisk);
171
+
172
+ // Local path to css styles
173
+ const styleResetPath = vscode.Uri.joinPath(this._extensionUri, 'media', 'reset.css');
174
+ const stylesPathMainPath = vscode.Uri.joinPath(this._extensionUri, 'media', 'vscode.css');
175
+
176
+ // Uri to load styles into webview
177
+ const stylesResetUri = webview.asWebviewUri(styleResetPath);
178
+ const stylesMainUri = webview.asWebviewUri(stylesPathMainPath);
179
+
180
+ // Use a nonce to only allow specific scripts to be run
181
+ const nonce = getNonce();
182
+
183
+ return `<!DOCTYPE html>
184
+ <html lang="en">
185
+ <head>
186
+ <meta charset="UTF-8">
187
+
188
+ <!--
189
+ Use a content security policy to only allow loading images from https or from our extension directory,
190
+ and only allow scripts that have a specific nonce.
191
+ -->
192
+ <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src ${webview.cspSource}; img-src ${webview.cspSource} https:; script-src 'nonce-${nonce}';">
193
+
194
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
195
+
196
+ <link href="${stylesResetUri}" rel="stylesheet">
197
+ <link href="${stylesMainUri}" rel="stylesheet">
198
+
199
+ <title>Cat Coding</title>
200
+ </head>
201
+ <body>
202
+ 此处输入需要反馈的数据:<input style="border: 1px solid #ccc; padding: 4px; border-radius: 4px;" placeholder="请输入反馈内容"/>
203
+ <button>反馈</button>
204
+
205
+ <script nonce="${nonce}">
206
+ const result = document.querySelector('input').value;
207
+ document.querySelector('button').addEventListener('click', (args) => {
208
+ const result = document.querySelector('input').value;
209
+ feedbackResult && feedbackResult(result);
210
+ });
211
+ window.mc = (${MessageChannel.toString()})();
212
+ window.mc.setCarrier();
213
+ window.mc.initiator();
214
+ </script>
215
+ </body>
216
+ </html>`;
217
+ }
218
+ }
219
+
220
+ function getNonce() {
221
+ let text = '';
222
+ const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
223
+ for (let i = 0; i < 32; i++) {
224
+ text += possible.charAt(Math.floor(Math.random() * possible.length));
225
+ }
226
+ return text;
227
+ }
@@ -4,22 +4,24 @@ interface Event {
4
4
  typename?: string;
5
5
  key?: string;
6
6
  channelId: string;
7
- data: FeedbackData;
8
- }
9
- interface FeedbackData {
10
- code: 0 | 1 | 2;
11
- msg: string;
12
7
  data: any;
13
8
  }
9
+
14
10
  // 每个vscode的node端和webview都分别拥有一个MessageChannel返回的对象,因为他们是不同载体
15
11
  // 同一webview如果打开了多个文档,各个文档也应该有不同的载体
16
12
  declare const window: any;
17
13
 
18
14
  const MessageChannel = () => {
19
- let cachedCarrier: vscode.Webview;
15
+ let cachedCarrier: vscode.Webview | null;
20
16
  let dispose: vscode.Disposable;
21
17
 
22
- const setCarrier = (carrier: any) => {
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) => {
23
25
  if (carrier === undefined) {
24
26
  cachedCarrier = (window as any).acquireVsCodeApi();
25
27
  (window as any).addEventListener('message', (event: any) => {
@@ -31,7 +33,7 @@ const MessageChannel = () => {
31
33
  dispose.dispose();
32
34
  }
33
35
  cachedCarrier = carrier;
34
- if (carrier === null) {
36
+ if (cachedCarrier === null) {
35
37
  return;
36
38
  }
37
39
  dispose = cachedCarrier.onDidReceiveMessage((event) =>
@@ -44,16 +46,15 @@ const MessageChannel = () => {
44
46
  } = {};
45
47
 
46
48
  const messageHandler = async (event: Event) => {
47
- const { data: feedbackData, typename } = event;
48
- const data = feedbackData.data;
49
+ const { data, typename } = event;
49
50
  const isTalkInExtension = typename && subscribers[typename];
50
51
  if (isTalkInExtension) {
51
52
  subscribers[typename as string].forEach((resolver) => {
52
- resolver(feedbackData);
53
+ resolver(data);
53
54
  });
54
55
  return;
55
56
  }
56
- const isTalkToExtension = typename && data?.viewType;
57
+ const isTalkToExtension = typename && (data as any)?.viewType;
57
58
  if(isTalkToExtension) {
58
59
  const activeTargetExtension = async (extensionId: string) => {
59
60
  const targetExtension = vscode.extensions.getExtension(extensionId);
@@ -86,15 +87,20 @@ const MessageChannel = () => {
86
87
  }
87
88
 
88
89
  };
90
+ /**
91
+ * typename: 消息类型,消息的发布和订阅都依赖这个typename
92
+ * subscriber:收到消息后把消息传递给subscriber
93
+ * once:一次性订阅,收到消息后就把订阅者移除
94
+ */
89
95
  const subscribe = (
90
96
  typename: string,
91
- subscriber: (data: FeedbackData) => any,
97
+ subscriber: (data: any) => any,
92
98
  once = false
93
99
  ) => {
94
100
  if (!subscriber || !(subscriber instanceof Function)) {
95
101
  return;
96
102
  }
97
- const resolver = (data: FeedbackData) => {
103
+ const resolver = (data: any) => {
98
104
  const result = subscriber(data);
99
105
  if (result !== undefined) {
100
106
  if (result instanceof Promise) {
@@ -128,18 +134,25 @@ const MessageChannel = () => {
128
134
  };
129
135
  };
130
136
 
131
- const publish = (typename: string, msg?: any) => {
137
+ /**
138
+ * typename: 消息类型,消息的发布和订阅都依赖这个typename
139
+ * msg:消息发布时带的参数
140
+ */
141
+ const publish = (typename: string, data?: any) => {
132
142
  try {
133
143
  cachedCarrier?.postMessage({
134
144
  typename: typename,
135
- data: msg,
145
+ data: data,
136
146
  });
137
147
  } catch (error) {0;}
138
148
  };
139
149
 
140
150
 
141
- // vscode.WebviewViewProvider的静态方法中调用
142
- const initiator = (viewType: string) => {
151
+ /**
152
+ * 如果要唤醒其余插件的webview,则双方插件的provider、web都要调用这个函数初始化
153
+ * viewType:provider传递WebviewProvieder的viewType,web则不用传递参数
154
+ */
155
+ const initiator = (viewType?: string) => {
143
156
  // for node
144
157
  if(viewType) {
145
158
  vscode.commands.registerCommand(`to_${viewType}`, async (args) => {
@@ -178,7 +191,7 @@ const MessageChannel = () => {
178
191
  });
179
192
  return;
180
193
  }
181
- publish('webviewRenderDone', null);
194
+ publish('webviewRenderDone');
182
195
  subscribe('clickAnyElement', (data) => {
183
196
  const clickAnyElement = async (data: any) => {
184
197
  const selectorList = data?.selector;
@@ -222,12 +235,12 @@ const MessageChannel = () => {
222
235
  const pubWithSub = async (
223
236
  typename: string,
224
237
  msg: any,
225
- subscriber?: (data: FeedbackData) => any
238
+ subscriber?: (data: any) => any
226
239
  ) => {
227
240
  publish(typename, msg);
228
241
 
229
242
  return new Promise((resolve) => {
230
- const removeSubscribe = subscribe(typename, (data: FeedbackData) => {
243
+ const removeSubscribe = subscribe(typename, (data: any) => {
231
244
  if (subscriber) {
232
245
  subscriber(data);
233
246
  } else {
@@ -0,0 +1,12 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "commonjs",
4
+ "target": "es2020",
5
+ "lib": ["es2020", "dom"],
6
+ "outDir": "out",
7
+ "sourceMap": true,
8
+ "strict": true,
9
+ "rootDir": "src"
10
+ },
11
+ "exclude": ["node_modules", ".vscode-test"]
12
+ }
@@ -0,0 +1,20 @@
1
+ /**@type {import('eslint').Linter.Config} */
2
+ // eslint-disable-next-line no-undef
3
+ module.exports = {
4
+ root: true,
5
+ parser: '@typescript-eslint/parser',
6
+ plugins: [
7
+ '@typescript-eslint',
8
+ ],
9
+ extends: [
10
+ 'eslint:recommended',
11
+ 'plugin:@typescript-eslint/recommended',
12
+ ],
13
+ rules: {
14
+ 'semi': [2, "always"],
15
+ '@typescript-eslint/no-unused-vars': 0,
16
+ '@typescript-eslint/no-explicit-any': 0,
17
+ '@typescript-eslint/explicit-module-boundary-types': 0,
18
+ '@typescript-eslint/no-non-null-assertion': 0,
19
+ }
20
+ };
@@ -0,0 +1,9 @@
1
+ {
2
+ // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
3
+ // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
4
+
5
+ // List of extensions which should be recommended for users of this workspace.
6
+ "recommendations": [
7
+ "dbaeumer.vscode-eslint"
8
+ ]
9
+ }
@@ -0,0 +1,18 @@
1
+ // A launch configuration that compiles the extension and then opens it inside a new window
2
+ // Use IntelliSense to learn about possible attributes.
3
+ // Hover to view descriptions of existing attributes.
4
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
+ {
6
+ "version": "0.2.0",
7
+ "configurations": [
8
+ {
9
+ "name": "Run Extension",
10
+ "type": "extensionHost",
11
+ "request": "launch",
12
+ "runtimeExecutable": "${execPath}",
13
+ "args": ["--extensionDevelopmentPath=${workspaceRoot}"],
14
+ "outFiles": ["${workspaceFolder}/out/**/*.js"],
15
+ "preLaunchTask": "npm: watch"
16
+ }
17
+ ]
18
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "editor.insertSpaces": false
3
+ }
@@ -0,0 +1,20 @@
1
+ // See https://go.microsoft.com/fwlink/?LinkId=733558
2
+ // for the documentation about the tasks.json format
3
+ {
4
+ "version": "2.0.0",
5
+ "tasks": [
6
+ {
7
+ "type": "npm",
8
+ "script": "watch",
9
+ "problemMatcher": "$tsc-watch",
10
+ "isBackground": true,
11
+ "presentation": {
12
+ "reveal": "never"
13
+ },
14
+ "group": {
15
+ "kind": "build",
16
+ "isDefault": true
17
+ }
18
+ }
19
+ ]
20
+ }
@@ -0,0 +1,24 @@
1
+ # Calico Colors — Webview View API Sample
2
+
3
+ Demonstrates VS Code's [webview view API](https://github.com/microsoft/vscode/issues/46585). This includes:
4
+
5
+ - Contributing a webview based view to the explorer.
6
+ - Posting messages from an extension to a webview view
7
+ - Posting message from a webview to an extension
8
+ - Persisting state in the view.
9
+ - Contributing commands to the view title.
10
+
11
+ ## VS Code API
12
+
13
+ ### `vscode` module
14
+
15
+ - [`window.registerWebviewViewProvider`](https://code.visualstudio.com/api/references/vscode-api#window.registerWebviewViewProvider)
16
+
17
+ ## Running the example
18
+
19
+ - Open this example in VS Code 1.49+
20
+ - `npm install`
21
+ - `npm run watch` or `npm run compile`
22
+ - `F5` to start debugging
23
+
24
+ In the explorer, expand the `Calico Colors` view.
@@ -0,0 +1,54 @@
1
+ body {
2
+ background-color: transparent;
3
+ }
4
+
5
+ .color-list {
6
+ list-style: none;
7
+ padding: 0;
8
+ }
9
+
10
+ .color-entry {
11
+ width: 100%;
12
+ display: flex;
13
+ margin-bottom: 0.4em;
14
+ border: 1px solid var(--vscode-input-border);
15
+ }
16
+
17
+ .color-preview {
18
+ width: 2em;
19
+ height: 2em;
20
+ }
21
+
22
+ .color-preview:hover {
23
+ outline: inset white;
24
+ }
25
+
26
+ .color-input {
27
+ display: block;
28
+ flex: 1;
29
+ width: 100%;
30
+ color: var(--vscode-input-foreground);
31
+ background-color: var(--vscode-input-background);
32
+ border: none;
33
+ padding: 0 0.6em;
34
+ }
35
+
36
+ .add-color-button {
37
+ display: block;
38
+ border: none;
39
+ margin: 0 auto;
40
+ }
41
+ .command-webview {
42
+ border-top: 1px solid #3c3c3c;
43
+ margin-top: 15px;
44
+ }
45
+ h2 {
46
+ font-weight: bold;
47
+ }
48
+ .send-message {
49
+ margin-top: 16px;
50
+ display: flex;
51
+ }
52
+ .response-message {
53
+ display: flex;
54
+ }
@@ -0,0 +1,100 @@
1
+ //@ts-check
2
+
3
+ // This script will be run within the webview itself
4
+ // It cannot access the main VS Code APIs directly.
5
+ (function () {
6
+ const vscode = acquireVsCodeApi();
7
+
8
+ const oldState = vscode.getState() || { colors: [] };
9
+
10
+ /** @type {Array<{ value: string }>} */
11
+ let colors = oldState.colors;
12
+
13
+ updateColorList(colors);
14
+
15
+ document.querySelector('.add-color-button').addEventListener('click', () => {
16
+ addColor();
17
+ });
18
+
19
+ // Handle messages sent from the extension to the webview
20
+ window.addEventListener('message', event => {
21
+ const message = event.data; // The json data that the extension sent
22
+ switch (message.type) {
23
+ case 'addColor':
24
+ {
25
+ addColor();
26
+ break;
27
+ }
28
+ case 'clearColors':
29
+ {
30
+ colors = [];
31
+ updateColorList(colors);
32
+ break;
33
+ }
34
+
35
+ }
36
+ });
37
+
38
+ /**
39
+ * @param {Array<{ value: string }>} colors
40
+ */
41
+ function updateColorList(colors) {
42
+ const ul = document.querySelector('.color-list');
43
+ ul.textContent = '';
44
+ for (const color of colors) {
45
+ const li = document.createElement('li');
46
+ li.className = 'color-entry';
47
+
48
+ const colorPreview = document.createElement('div');
49
+ colorPreview.className = 'color-preview';
50
+ colorPreview.style.backgroundColor = `#${color.value}`;
51
+ colorPreview.addEventListener('click', () => {
52
+ onColorClicked(color.value);
53
+ });
54
+ li.appendChild(colorPreview);
55
+
56
+ const input = document.createElement('input');
57
+ input.className = 'color-input';
58
+ input.type = 'text';
59
+ input.value = color.value;
60
+ input.addEventListener('change', (e) => {
61
+ const value = e.target.value;
62
+ if (!value) {
63
+ // Treat empty value as delete
64
+ colors.splice(colors.indexOf(color), 1);
65
+ } else {
66
+ color.value = value;
67
+ }
68
+ updateColorList(colors);
69
+ });
70
+ li.appendChild(input);
71
+
72
+ ul.appendChild(li);
73
+ }
74
+
75
+ // Update the saved state
76
+ vscode.setState({ colors: colors });
77
+ }
78
+
79
+ /**
80
+ * @param {string} color
81
+ */
82
+ function onColorClicked(color) {
83
+ vscode.postMessage({ type: 'colorSelected', value: color });
84
+ }
85
+
86
+ /**
87
+ * @returns string
88
+ */
89
+ function getNewCalicoColor() {
90
+ const colors = ['020202', 'f1eeee', 'a85b20', 'daab70', 'efcb99'];
91
+ return colors[Math.floor(Math.random() * colors.length)];
92
+ }
93
+
94
+ function addColor() {
95
+ colors.push({ value: getNewCalicoColor() });
96
+ updateColorList(colors);
97
+ }
98
+ }());
99
+
100
+