@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.
- 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 +1 -1
- package/src/messageChannel.ts +264 -0
- package/dist/messageChennel.d.ts +0 -15
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
body {
|
|
2
|
+
justify-content: center;
|
|
3
|
+
align-items: center;
|
|
4
|
+
margin: 1em 2em;
|
|
5
|
+
background-image: url(./sand.jpg);
|
|
6
|
+
background-repeat: repeat;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
body.vscode-dark {
|
|
10
|
+
background-image: url(./sand-dark.jpg);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.notes {
|
|
14
|
+
display: grid;
|
|
15
|
+
grid-template-columns: repeat(auto-fill, 100px);
|
|
16
|
+
grid-template-rows: repeat(auto-fill, 100px);
|
|
17
|
+
grid-gap: 2em;
|
|
18
|
+
justify-content: center;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.note {
|
|
22
|
+
display: flex;
|
|
23
|
+
flex-direction: column;
|
|
24
|
+
border-radius: 5px;
|
|
25
|
+
background-color: var(--vscode-editor-background);
|
|
26
|
+
text-align: center;
|
|
27
|
+
padding: 0.6em;
|
|
28
|
+
position: relative;
|
|
29
|
+
overflow: hidden;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.note .text {
|
|
33
|
+
flex: 1;
|
|
34
|
+
font-size: 3em;
|
|
35
|
+
display: flex;
|
|
36
|
+
justify-content: center;
|
|
37
|
+
align-items: center;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.note .created {
|
|
41
|
+
font-style: italic;
|
|
42
|
+
font-size: 0.75em;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.add-button {
|
|
46
|
+
height: 100px;
|
|
47
|
+
display: flex;
|
|
48
|
+
justify-content: center;
|
|
49
|
+
align-items: center;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.delete-button {
|
|
53
|
+
position: absolute;
|
|
54
|
+
top: 0;
|
|
55
|
+
right: 0;
|
|
56
|
+
display: none;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.delete-button:before {
|
|
60
|
+
content: 'delete';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.note:hover .delete-button {
|
|
64
|
+
display: block;
|
|
65
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
// Script run within the webview itself.
|
|
4
|
+
(function () {
|
|
5
|
+
|
|
6
|
+
// Get a reference to the VS Code webview api.
|
|
7
|
+
// We use this API to post messages back to our extension.
|
|
8
|
+
|
|
9
|
+
// @ts-ignore
|
|
10
|
+
const vscode = acquireVsCodeApi();
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
const notesContainer = /** @type {HTMLElement} */ (document.querySelector('.notes'));
|
|
14
|
+
|
|
15
|
+
const addButtonContainer = document.querySelector('.add-button');
|
|
16
|
+
addButtonContainer.querySelector('button').addEventListener('click', () => {
|
|
17
|
+
vscode.postMessage({
|
|
18
|
+
type: 'add'
|
|
19
|
+
});
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
const errorContainer = document.createElement('div');
|
|
23
|
+
document.body.appendChild(errorContainer);
|
|
24
|
+
errorContainer.className = 'error'
|
|
25
|
+
errorContainer.style.display = 'none'
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Render the document in the webview.
|
|
29
|
+
*/
|
|
30
|
+
function updateContent(/** @type {string} */ text) {
|
|
31
|
+
let json;
|
|
32
|
+
try {
|
|
33
|
+
if (!text) {
|
|
34
|
+
text = '{}';
|
|
35
|
+
}
|
|
36
|
+
json = JSON.parse(text);
|
|
37
|
+
} catch {
|
|
38
|
+
notesContainer.style.display = 'none';
|
|
39
|
+
errorContainer.innerText = 'Error: Document is not valid json';
|
|
40
|
+
errorContainer.style.display = '';
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
notesContainer.style.display = '';
|
|
44
|
+
errorContainer.style.display = 'none';
|
|
45
|
+
|
|
46
|
+
// Render the scratches
|
|
47
|
+
notesContainer.innerHTML = '';
|
|
48
|
+
for (const note of json.scratches || []) {
|
|
49
|
+
const element = document.createElement('div');
|
|
50
|
+
element.className = 'note';
|
|
51
|
+
notesContainer.appendChild(element);
|
|
52
|
+
|
|
53
|
+
const text = document.createElement('div');
|
|
54
|
+
text.className = 'text';
|
|
55
|
+
const textContent = document.createElement('span');
|
|
56
|
+
textContent.innerText = note.text;
|
|
57
|
+
text.appendChild(textContent);
|
|
58
|
+
element.appendChild(text);
|
|
59
|
+
|
|
60
|
+
const created = document.createElement('div');
|
|
61
|
+
created.className = 'created';
|
|
62
|
+
created.innerText = new Date(note.created).toUTCString();
|
|
63
|
+
element.appendChild(created);
|
|
64
|
+
|
|
65
|
+
const deleteButton = document.createElement('button');
|
|
66
|
+
deleteButton.className = 'delete-button';
|
|
67
|
+
deleteButton.addEventListener('click', () => {
|
|
68
|
+
vscode.postMessage({ type: 'delete', id: note.id, });
|
|
69
|
+
});
|
|
70
|
+
element.appendChild(deleteButton);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
notesContainer.appendChild(addButtonContainer);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Handle messages sent from the extension to the webview
|
|
77
|
+
window.addEventListener('message', event => {
|
|
78
|
+
const message = event.data; // The json data that the extension sent
|
|
79
|
+
switch (message.type) {
|
|
80
|
+
case 'update':
|
|
81
|
+
const text = message.text;
|
|
82
|
+
|
|
83
|
+
// Update our webview's content
|
|
84
|
+
updateContent(text);
|
|
85
|
+
|
|
86
|
+
// Then persist state information.
|
|
87
|
+
// This state is returned in the call to `vscode.getState` below when a webview is reloaded.
|
|
88
|
+
vscode.setState({ text });
|
|
89
|
+
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Webviews are normally torn down when not visible and re-created when they become visible again.
|
|
95
|
+
// State lets us save information across these re-loads
|
|
96
|
+
const state = vscode.getState();
|
|
97
|
+
if (state) {
|
|
98
|
+
updateContent(state.text);
|
|
99
|
+
}
|
|
100
|
+
}());
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<!-- Generator: Adobe Illustrator 24.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
|
3
|
+
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
4
|
+
viewBox="0 0 40 50" style="enable-background:new 0 0 40 50;" xml:space="preserve">
|
|
5
|
+
<style type="text/css">
|
|
6
|
+
</style>
|
|
7
|
+
<g class="st0">
|
|
8
|
+
<g>
|
|
9
|
+
<path d="M16.5,2.2c-1.4,0-2.6,0.5-3.8,1.2c-0.2-0.9-0.1-1.7,0.4-2.5c0.2-0.4,0.7-0.4,1.1-0.1C15,1.3,15.7,1.8,16.5,2.2z"/>
|
|
10
|
+
<path d="M6.5,10c-0.9,0.4-1.5,1.2-2.3,1.8C4,11,3.7,10.3,3.6,9.6s0.2-1,1-0.8C5.3,9.1,5.9,9.5,6.5,10z"/>
|
|
11
|
+
<path d="M29.2,3.4c-0.8-0.3-1.6-0.5-2.5-0.8c0-0.1,0.1-0.1,0.1-0.2c0.6-0.5,1.2-1.6,1.9-1.3C29.6,1.5,29.1,2.6,29.2,3.4z"/>
|
|
12
|
+
<path d="M36.2,11.9c-0.3-0.6-0.7-1.2-1-1.7c0.5-0.4,1-1.1,1.6-0.7c0.7,0.5-0.1,1.1-0.2,1.7C36.5,11.4,36.3,11.6,36.2,11.9z"/>
|
|
13
|
+
<path d="M21.1,15.1c3.1,0.1,5.2,1.8,6.4,4.5c0.3,0.7,0.5,1.4,0.7,2.1c0.8,3.2-1.8,5.8-5,4.9c-1.4-0.4-2.7-0.6-4.1-0.3
|
|
14
|
+
c-0.9,0.2-1.7,0.1-2.6-0.3c-3.3-1.3-4.1-4-2-6.9c1.3-1.7,2.7-3.2,4.9-3.9C20,15.2,20.5,15.1,21.1,15.1z"/>
|
|
15
|
+
<path d="M15.6,15.6c0,1.9-1.6,3.5-3.5,3.5c-1.7,0-3.2-1.4-3.2-2.9c0-2.2,1.6-4,3.6-4C14.2,12.2,15.6,13.8,15.6,15.6z"/>
|
|
16
|
+
<path d="M17.7,13.1c-2,0-3.2-1-3.2-2.8c0-2.6,0.9-3.8,3-3.8c2,0,3.5,1.4,3.5,3.3C21.1,11.9,19.9,13.1,17.7,13.1z"/>
|
|
17
|
+
<path d="M27.8,10.6c0,1.8-1.2,3-3.1,3c-1.6,0-2.9-1.7-2.9-3.7c0-1.7,1.1-2.8,2.8-2.8C26.6,7.1,27.8,8.4,27.8,10.6z"/>
|
|
18
|
+
<path d="M32.5,16c0,1.7-1.1,2.9-2.6,2.8c-1.6-0.1-3-1.5-2.9-3.2c0-1.7,1.1-2.7,2.8-2.7C31.6,13,32.6,14.1,32.5,16z"/>
|
|
19
|
+
</g>
|
|
20
|
+
</g>
|
|
21
|
+
</svg>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<!-- Generator: Adobe Illustrator 24.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
|
3
|
+
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
4
|
+
viewBox="0 0 40 50" style="enable-background:new 0 0 40 50;" xml:space="preserve">
|
|
5
|
+
<style type="text/css">
|
|
6
|
+
</style>
|
|
7
|
+
<g class="st0">
|
|
8
|
+
<path d="M6.5,10c0.9-0.4,1.8-0.5,2.8-0.5c0.8,0,1.1-0.2,1-1c-0.2-2.2,0.8-3.8,2.4-5c1.2-0.8,2.4-1.2,3.8-1.2c1.6-0.1,3,0.5,4.2,1.5
|
|
9
|
+
c0.5,0.5,0.9,0.4,1.5,0c1.3-1,2.9-1,4.5-1.1c0.8,0.3,1.6,0.5,2.5,0.8c1.4,1,2.2,2.3,2.4,4c0.1,0.5,0.2,0.7,0.7,0.9
|
|
10
|
+
c1.2,0.3,2,1.1,3,1.8c0.3,0.6,0.7,1.2,1,1.7c0.6,2.5,1.1,4.9,0.1,7.4c-0.5,1.2-1.2,2.2-2.5,2.8c-0.7,0.3-1,0.8-1.2,1.5
|
|
11
|
+
c-0.5,2.1-1.3,4-1.7,6.1c-0.1,0.7-0.4,1.4-1,1.9c-1.1,1-1.4,2.4-1.4,3.8c-0.2,4.7,6.7,10.8-2.2,13.5c-5.8,0-13.6,0.9-15.1-2.2
|
|
12
|
+
c-1.7-3.7,0-4.7,0-8.8c0-2.2-0.3-4.3-1.9-6.1c-0.8-0.9-0.9-2.2-0.9-3.4c0-1.1-0.4-1.8-1.1-2.5C4.7,23.2,3.5,20,3,16.4
|
|
13
|
+
c-0.2-1.7,0.2-3.2,1.1-4.6C5,11.2,5.6,10.4,6.5,10z M21.1,15.1c-0.6,0-1.1,0.1-1.6,0.2c-2.1,0.6-3.6,2.1-4.9,3.9
|
|
14
|
+
c-2.1,2.8-1.3,5.6,2,6.9c0.8,0.3,1.7,0.4,2.6,0.3c1.4-0.2,2.7-0.1,4.1,0.3c3.2,0.9,5.8-1.6,5-4.9c-0.2-0.7-0.4-1.5-0.7-2.1
|
|
15
|
+
C26.2,16.9,24.2,15.2,21.1,15.1z M15.6,15.6c0-1.8-1.4-3.4-3.1-3.5c-2,0-3.6,1.8-3.6,4c0,1.6,1.5,2.9,3.2,2.9
|
|
16
|
+
C14,19.1,15.5,17.6,15.6,15.6z M17.7,13.1c2.1,0,3.3-1.2,3.3-3.4c0-1.9-1.5-3.3-3.5-3.3c-2.1,0-3,1.2-3,3.8
|
|
17
|
+
C14.6,12.1,15.7,13.1,17.7,13.1z M27.8,10.6c0-2.1-1.2-3.4-3.2-3.4c-1.7,0-2.7,1-2.8,2.8c0,2.1,1.3,3.7,2.9,3.7
|
|
18
|
+
C26.5,13.6,27.8,12.4,27.8,10.6z M32.5,16c0-1.9-1-3-2.7-3.1c-1.7,0-2.8,1-2.8,2.7c0,1.6,1.3,3.1,2.9,3.2
|
|
19
|
+
C31.4,18.9,32.5,17.7,32.5,16z"/>
|
|
20
|
+
</g>
|
|
21
|
+
</svg>
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
html, body {
|
|
2
|
+
height: 100%;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.drawing-canvas {
|
|
6
|
+
width: 100%;
|
|
7
|
+
height: 100%;
|
|
8
|
+
flex: 1;
|
|
9
|
+
display: flex;
|
|
10
|
+
justify-content: center;
|
|
11
|
+
align-items: center;
|
|
12
|
+
background-repeat: repeat;
|
|
13
|
+
flex-direction: column;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.drawing-controls {
|
|
17
|
+
position: fixed;
|
|
18
|
+
bottom: 0;
|
|
19
|
+
left: 0;
|
|
20
|
+
width: 100%;
|
|
21
|
+
display: flex;
|
|
22
|
+
justify-content: center;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.drawing-controls button {
|
|
26
|
+
position: relative;
|
|
27
|
+
width: 100px;
|
|
28
|
+
height: 100px;
|
|
29
|
+
background: none;
|
|
30
|
+
border: none;
|
|
31
|
+
transform: translateY(30%);
|
|
32
|
+
transition: transform 0.1s linear;
|
|
33
|
+
outline: none;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.drawing-controls button:disabled {
|
|
37
|
+
opacity: 0.5;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.drawing-controls button.active:not(:disabled),
|
|
41
|
+
.drawing-controls button:hover:not(:disabled) {
|
|
42
|
+
transform: translateY(10%);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.drawing-controls button:before,
|
|
46
|
+
.drawing-controls button:after {
|
|
47
|
+
display: block;
|
|
48
|
+
content: '';
|
|
49
|
+
position: absolute;
|
|
50
|
+
top: 0;
|
|
51
|
+
left: 0;
|
|
52
|
+
width: 100%;
|
|
53
|
+
height: 100%;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.drawing-controls button:before {
|
|
57
|
+
-webkit-mask: url("./paw-color.svg") no-repeat 50% 50%;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.drawing-controls button:after {
|
|
61
|
+
background-color: #111;
|
|
62
|
+
-webkit-mask: url("./paw-outline.svg") no-repeat 50% 50%;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.drawing-controls button.black:before {
|
|
66
|
+
background-color: #333;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.drawing-controls button.white:before {
|
|
70
|
+
background-color: white;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.drawing-controls button.red:before {
|
|
74
|
+
background-color: red;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.drawing-controls button.green:before {
|
|
78
|
+
background-color: green;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.drawing-controls button.blue:before {
|
|
82
|
+
background-color: blue;
|
|
83
|
+
}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
// This script is run within the webview itself
|
|
4
|
+
(function () {
|
|
5
|
+
// @ts-ignore
|
|
6
|
+
const vscode = acquireVsCodeApi();
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A drawn line.
|
|
10
|
+
*/
|
|
11
|
+
class Stroke {
|
|
12
|
+
constructor(/** @type {string} */ color, /** @type {Array<[number, number]> | undefined} */ stroke) {
|
|
13
|
+
this.color = color;
|
|
14
|
+
/** @type {Array<[number, number]>} */
|
|
15
|
+
this.stroke = stroke || [];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
addPoint(/** @type {number} */ x, /** @type {number} */ y) {
|
|
19
|
+
this.stroke.push([x, y])
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param {Uint8Array} initialContent
|
|
25
|
+
* @return {Promise<HTMLImageElement>}
|
|
26
|
+
*/
|
|
27
|
+
async function loadImageFromData(initialContent) {
|
|
28
|
+
const blob = new Blob([initialContent], { 'type': 'image/png' });
|
|
29
|
+
const url = URL.createObjectURL(blob);
|
|
30
|
+
try {
|
|
31
|
+
const img = document.createElement('img');
|
|
32
|
+
img.crossOrigin = 'anonymous';
|
|
33
|
+
img.src = url;
|
|
34
|
+
await new Promise((resolve, reject) => {
|
|
35
|
+
img.onload = resolve;
|
|
36
|
+
img.onerror = reject;
|
|
37
|
+
});
|
|
38
|
+
return img;
|
|
39
|
+
} finally {
|
|
40
|
+
URL.revokeObjectURL(url);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
class PawDrawEditor {
|
|
45
|
+
constructor( /** @type {HTMLElement} */ parent) {
|
|
46
|
+
this.ready = false;
|
|
47
|
+
|
|
48
|
+
this.editable = false;
|
|
49
|
+
|
|
50
|
+
this.drawingColor = 'black';
|
|
51
|
+
|
|
52
|
+
/** @type {Array<Stroke>} */
|
|
53
|
+
this.strokes = [];
|
|
54
|
+
|
|
55
|
+
/** @type {Stroke | undefined} */
|
|
56
|
+
this.currentStroke = undefined;
|
|
57
|
+
|
|
58
|
+
this._initElements(parent);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
addPoint(/** @type {number} */ x, /** @type {number} */ y) {
|
|
62
|
+
if (this.currentStroke) {
|
|
63
|
+
this.currentStroke.addPoint(x, y)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
beginStoke(/** @type {string} */ color) {
|
|
68
|
+
this.currentStroke = new Stroke(color);
|
|
69
|
+
this.strokes.push(this.currentStroke);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
endStroke() {
|
|
73
|
+
const previous = this.currentStroke;
|
|
74
|
+
this.currentStroke = undefined;
|
|
75
|
+
return previous;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
setEditable(editable) {
|
|
79
|
+
this.editable = editable;
|
|
80
|
+
const colorButtons = /** @type {NodeListOf<HTMLButtonElement>} */ (document.querySelectorAll('.drawing-controls button'));
|
|
81
|
+
for (const colorButton of colorButtons) {
|
|
82
|
+
colorButton.disabled = !editable;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
_initElements(/** @type {HTMLElement} */ parent) {
|
|
87
|
+
const colorButtons = /** @type {NodeListOf<HTMLButtonElement>} */ (document.querySelectorAll('.drawing-controls button'));
|
|
88
|
+
for (const colorButton of colorButtons) {
|
|
89
|
+
colorButton.addEventListener('click', e => {
|
|
90
|
+
e.stopPropagation();
|
|
91
|
+
colorButtons.forEach(button => button.classList.remove('active'));
|
|
92
|
+
colorButton.classList.add('active');
|
|
93
|
+
this.drawingColor = colorButton.dataset['color'];
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
this.wrapper = document.createElement('div');
|
|
98
|
+
this.wrapper.style.position = 'relative';
|
|
99
|
+
parent.append(this.wrapper);
|
|
100
|
+
|
|
101
|
+
this.initialCanvas = document.createElement('canvas');
|
|
102
|
+
this.initialCtx = this.initialCanvas.getContext('2d');
|
|
103
|
+
this.wrapper.append(this.initialCanvas);
|
|
104
|
+
|
|
105
|
+
this.drawingCanvas = document.createElement('canvas');
|
|
106
|
+
this.drawingCanvas.style.position = 'absolute';
|
|
107
|
+
this.drawingCanvas.style.top = '0';
|
|
108
|
+
this.drawingCanvas.style.left = '0';
|
|
109
|
+
this.drawingCtx = this.drawingCanvas.getContext('2d');
|
|
110
|
+
this.wrapper.append(this.drawingCanvas);
|
|
111
|
+
|
|
112
|
+
let isDrawing = false;
|
|
113
|
+
|
|
114
|
+
parent.addEventListener('mousedown', () => {
|
|
115
|
+
if (!this.ready || !this.editable) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
this.beginStoke(this.drawingColor);
|
|
120
|
+
this.drawingCtx.strokeStyle = this.drawingColor;
|
|
121
|
+
|
|
122
|
+
isDrawing = true;
|
|
123
|
+
document.body.classList.add('isDrawing');
|
|
124
|
+
this.drawingCtx.beginPath();
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
document.body.addEventListener('mouseup', async () => {
|
|
128
|
+
if (!isDrawing || !this.ready || !this.editable) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
isDrawing = false;
|
|
133
|
+
document.body.classList.remove('isDrawing');
|
|
134
|
+
this.drawingCtx.closePath();
|
|
135
|
+
|
|
136
|
+
const edit = this.endStroke();
|
|
137
|
+
|
|
138
|
+
if (edit.stroke.length) {
|
|
139
|
+
vscode.postMessage({
|
|
140
|
+
type: 'stroke',
|
|
141
|
+
color: edit.color,
|
|
142
|
+
stroke: edit.stroke,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
parent.addEventListener('mousemove', e => {
|
|
148
|
+
if (!isDrawing || !this.ready || !this.editable) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const rect = this.wrapper.getBoundingClientRect();
|
|
152
|
+
const x = e.clientX - rect.left;
|
|
153
|
+
const y = e.clientY - rect.top;
|
|
154
|
+
this.drawingCtx.lineTo(x, y);
|
|
155
|
+
this.drawingCtx.stroke();
|
|
156
|
+
this.addPoint(x, y);
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
_redraw() {
|
|
161
|
+
this.drawingCtx.clearRect(0, 0, this.drawingCanvas.width, this.drawingCanvas.height);
|
|
162
|
+
for (const stroke of this.strokes) {
|
|
163
|
+
this.drawingCtx.strokeStyle = stroke.color;
|
|
164
|
+
this.drawingCtx.beginPath();
|
|
165
|
+
for (const [x, y] of stroke.stroke) {
|
|
166
|
+
this.drawingCtx.lineTo(x, y);
|
|
167
|
+
}
|
|
168
|
+
this.drawingCtx.stroke();
|
|
169
|
+
this.drawingCtx.closePath();
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* @param {Uint8Array | undefined} data
|
|
175
|
+
* @param {Array<Stroke> | undefined} strokes
|
|
176
|
+
*/
|
|
177
|
+
async reset(data, strokes = []) {
|
|
178
|
+
if (data) {
|
|
179
|
+
const img = await loadImageFromData(data);
|
|
180
|
+
this.initialCanvas.width = this.drawingCanvas.width = img.naturalWidth;
|
|
181
|
+
this.initialCanvas.height = this.drawingCanvas.height = img.naturalHeight;
|
|
182
|
+
this.initialCtx.drawImage(img, 0, 0);
|
|
183
|
+
this.ready = true;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
this.strokes = strokes;
|
|
187
|
+
this._redraw();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* @param {Array<Stroke> | undefined} strokes
|
|
192
|
+
*/
|
|
193
|
+
async resetUntitled(strokes = []) {
|
|
194
|
+
const size = 100;
|
|
195
|
+
this.initialCanvas.width = this.drawingCanvas.width = size;
|
|
196
|
+
this.initialCanvas.height = this.drawingCanvas.height = size;
|
|
197
|
+
|
|
198
|
+
this.initialCtx.save();
|
|
199
|
+
{
|
|
200
|
+
this.initialCtx.fillStyle = 'white';
|
|
201
|
+
this.initialCtx.fillRect(0, 0, size, size);
|
|
202
|
+
}
|
|
203
|
+
this.initialCtx.restore();
|
|
204
|
+
|
|
205
|
+
this.ready = true;
|
|
206
|
+
|
|
207
|
+
this.strokes = strokes;
|
|
208
|
+
this._redraw();
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** @return {Promise<Uint8Array>} */
|
|
212
|
+
async getImageData() {
|
|
213
|
+
const outCanvas = document.createElement('canvas');
|
|
214
|
+
outCanvas.width = this.drawingCanvas.width;
|
|
215
|
+
outCanvas.height = this.drawingCanvas.height;
|
|
216
|
+
|
|
217
|
+
const outCtx = outCanvas.getContext('2d');
|
|
218
|
+
outCtx.drawImage(this.initialCanvas, 0, 0);
|
|
219
|
+
outCtx.drawImage(this.drawingCanvas, 0, 0);
|
|
220
|
+
|
|
221
|
+
const blob = await new Promise(resolve => {
|
|
222
|
+
outCanvas.toBlob(resolve, 'image/png')
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
return new Uint8Array(await blob.arrayBuffer());
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const editor = new PawDrawEditor(document.querySelector('.drawing-canvas'));
|
|
230
|
+
|
|
231
|
+
// Handle messages from the extension
|
|
232
|
+
window.addEventListener('message', async e => {
|
|
233
|
+
const { type, body, requestId } = e.data;
|
|
234
|
+
switch (type) {
|
|
235
|
+
case 'init':
|
|
236
|
+
{
|
|
237
|
+
editor.setEditable(body.editable);
|
|
238
|
+
if (body.untitled) {
|
|
239
|
+
await editor.resetUntitled();
|
|
240
|
+
return;
|
|
241
|
+
} else {
|
|
242
|
+
// Load the initial image into the canvas.
|
|
243
|
+
await editor.reset(body.value);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
case 'update':
|
|
248
|
+
{
|
|
249
|
+
const strokes = body.edits.map(edit => new Stroke(edit.color, edit.stroke));
|
|
250
|
+
await editor.reset(body.content, strokes)
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
case 'getFileData':
|
|
254
|
+
{
|
|
255
|
+
// Get the image data for the canvas and post it back to the extension.
|
|
256
|
+
editor.getImageData().then(data => {
|
|
257
|
+
vscode.postMessage({ type: 'response', requestId, body: Array.from(data) });
|
|
258
|
+
});
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
// Signal to VS Code that the webview is initialized.
|
|
265
|
+
vscode.postMessage({ type: 'ready' });
|
|
266
|
+
}());
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
html {
|
|
2
|
+
box-sizing: border-box;
|
|
3
|
+
font-size: 13px;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
*,
|
|
7
|
+
*:before,
|
|
8
|
+
*:after {
|
|
9
|
+
box-sizing: inherit;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
body,
|
|
13
|
+
h1,
|
|
14
|
+
h2,
|
|
15
|
+
h3,
|
|
16
|
+
h4,
|
|
17
|
+
h5,
|
|
18
|
+
h6,
|
|
19
|
+
p,
|
|
20
|
+
ol,
|
|
21
|
+
ul {
|
|
22
|
+
margin: 0;
|
|
23
|
+
padding: 0;
|
|
24
|
+
font-weight: normal;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
img {
|
|
28
|
+
max-width: 100%;
|
|
29
|
+
height: auto;
|
|
30
|
+
}
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--container-paddding: 20px;
|
|
3
|
+
--input-padding-vertical: 6px;
|
|
4
|
+
--input-padding-horizontal: 4px;
|
|
5
|
+
--input-margin-vertical: 4px;
|
|
6
|
+
--input-margin-horizontal: 0;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
body {
|
|
10
|
+
padding: 0 var(--container-paddding);
|
|
11
|
+
color: var(--vscode-foreground);
|
|
12
|
+
font-size: var(--vscode-font-size);
|
|
13
|
+
font-weight: var(--vscode-font-weight);
|
|
14
|
+
font-family: var(--vscode-font-family);
|
|
15
|
+
background-color: var(--vscode-editor-background);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
ol,
|
|
19
|
+
ul {
|
|
20
|
+
padding-left: var(--container-paddding);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
body > *,
|
|
24
|
+
form > * {
|
|
25
|
+
margin-block-start: var(--input-margin-vertical);
|
|
26
|
+
margin-block-end: var(--input-margin-vertical);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
*:focus {
|
|
30
|
+
outline-color: var(--vscode-focusBorder) !important;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
a {
|
|
34
|
+
color: var(--vscode-textLink-foreground);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
a:hover,
|
|
38
|
+
a:active {
|
|
39
|
+
color: var(--vscode-textLink-activeForeground);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
code {
|
|
43
|
+
font-size: var(--vscode-editor-font-size);
|
|
44
|
+
font-family: var(--vscode-editor-font-family);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
button {
|
|
48
|
+
border: none;
|
|
49
|
+
padding: var(--input-padding-vertical) var(--input-padding-horizontal);
|
|
50
|
+
width: 100%;
|
|
51
|
+
text-align: center;
|
|
52
|
+
outline: 1px solid transparent;
|
|
53
|
+
outline-offset: 2px !important;
|
|
54
|
+
color: var(--vscode-button-foreground);
|
|
55
|
+
background: var(--vscode-button-background);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
button:hover {
|
|
59
|
+
cursor: pointer;
|
|
60
|
+
background: var(--vscode-button-hoverBackground);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
button:focus {
|
|
64
|
+
outline-color: var(--vscode-focusBorder);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
button.secondary {
|
|
68
|
+
color: var(--vscode-button-secondaryForeground);
|
|
69
|
+
background: var(--vscode-button-secondaryBackground);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
button.secondary:hover {
|
|
73
|
+
background: var(--vscode-button-secondaryHoverBackground);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
input:not([type='checkbox']),
|
|
77
|
+
textarea {
|
|
78
|
+
display: block;
|
|
79
|
+
width: 100%;
|
|
80
|
+
border: none;
|
|
81
|
+
font-family: var(--vscode-font-family);
|
|
82
|
+
padding: var(--input-padding-vertical) var(--input-padding-horizontal);
|
|
83
|
+
color: var(--vscode-input-foreground);
|
|
84
|
+
outline-color: var(--vscode-input-border);
|
|
85
|
+
background-color: var(--vscode-input-background);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
input::placeholder,
|
|
89
|
+
textarea::placeholder {
|
|
90
|
+
color: var(--vscode-input-placeholderForeground);
|
|
91
|
+
}
|