Merge commit 'be3e8236086165e5e45a5a10783823874b3f3ebd' as 'lib/vscode'
This commit is contained in:
11
lib/vscode/extensions/image-preview/.vscodeignore
Normal file
11
lib/vscode/extensions/image-preview/.vscodeignore
Normal file
@ -0,0 +1,11 @@
|
||||
test/**
|
||||
src/**
|
||||
tsconfig.json
|
||||
out/test/**
|
||||
out/**
|
||||
extension.webpack.config.js
|
||||
extension-browser.webpack.config.js
|
||||
cgmanifest.json
|
||||
yarn.lock
|
||||
preview-src/**
|
||||
webpack.config.js
|
16
lib/vscode/extensions/image-preview/README.md
Normal file
16
lib/vscode/extensions/image-preview/README.md
Normal file
@ -0,0 +1,16 @@
|
||||
# Image Preview
|
||||
|
||||
**Notice:** This extension is bundled with Visual Studio Code. It can be disabled but not uninstalled.
|
||||
|
||||
## Features
|
||||
|
||||
This extension provides VS Code's built-in image preview functionality.
|
||||
|
||||
Supported image formats:
|
||||
|
||||
- `*.jpg`, `*.jpe`, `*.jpeg`
|
||||
- `*.png`
|
||||
- `*.bmp`
|
||||
- `*.gif`
|
||||
- `*.ico`
|
||||
- `*.webp`
|
@ -0,0 +1,17 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
//@ts-check
|
||||
|
||||
'use strict';
|
||||
|
||||
const withBrowserDefaults = require('../shared.webpack.config').browser;
|
||||
|
||||
module.exports = withBrowserDefaults({
|
||||
context: __dirname,
|
||||
entry: {
|
||||
extension: './src/extension.ts'
|
||||
},
|
||||
});
|
@ -0,0 +1,20 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
//@ts-check
|
||||
|
||||
'use strict';
|
||||
|
||||
const withDefaults = require('../shared.webpack.config');
|
||||
|
||||
module.exports = withDefaults({
|
||||
context: __dirname,
|
||||
resolve: {
|
||||
mainFields: ['module', 'main']
|
||||
},
|
||||
entry: {
|
||||
extension: './src/extension.ts',
|
||||
}
|
||||
});
|
BIN
lib/vscode/extensions/image-preview/icon.png
Normal file
BIN
lib/vscode/extensions/image-preview/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
18
lib/vscode/extensions/image-preview/icon.svg
Normal file
18
lib/vscode/extensions/image-preview/icon.svg
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 23.0.6, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<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"
|
||||
viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#C5C5C5;}
|
||||
</style>
|
||||
<g>
|
||||
<path class="st0" d="M2,14.1l-1.1-1L0.9,3l1-1.1l12.1,0l1.1,1l0,10.1L14,14.1H2z M13.9,12.9V3.1H2.1v9.8H13.9z M8.9,12.1V7.9h4.2
|
||||
v4.2H8.9z M11.9,10.9V9.1h-1.8v1.8H11.9z M2.9,12.1v-1.2h4.2v1.2H2.9z M2.9,9.1V7.9h4.2v1.2H2.9z M2.9,7.1V3.9h10.2v3.2H2.9z
|
||||
M11.9,5.9V5.1H4.1v0.8H11.9z"/>
|
||||
<path d="M14,2l1,1v10l-1,1H2l-1-1V3l1-1H14 M2,13h12V3H2V13 M13,4v3H3V4H13 M4,6h8V5H4V6 M13,8v4H9V8H13 M10,11h2V9h-2V11 M7,8v1H3
|
||||
V8H7 M7,11v1H3v-1H7 M14.1,1.8L14.1,1.8H2H1.9L1.9,1.9l-1,1L0.8,2.9V3v10v0.1l0.1,0.1l1,1l0.1,0.1H2h12h0.1l0.1-0.1l1-1l0.1-0.1V13
|
||||
V3V2.9l-0.1-0.1L14.1,1.8L14.1,1.8L14.1,1.8z M2.2,3.2h11.6v9.6H2.2V3.2L2.2,3.2z M13.2,3.8H13H3H2.8V4v3v0.2H3h10h0.2V7V4V3.8
|
||||
L13.2,3.8z M4.2,5.2h7.6v0.6H4.2V5.2L4.2,5.2z M13.2,7.8H13H9H8.8V8v4v0.2H9h4h0.2V12V8V7.8L13.2,7.8z M10.2,9.2h1.6v1.6h-1.6V9.2
|
||||
L10.2,9.2z M7.2,7.8H7H3H2.8V8v1v0.2H3h4h0.2V9V8V7.8L7.2,7.8z M7.2,10.8H7H3H2.8V11v1v0.2H3h4h0.2V12v-1V10.8L7.2,10.8z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
31
lib/vscode/extensions/image-preview/media/loading-dark.svg
Normal file
31
lib/vscode/extensions/image-preview/media/loading-dark.svg
Normal file
@ -0,0 +1,31 @@
|
||||
<?xml version='1.0' standalone='no' ?>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='10px' height='10px'>
|
||||
<style>
|
||||
circle {
|
||||
animation: ball 0.6s linear infinite;
|
||||
}
|
||||
|
||||
circle:nth-child(2) { animation-delay: 0.075s; }
|
||||
circle:nth-child(3) { animation-delay: 0.15s; }
|
||||
circle:nth-child(4) { animation-delay: 0.225s; }
|
||||
circle:nth-child(5) { animation-delay: 0.3s; }
|
||||
circle:nth-child(6) { animation-delay: 0.375s; }
|
||||
circle:nth-child(7) { animation-delay: 0.45s; }
|
||||
circle:nth-child(8) { animation-delay: 0.525s; }
|
||||
|
||||
@keyframes ball {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0.3; }
|
||||
}
|
||||
</style>
|
||||
<g style="fill:grey;">
|
||||
<circle cx='5' cy='1' r='1' style='opacity:0.3;' />
|
||||
<circle cx='7.8284' cy='2.1716' r='1' style='opacity:0.3;' />
|
||||
<circle cx='9' cy='5' r='1' style='opacity:0.3;' />
|
||||
<circle cx='7.8284' cy='7.8284' r='1' style='opacity:0.3;' />
|
||||
<circle cx='5' cy='9' r='1' style='opacity:0.3;' />
|
||||
<circle cx='2.1716' cy='7.8284' r='1' style='opacity:0.3;' />
|
||||
<circle cx='1' cy='5' r='1' style='opacity:0.3;' />
|
||||
<circle cx='2.1716' cy='2.1716' r='1' style='opacity:0.3;' />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
31
lib/vscode/extensions/image-preview/media/loading-hc.svg
Normal file
31
lib/vscode/extensions/image-preview/media/loading-hc.svg
Normal file
@ -0,0 +1,31 @@
|
||||
<?xml version='1.0' standalone='no' ?>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='10px' height='10px'>
|
||||
<style>
|
||||
circle {
|
||||
animation: ball 0.6s linear infinite;
|
||||
}
|
||||
|
||||
circle:nth-child(2) { animation-delay: 0.075s; }
|
||||
circle:nth-child(3) { animation-delay: 0.15s; }
|
||||
circle:nth-child(4) { animation-delay: 0.225s; }
|
||||
circle:nth-child(5) { animation-delay: 0.3s; }
|
||||
circle:nth-child(6) { animation-delay: 0.375s; }
|
||||
circle:nth-child(7) { animation-delay: 0.45s; }
|
||||
circle:nth-child(8) { animation-delay: 0.525s; }
|
||||
|
||||
@keyframes ball {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0.3; }
|
||||
}
|
||||
</style>
|
||||
<g style="fill:white;">
|
||||
<circle cx='5' cy='1' r='1' style='opacity:0.3;' />
|
||||
<circle cx='7.8284' cy='2.1716' r='1' style='opacity:0.3;' />
|
||||
<circle cx='9' cy='5' r='1' style='opacity:0.3;' />
|
||||
<circle cx='7.8284' cy='7.8284' r='1' style='opacity:0.3;' />
|
||||
<circle cx='5' cy='9' r='1' style='opacity:0.3;' />
|
||||
<circle cx='2.1716' cy='7.8284' r='1' style='opacity:0.3;' />
|
||||
<circle cx='1' cy='5' r='1' style='opacity:0.3;' />
|
||||
<circle cx='2.1716' cy='2.1716' r='1' style='opacity:0.3;' />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
31
lib/vscode/extensions/image-preview/media/loading.svg
Normal file
31
lib/vscode/extensions/image-preview/media/loading.svg
Normal file
@ -0,0 +1,31 @@
|
||||
<?xml version='1.0' standalone='no' ?>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='10px' height='10px'>
|
||||
<style>
|
||||
circle {
|
||||
animation: ball 0.6s linear infinite;
|
||||
}
|
||||
|
||||
circle:nth-child(2) { animation-delay: 0.075s; }
|
||||
circle:nth-child(3) { animation-delay: 0.15s; }
|
||||
circle:nth-child(4) { animation-delay: 0.225s; }
|
||||
circle:nth-child(5) { animation-delay: 0.3s; }
|
||||
circle:nth-child(6) { animation-delay: 0.375s; }
|
||||
circle:nth-child(7) { animation-delay: 0.45s; }
|
||||
circle:nth-child(8) { animation-delay: 0.525s; }
|
||||
|
||||
@keyframes ball {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0.3; }
|
||||
}
|
||||
</style>
|
||||
<g>
|
||||
<circle cx='5' cy='1' r='1' style='opacity:0.3;' />
|
||||
<circle cx='7.8284' cy='2.1716' r='1' style='opacity:0.3;' />
|
||||
<circle cx='9' cy='5' r='1' style='opacity:0.3;' />
|
||||
<circle cx='7.8284' cy='7.8284' r='1' style='opacity:0.3;' />
|
||||
<circle cx='5' cy='9' r='1' style='opacity:0.3;' />
|
||||
<circle cx='2.1716' cy='7.8284' r='1' style='opacity:0.3;' />
|
||||
<circle cx='1' cy='5' r='1' style='opacity:0.3;' />
|
||||
<circle cx='2.1716' cy='2.1716' r='1' style='opacity:0.3;' />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
116
lib/vscode/extensions/image-preview/media/main.css
Normal file
116
lib/vscode/extensions/image-preview/media/main.css
Normal file
@ -0,0 +1,116 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
html, body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
body img {
|
||||
max-width: none;
|
||||
max-height: none;
|
||||
}
|
||||
|
||||
.container:focus {
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 5px 0 0 10px;
|
||||
box-sizing: border-box;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.container.image {
|
||||
padding: 0;
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.container.image img {
|
||||
padding: 0;
|
||||
background-position: 0 0, 8px 8px;
|
||||
background-size: 16px 16px;
|
||||
border: 1px solid var(--vscode-imagePreview-border);
|
||||
}
|
||||
|
||||
.container.image img {
|
||||
background-image:
|
||||
linear-gradient(45deg, rgb(230, 230, 230) 25%, transparent 25%, transparent 75%, rgb(230, 230, 230) 75%, rgb(230, 230, 230)),
|
||||
linear-gradient(45deg, rgb(230, 230, 230) 25%, transparent 25%, transparent 75%, rgb(230, 230, 230) 75%, rgb(230, 230, 230));
|
||||
}
|
||||
|
||||
.vscode-dark.container.image img {
|
||||
background-image:
|
||||
linear-gradient(45deg, rgb(20, 20, 20) 25%, transparent 25%, transparent 75%, rgb(20, 20, 20) 75%, rgb(20, 20, 20)),
|
||||
linear-gradient(45deg, rgb(20, 20, 20) 25%, transparent 25%, transparent 75%, rgb(20, 20, 20) 75%, rgb(20, 20, 20));
|
||||
}
|
||||
|
||||
.container img.pixelated {
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
|
||||
.container img.scale-to-fit {
|
||||
max-width: calc(100% - 20px);
|
||||
max-height: calc(100% - 20px);
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.container img {
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.container.ready.zoom-in {
|
||||
cursor: zoom-in;
|
||||
}
|
||||
|
||||
.container.ready.zoom-out {
|
||||
cursor: zoom-out;
|
||||
}
|
||||
|
||||
.container .embedded-link,
|
||||
.container .embedded-link:hover {
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.container.loading,
|
||||
.container.error {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.loading-indicator {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
background-image: url('./loading.svg');
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.loading-indicator,
|
||||
.image-load-error {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.loading .loading-indicator,
|
||||
.error .image-load-error {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.image-load-error {
|
||||
margin: 1em;
|
||||
}
|
||||
|
||||
.vscode-dark .loading-indicator {
|
||||
background-image: url('./loading-dark.svg');
|
||||
}
|
||||
|
||||
.vscode-high-contrast .loading-indicator {
|
||||
background-image: url('./loading-hc.svg');
|
||||
}
|
340
lib/vscode/extensions/image-preview/media/main.js
Normal file
340
lib/vscode/extensions/image-preview/media/main.js
Normal file
@ -0,0 +1,340 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
// @ts-check
|
||||
"use strict";
|
||||
|
||||
(function () {
|
||||
/**
|
||||
* @param {number} value
|
||||
* @param {number} min
|
||||
* @param {number} max
|
||||
* @return {number}
|
||||
*/
|
||||
function clamp(value, min, max) {
|
||||
return Math.min(Math.max(value, min), max);
|
||||
}
|
||||
|
||||
function getSettings() {
|
||||
const element = document.getElementById('image-preview-settings');
|
||||
if (element) {
|
||||
const data = element.getAttribute('data-settings');
|
||||
if (data) {
|
||||
return JSON.parse(data);
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`Could not load settings`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable image-rendering: pixelated for images scaled by more than this.
|
||||
*/
|
||||
const PIXELATION_THRESHOLD = 3;
|
||||
|
||||
const SCALE_PINCH_FACTOR = 0.075;
|
||||
const MAX_SCALE = 20;
|
||||
const MIN_SCALE = 0.1;
|
||||
|
||||
const zoomLevels = [
|
||||
0.1,
|
||||
0.2,
|
||||
0.3,
|
||||
0.4,
|
||||
0.5,
|
||||
0.6,
|
||||
0.7,
|
||||
0.8,
|
||||
0.9,
|
||||
1,
|
||||
1.5,
|
||||
2,
|
||||
3,
|
||||
5,
|
||||
7,
|
||||
10,
|
||||
15,
|
||||
20
|
||||
];
|
||||
|
||||
const settings = getSettings();
|
||||
const isMac = settings.isMac;
|
||||
|
||||
const vscode = acquireVsCodeApi();
|
||||
|
||||
const initialState = vscode.getState() || { scale: 'fit', offsetX: 0, offsetY: 0 };
|
||||
|
||||
// State
|
||||
let scale = initialState.scale;
|
||||
let ctrlPressed = false;
|
||||
let altPressed = false;
|
||||
let hasLoadedImage = false;
|
||||
let consumeClick = true;
|
||||
let isActive = false;
|
||||
|
||||
// Elements
|
||||
const container = document.body;
|
||||
const image = document.createElement('img');
|
||||
|
||||
function updateScale(newScale) {
|
||||
if (!image || !hasLoadedImage || !image.parentElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (newScale === 'fit') {
|
||||
scale = 'fit';
|
||||
image.classList.add('scale-to-fit');
|
||||
image.classList.remove('pixelated');
|
||||
image.style.minWidth = 'auto';
|
||||
image.style.width = 'auto';
|
||||
vscode.setState(undefined);
|
||||
} else {
|
||||
scale = clamp(newScale, MIN_SCALE, MAX_SCALE);
|
||||
if (scale >= PIXELATION_THRESHOLD) {
|
||||
image.classList.add('pixelated');
|
||||
} else {
|
||||
image.classList.remove('pixelated');
|
||||
}
|
||||
|
||||
const dx = (window.scrollX + container.clientWidth / 2) / container.scrollWidth;
|
||||
const dy = (window.scrollY + container.clientHeight / 2) / container.scrollHeight;
|
||||
|
||||
image.classList.remove('scale-to-fit');
|
||||
image.style.minWidth = `${(image.naturalWidth * scale)}px`;
|
||||
image.style.width = `${(image.naturalWidth * scale)}px`;
|
||||
|
||||
const newScrollX = container.scrollWidth * dx - container.clientWidth / 2;
|
||||
const newScrollY = container.scrollHeight * dy - container.clientHeight / 2;
|
||||
|
||||
window.scrollTo(newScrollX, newScrollY);
|
||||
|
||||
vscode.setState({ scale: scale, offsetX: newScrollX, offsetY: newScrollY });
|
||||
}
|
||||
|
||||
vscode.postMessage({
|
||||
type: 'zoom',
|
||||
value: scale
|
||||
});
|
||||
}
|
||||
|
||||
function setActive(value) {
|
||||
isActive = value;
|
||||
if (value) {
|
||||
if (isMac ? altPressed : ctrlPressed) {
|
||||
container.classList.remove('zoom-in');
|
||||
container.classList.add('zoom-out');
|
||||
} else {
|
||||
container.classList.remove('zoom-out');
|
||||
container.classList.add('zoom-in');
|
||||
}
|
||||
} else {
|
||||
ctrlPressed = false;
|
||||
altPressed = false;
|
||||
container.classList.remove('zoom-out');
|
||||
container.classList.remove('zoom-in');
|
||||
}
|
||||
}
|
||||
|
||||
function firstZoom() {
|
||||
if (!image || !hasLoadedImage) {
|
||||
return;
|
||||
}
|
||||
|
||||
scale = image.clientWidth / image.naturalWidth;
|
||||
updateScale(scale);
|
||||
}
|
||||
|
||||
function zoomIn() {
|
||||
if (scale === 'fit') {
|
||||
firstZoom();
|
||||
}
|
||||
|
||||
let i = 0;
|
||||
for (; i < zoomLevels.length; ++i) {
|
||||
if (zoomLevels[i] > scale) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
updateScale(zoomLevels[i] || MAX_SCALE);
|
||||
}
|
||||
|
||||
function zoomOut() {
|
||||
if (scale === 'fit') {
|
||||
firstZoom();
|
||||
}
|
||||
|
||||
let i = zoomLevels.length - 1;
|
||||
for (; i >= 0; --i) {
|
||||
if (zoomLevels[i] < scale) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
updateScale(zoomLevels[i] || MIN_SCALE);
|
||||
}
|
||||
|
||||
window.addEventListener('keydown', (/** @type {KeyboardEvent} */ e) => {
|
||||
if (!image || !hasLoadedImage) {
|
||||
return;
|
||||
}
|
||||
ctrlPressed = e.ctrlKey;
|
||||
altPressed = e.altKey;
|
||||
|
||||
if (isMac ? altPressed : ctrlPressed) {
|
||||
container.classList.remove('zoom-in');
|
||||
container.classList.add('zoom-out');
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('keyup', (/** @type {KeyboardEvent} */ e) => {
|
||||
if (!image || !hasLoadedImage) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctrlPressed = e.ctrlKey;
|
||||
altPressed = e.altKey;
|
||||
|
||||
if (!(isMac ? altPressed : ctrlPressed)) {
|
||||
container.classList.remove('zoom-out');
|
||||
container.classList.add('zoom-in');
|
||||
}
|
||||
});
|
||||
|
||||
container.addEventListener('mousedown', (/** @type {MouseEvent} */ e) => {
|
||||
if (!image || !hasLoadedImage) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.button !== 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctrlPressed = e.ctrlKey;
|
||||
altPressed = e.altKey;
|
||||
|
||||
consumeClick = !isActive;
|
||||
});
|
||||
|
||||
container.addEventListener('click', (/** @type {MouseEvent} */ e) => {
|
||||
if (!image || !hasLoadedImage) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.button !== 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (consumeClick) {
|
||||
consumeClick = false;
|
||||
return;
|
||||
}
|
||||
// left click
|
||||
if (scale === 'fit') {
|
||||
firstZoom();
|
||||
}
|
||||
|
||||
if (!(isMac ? altPressed : ctrlPressed)) { // zoom in
|
||||
zoomIn();
|
||||
} else {
|
||||
zoomOut();
|
||||
}
|
||||
});
|
||||
|
||||
container.addEventListener('wheel', (/** @type {WheelEvent} */ e) => {
|
||||
// Prevent pinch to zoom
|
||||
if (e.ctrlKey) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
if (!image || !hasLoadedImage) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isScrollWheelKeyPressed = isMac ? altPressed : ctrlPressed;
|
||||
if (!isScrollWheelKeyPressed && !e.ctrlKey) { // pinching is reported as scroll wheel + ctrl
|
||||
return;
|
||||
}
|
||||
|
||||
if (scale === 'fit') {
|
||||
firstZoom();
|
||||
}
|
||||
|
||||
let delta = e.deltaY > 0 ? 1 : -1;
|
||||
updateScale(scale * (1 - delta * SCALE_PINCH_FACTOR));
|
||||
}, { passive: false });
|
||||
|
||||
window.addEventListener('scroll', e => {
|
||||
if (!image || !hasLoadedImage || !image.parentElement || scale === 'fit') {
|
||||
return;
|
||||
}
|
||||
|
||||
const entry = vscode.getState();
|
||||
if (entry) {
|
||||
vscode.setState({ scale: entry.scale, offsetX: window.scrollX, offsetY: window.scrollY });
|
||||
}
|
||||
}, { passive: true });
|
||||
|
||||
container.classList.add('image');
|
||||
|
||||
image.classList.add('scale-to-fit');
|
||||
|
||||
image.addEventListener('load', () => {
|
||||
if (hasLoadedImage) {
|
||||
return;
|
||||
}
|
||||
hasLoadedImage = true;
|
||||
|
||||
vscode.postMessage({
|
||||
type: 'size',
|
||||
value: `${image.naturalWidth}x${image.naturalHeight}`,
|
||||
});
|
||||
|
||||
document.body.classList.remove('loading');
|
||||
document.body.classList.add('ready');
|
||||
document.body.append(image);
|
||||
|
||||
updateScale(scale);
|
||||
|
||||
if (initialState.scale !== 'fit') {
|
||||
window.scrollTo(initialState.offsetX, initialState.offsetY);
|
||||
}
|
||||
});
|
||||
|
||||
image.addEventListener('error', e => {
|
||||
if (hasLoadedImage) {
|
||||
return;
|
||||
}
|
||||
|
||||
hasLoadedImage = true;
|
||||
document.body.classList.add('error');
|
||||
document.body.classList.remove('loading');
|
||||
});
|
||||
|
||||
image.src = settings.src;
|
||||
|
||||
document.querySelector('.open-file-link').addEventListener('click', () => {
|
||||
vscode.postMessage({
|
||||
type: 'reopen-as-text',
|
||||
});
|
||||
});
|
||||
|
||||
window.addEventListener('message', e => {
|
||||
switch (e.data.type) {
|
||||
case 'setScale':
|
||||
updateScale(e.data.scale);
|
||||
break;
|
||||
|
||||
case 'setActive':
|
||||
setActive(e.data.value);
|
||||
break;
|
||||
|
||||
case 'zoomIn':
|
||||
zoomIn();
|
||||
break;
|
||||
|
||||
case 'zoomOut':
|
||||
zoomOut();
|
||||
break;
|
||||
}
|
||||
});
|
||||
}());
|
81
lib/vscode/extensions/image-preview/package.json
Normal file
81
lib/vscode/extensions/image-preview/package.json
Normal file
@ -0,0 +1,81 @@
|
||||
{
|
||||
"name": "image-preview",
|
||||
"displayName": "%displayName%",
|
||||
"description": "%description%",
|
||||
"extensionKind": [
|
||||
"ui",
|
||||
"workspace",
|
||||
"web"
|
||||
],
|
||||
"version": "1.0.0",
|
||||
"publisher": "vscode",
|
||||
"icon": "icon.png",
|
||||
"enableProposedApi": true,
|
||||
"license": "MIT",
|
||||
"aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217",
|
||||
"engines": {
|
||||
"vscode": "^1.39.0"
|
||||
},
|
||||
"main": "./out/extension",
|
||||
"browser": "./dist/browser/extension.js",
|
||||
"categories": [
|
||||
"Other"
|
||||
],
|
||||
"activationEvents": [
|
||||
"onCustomEditor:imagePreview.previewEditor",
|
||||
"onCommand:imagePreview.zoomIn",
|
||||
"onCommand:imagePreview.zoomOut"
|
||||
],
|
||||
"contributes": {
|
||||
"customEditors": [
|
||||
{
|
||||
"viewType": "imagePreview.previewEditor",
|
||||
"displayName": "%customEditors.displayName%",
|
||||
"priority": "builtin",
|
||||
"selector": [
|
||||
{
|
||||
"filenamePattern": "*.{jpg,jpe,jpeg,png,bmp,gif,ico,webp}"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"commands": [
|
||||
{
|
||||
"command": "imagePreview.zoomIn",
|
||||
"title": "%command.zoomIn%",
|
||||
"category": "Image Preview"
|
||||
},
|
||||
{
|
||||
"command": "imagePreview.zoomOut",
|
||||
"title": "%command.zoomOut%",
|
||||
"category": "Image Preview"
|
||||
}
|
||||
],
|
||||
"menus": {
|
||||
"commandPalette": [
|
||||
{
|
||||
"command": "imagePreview.zoomIn",
|
||||
"when": "imagePreviewFocus",
|
||||
"group": "1_imagePreview"
|
||||
},
|
||||
{
|
||||
"command": "imagePreview.zoomOut",
|
||||
"when": "imagePreviewFocus",
|
||||
"group": "1_imagePreview"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"compile": "gulp compile-extension:image-preview",
|
||||
"watch": "npm run build-preview && gulp watch-extension:image-preview",
|
||||
"vscode:prepublish": "npm run build-ext",
|
||||
"build-ext": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:image-preview ./tsconfig.json",
|
||||
"compile-web": "npx webpack-cli --config extension-browser.webpack.config --mode none",
|
||||
"watch-web": "npx webpack-cli --config extension-browser.webpack.config --mode none --watch --info-verbosity verbose"
|
||||
},
|
||||
"dependencies": {
|
||||
"vscode-extension-telemetry": "0.1.1",
|
||||
"vscode-nls": "^4.0.0"
|
||||
}
|
||||
}
|
7
lib/vscode/extensions/image-preview/package.nls.json
Normal file
7
lib/vscode/extensions/image-preview/package.nls.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"displayName": "Image Preview",
|
||||
"description": "Provides VS Code's built-in image preview",
|
||||
"customEditors.displayName": "Image Preview",
|
||||
"command.zoomIn": "Zoom in",
|
||||
"command.zoomOut": "Zoom out"
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { PreviewStatusBarEntry } from './ownedStatusBarEntry';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
class BinarySize {
|
||||
static readonly KB = 1024;
|
||||
static readonly MB = BinarySize.KB * BinarySize.KB;
|
||||
static readonly GB = BinarySize.MB * BinarySize.KB;
|
||||
static readonly TB = BinarySize.GB * BinarySize.KB;
|
||||
|
||||
static formatSize(size: number): string {
|
||||
if (size < BinarySize.KB) {
|
||||
return localize('sizeB', "{0}B", size);
|
||||
}
|
||||
|
||||
if (size < BinarySize.MB) {
|
||||
return localize('sizeKB', "{0}KB", (size / BinarySize.KB).toFixed(2));
|
||||
}
|
||||
|
||||
if (size < BinarySize.GB) {
|
||||
return localize('sizeMB', "{0}MB", (size / BinarySize.MB).toFixed(2));
|
||||
}
|
||||
|
||||
if (size < BinarySize.TB) {
|
||||
return localize('sizeGB', "{0}GB", (size / BinarySize.GB).toFixed(2));
|
||||
}
|
||||
|
||||
return localize('sizeTB', "{0}TB", (size / BinarySize.TB).toFixed(2));
|
||||
}
|
||||
}
|
||||
|
||||
export class BinarySizeStatusBarEntry extends PreviewStatusBarEntry {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'imagePreview.binarySize',
|
||||
name: localize('sizeStatusBar.name', "Image Binary Size"),
|
||||
alignment: vscode.StatusBarAlignment.Right,
|
||||
priority: 100,
|
||||
});
|
||||
}
|
||||
|
||||
public show(owner: string, size: number | undefined) {
|
||||
if (typeof size === 'number') {
|
||||
super.showItem(owner, BinarySize.formatSize(size));
|
||||
} else {
|
||||
this.hide(owner);
|
||||
}
|
||||
}
|
||||
}
|
42
lib/vscode/extensions/image-preview/src/dispose.ts
Normal file
42
lib/vscode/extensions/image-preview/src/dispose.ts
Normal file
@ -0,0 +1,42 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
export function disposeAll(disposables: vscode.Disposable[]) {
|
||||
while (disposables.length) {
|
||||
const item = disposables.pop();
|
||||
if (item) {
|
||||
item.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class Disposable {
|
||||
private _isDisposed = false;
|
||||
|
||||
protected _disposables: vscode.Disposable[] = [];
|
||||
|
||||
public dispose(): any {
|
||||
if (this._isDisposed) {
|
||||
return;
|
||||
}
|
||||
this._isDisposed = true;
|
||||
disposeAll(this._disposables);
|
||||
}
|
||||
|
||||
protected _register<T extends vscode.Disposable>(value: T): T {
|
||||
if (this._isDisposed) {
|
||||
value.dispose();
|
||||
} else {
|
||||
this._disposables.push(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
protected get isDisposed() {
|
||||
return this._isDisposed;
|
||||
}
|
||||
}
|
35
lib/vscode/extensions/image-preview/src/extension.ts
Normal file
35
lib/vscode/extensions/image-preview/src/extension.ts
Normal file
@ -0,0 +1,35 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { BinarySizeStatusBarEntry } from './binarySizeStatusBarEntry';
|
||||
import { PreviewManager } from './preview';
|
||||
import { SizeStatusBarEntry } from './sizeStatusBarEntry';
|
||||
import { ZoomStatusBarEntry } from './zoomStatusBarEntry';
|
||||
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
const sizeStatusBarEntry = new SizeStatusBarEntry();
|
||||
context.subscriptions.push(sizeStatusBarEntry);
|
||||
|
||||
const binarySizeStatusBarEntry = new BinarySizeStatusBarEntry();
|
||||
context.subscriptions.push(binarySizeStatusBarEntry);
|
||||
|
||||
const zoomStatusBarEntry = new ZoomStatusBarEntry();
|
||||
context.subscriptions.push(zoomStatusBarEntry);
|
||||
|
||||
const previewManager = new PreviewManager(context.extensionUri, sizeStatusBarEntry, binarySizeStatusBarEntry, zoomStatusBarEntry);
|
||||
|
||||
context.subscriptions.push(vscode.window.registerCustomEditorProvider(PreviewManager.viewType, previewManager, {
|
||||
supportsMultipleEditorsPerDocument: true,
|
||||
}));
|
||||
|
||||
context.subscriptions.push(vscode.commands.registerCommand('imagePreview.zoomIn', () => {
|
||||
previewManager.activePreview?.zoomIn();
|
||||
}));
|
||||
|
||||
context.subscriptions.push(vscode.commands.registerCommand('imagePreview.zoomOut', () => {
|
||||
previewManager.activePreview?.zoomOut();
|
||||
}));
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { Disposable } from './dispose';
|
||||
|
||||
export abstract class PreviewStatusBarEntry extends Disposable {
|
||||
private _showOwner: string | undefined;
|
||||
|
||||
protected readonly entry: vscode.StatusBarItem;
|
||||
|
||||
constructor(options: vscode.window.StatusBarItemOptions) {
|
||||
super();
|
||||
this.entry = this._register(vscode.window.createStatusBarItem(options));
|
||||
}
|
||||
|
||||
protected showItem(owner: string, text: string) {
|
||||
this._showOwner = owner;
|
||||
this.entry.text = text;
|
||||
this.entry.show();
|
||||
}
|
||||
|
||||
public hide(owner: string) {
|
||||
if (owner === this._showOwner) {
|
||||
this.entry.hide();
|
||||
this._showOwner = undefined;
|
||||
}
|
||||
}
|
||||
}
|
266
lib/vscode/extensions/image-preview/src/preview.ts
Normal file
266
lib/vscode/extensions/image-preview/src/preview.ts
Normal file
@ -0,0 +1,266 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { Disposable } from './dispose';
|
||||
import { SizeStatusBarEntry } from './sizeStatusBarEntry';
|
||||
import { Scale, ZoomStatusBarEntry } from './zoomStatusBarEntry';
|
||||
import { BinarySizeStatusBarEntry } from './binarySizeStatusBarEntry';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
|
||||
export class PreviewManager implements vscode.CustomReadonlyEditorProvider {
|
||||
|
||||
public static readonly viewType = 'imagePreview.previewEditor';
|
||||
|
||||
private readonly _previews = new Set<Preview>();
|
||||
private _activePreview: Preview | undefined;
|
||||
|
||||
constructor(
|
||||
private readonly extensionRoot: vscode.Uri,
|
||||
private readonly sizeStatusBarEntry: SizeStatusBarEntry,
|
||||
private readonly binarySizeStatusBarEntry: BinarySizeStatusBarEntry,
|
||||
private readonly zoomStatusBarEntry: ZoomStatusBarEntry,
|
||||
) { }
|
||||
|
||||
public async openCustomDocument(uri: vscode.Uri) {
|
||||
return { uri, dispose: () => { } };
|
||||
}
|
||||
|
||||
public async resolveCustomEditor(
|
||||
document: vscode.CustomDocument,
|
||||
webviewEditor: vscode.WebviewPanel,
|
||||
): Promise<void> {
|
||||
const preview = new Preview(this.extensionRoot, document.uri, webviewEditor, this.sizeStatusBarEntry, this.binarySizeStatusBarEntry, this.zoomStatusBarEntry);
|
||||
this._previews.add(preview);
|
||||
this.setActivePreview(preview);
|
||||
|
||||
webviewEditor.onDidDispose(() => { this._previews.delete(preview); });
|
||||
|
||||
webviewEditor.onDidChangeViewState(() => {
|
||||
if (webviewEditor.active) {
|
||||
this.setActivePreview(preview);
|
||||
} else if (this._activePreview === preview && !webviewEditor.active) {
|
||||
this.setActivePreview(undefined);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public get activePreview() { return this._activePreview; }
|
||||
|
||||
private setActivePreview(value: Preview | undefined): void {
|
||||
this._activePreview = value;
|
||||
this.setPreviewActiveContext(!!value);
|
||||
}
|
||||
|
||||
private setPreviewActiveContext(value: boolean) {
|
||||
vscode.commands.executeCommand('setContext', 'imagePreviewFocus', value);
|
||||
}
|
||||
}
|
||||
|
||||
const enum PreviewState {
|
||||
Disposed,
|
||||
Visible,
|
||||
Active,
|
||||
}
|
||||
|
||||
class Preview extends Disposable {
|
||||
|
||||
private readonly id: string = `${Date.now()}-${Math.random().toString()}`;
|
||||
|
||||
private _previewState = PreviewState.Visible;
|
||||
private _imageSize: string | undefined;
|
||||
private _imageBinarySize: number | undefined;
|
||||
private _imageZoom: Scale | undefined;
|
||||
|
||||
private readonly emptyPngDataUri = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAEElEQVR42gEFAPr/AP///wAI/AL+Sr4t6gAAAABJRU5ErkJggg==';
|
||||
|
||||
constructor(
|
||||
private readonly extensionRoot: vscode.Uri,
|
||||
private readonly resource: vscode.Uri,
|
||||
private readonly webviewEditor: vscode.WebviewPanel,
|
||||
private readonly sizeStatusBarEntry: SizeStatusBarEntry,
|
||||
private readonly binarySizeStatusBarEntry: BinarySizeStatusBarEntry,
|
||||
private readonly zoomStatusBarEntry: ZoomStatusBarEntry,
|
||||
) {
|
||||
super();
|
||||
const resourceRoot = resource.with({
|
||||
path: resource.path.replace(/\/[^\/]+?\.\w+$/, '/'),
|
||||
});
|
||||
|
||||
webviewEditor.webview.options = {
|
||||
enableScripts: true,
|
||||
localResourceRoots: [
|
||||
resourceRoot,
|
||||
extensionRoot,
|
||||
]
|
||||
};
|
||||
|
||||
this._register(webviewEditor.webview.onDidReceiveMessage(message => {
|
||||
switch (message.type) {
|
||||
case 'size':
|
||||
{
|
||||
this._imageSize = message.value;
|
||||
this.update();
|
||||
break;
|
||||
}
|
||||
case 'zoom':
|
||||
{
|
||||
this._imageZoom = message.value;
|
||||
this.update();
|
||||
break;
|
||||
}
|
||||
|
||||
case 'reopen-as-text':
|
||||
{
|
||||
vscode.commands.executeCommand('vscode.openWith', resource, 'default', webviewEditor.viewColumn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(zoomStatusBarEntry.onDidChangeScale(e => {
|
||||
if (this._previewState === PreviewState.Active) {
|
||||
this.webviewEditor.webview.postMessage({ type: 'setScale', scale: e.scale });
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(webviewEditor.onDidChangeViewState(() => {
|
||||
this.update();
|
||||
this.webviewEditor.webview.postMessage({ type: 'setActive', value: this.webviewEditor.active });
|
||||
}));
|
||||
|
||||
this._register(webviewEditor.onDidDispose(() => {
|
||||
if (this._previewState === PreviewState.Active) {
|
||||
this.sizeStatusBarEntry.hide(this.id);
|
||||
this.binarySizeStatusBarEntry.hide(this.id);
|
||||
this.zoomStatusBarEntry.hide(this.id);
|
||||
}
|
||||
this._previewState = PreviewState.Disposed;
|
||||
}));
|
||||
|
||||
const watcher = this._register(vscode.workspace.createFileSystemWatcher(resource.fsPath));
|
||||
this._register(watcher.onDidChange(e => {
|
||||
if (e.toString() === this.resource.toString()) {
|
||||
this.render();
|
||||
}
|
||||
}));
|
||||
this._register(watcher.onDidDelete(e => {
|
||||
if (e.toString() === this.resource.toString()) {
|
||||
this.webviewEditor.dispose();
|
||||
}
|
||||
}));
|
||||
|
||||
vscode.workspace.fs.stat(resource).then(({ size }) => {
|
||||
this._imageBinarySize = size;
|
||||
this.update();
|
||||
});
|
||||
|
||||
this.render();
|
||||
this.update();
|
||||
this.webviewEditor.webview.postMessage({ type: 'setActive', value: this.webviewEditor.active });
|
||||
}
|
||||
|
||||
public zoomIn() {
|
||||
if (this._previewState === PreviewState.Active) {
|
||||
this.webviewEditor.webview.postMessage({ type: 'zoomIn' });
|
||||
}
|
||||
}
|
||||
|
||||
public zoomOut() {
|
||||
if (this._previewState === PreviewState.Active) {
|
||||
this.webviewEditor.webview.postMessage({ type: 'zoomOut' });
|
||||
}
|
||||
}
|
||||
|
||||
private async render() {
|
||||
if (this._previewState !== PreviewState.Disposed) {
|
||||
this.webviewEditor.webview.html = await this.getWebviewContents();
|
||||
}
|
||||
}
|
||||
|
||||
private update() {
|
||||
if (this._previewState === PreviewState.Disposed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.webviewEditor.active) {
|
||||
this._previewState = PreviewState.Active;
|
||||
this.sizeStatusBarEntry.show(this.id, this._imageSize || '');
|
||||
this.binarySizeStatusBarEntry.show(this.id, this._imageBinarySize);
|
||||
this.zoomStatusBarEntry.show(this.id, this._imageZoom || 'fit');
|
||||
} else {
|
||||
if (this._previewState === PreviewState.Active) {
|
||||
this.sizeStatusBarEntry.hide(this.id);
|
||||
this.binarySizeStatusBarEntry.hide(this.id);
|
||||
this.zoomStatusBarEntry.hide(this.id);
|
||||
}
|
||||
this._previewState = PreviewState.Visible;
|
||||
}
|
||||
}
|
||||
|
||||
private async getWebviewContents(): Promise<string> {
|
||||
const version = Date.now().toString();
|
||||
const settings = {
|
||||
isMac: process.platform === 'darwin',
|
||||
src: await this.getResourcePath(this.webviewEditor, this.resource, version),
|
||||
};
|
||||
|
||||
const nonce = Date.now().toString();
|
||||
|
||||
return /* html */`<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<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">
|
||||
|
||||
<title>Image Preview</title>
|
||||
|
||||
<link rel="stylesheet" href="${escapeAttribute(this.extensionResource('/media/main.css'))}" type="text/css" media="screen" nonce="${nonce}">
|
||||
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' data: ${this.webviewEditor.webview.cspSource}; script-src 'nonce-${nonce}'; style-src 'self' 'nonce-${nonce}';">
|
||||
<meta id="image-preview-settings" data-settings="${escapeAttribute(JSON.stringify(settings))}">
|
||||
</head>
|
||||
<body class="container image scale-to-fit loading">
|
||||
<div class="loading-indicator"></div>
|
||||
<div class="image-load-error">
|
||||
<p>${localize('preview.imageLoadError', "An error occurred while loading the image.")}</p>
|
||||
<a href="#" class="open-file-link">${localize('preview.imageLoadErrorLink', "Open file using VS Code's standard text/binary editor?")}</a>
|
||||
</div>
|
||||
<script src="${escapeAttribute(this.extensionResource('/media/main.js'))}" nonce="${nonce}"></script>
|
||||
</body>
|
||||
</html>`;
|
||||
}
|
||||
|
||||
private async getResourcePath(webviewEditor: vscode.WebviewPanel, resource: vscode.Uri, version: string): Promise<string> {
|
||||
if (resource.scheme === 'git') {
|
||||
const stat = await vscode.workspace.fs.stat(resource);
|
||||
if (stat.size === 0) {
|
||||
return this.emptyPngDataUri;
|
||||
}
|
||||
}
|
||||
|
||||
// Avoid adding cache busting if there is already a query string
|
||||
if (resource.query) {
|
||||
return webviewEditor.webview.asWebviewUri(resource).toString();
|
||||
}
|
||||
return webviewEditor.webview.asWebviewUri(resource).with({ query: `version=${version}` }).toString();
|
||||
}
|
||||
|
||||
private extensionResource(path: string) {
|
||||
return this.webviewEditor.webview.asWebviewUri(this.extensionRoot.with({
|
||||
path: this.extensionRoot.path + path
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
function escapeAttribute(value: string | vscode.Uri): string {
|
||||
return value.toString().replace(/"/g, '"');
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { PreviewStatusBarEntry } from './ownedStatusBarEntry';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export class SizeStatusBarEntry extends PreviewStatusBarEntry {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'imagePreview.size',
|
||||
name: localize('sizeStatusBar.name', "Image Size"),
|
||||
alignment: vscode.StatusBarAlignment.Right,
|
||||
priority: 101 /* to the left of editor status (100) */,
|
||||
});
|
||||
}
|
||||
|
||||
public show(owner: string, text: string) {
|
||||
this.showItem(owner, text);
|
||||
}
|
||||
}
|
8
lib/vscode/extensions/image-preview/src/typings/ref.d.ts
vendored
Normal file
8
lib/vscode/extensions/image-preview/src/typings/ref.d.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/// <reference path='../../../../src/vs/vscode.d.ts'/>
|
||||
/// <reference path='../../../../src/vs/vscode.proposed.d.ts'/>
|
||||
/// <reference types='@types/node'/>
|
@ -0,0 +1,58 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { PreviewStatusBarEntry as OwnedStatusBarEntry } from './ownedStatusBarEntry';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
const selectZoomLevelCommandId = '_imagePreview.selectZoomLevel';
|
||||
|
||||
export type Scale = number | 'fit';
|
||||
|
||||
export class ZoomStatusBarEntry extends OwnedStatusBarEntry {
|
||||
|
||||
private readonly _onDidChangeScale = this._register(new vscode.EventEmitter<{ scale: Scale }>());
|
||||
public readonly onDidChangeScale = this._onDidChangeScale.event;
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'imagePreview.zoom',
|
||||
name: localize('zoomStatusBar.name', "Image Zoom"),
|
||||
alignment: vscode.StatusBarAlignment.Right,
|
||||
priority: 102 /* to the left of editor size entry (101) */,
|
||||
});
|
||||
|
||||
this._register(vscode.commands.registerCommand(selectZoomLevelCommandId, async () => {
|
||||
type MyPickItem = vscode.QuickPickItem & { scale: Scale };
|
||||
|
||||
const scales: Scale[] = [10, 5, 2, 1, 0.5, 0.2, 'fit'];
|
||||
const options = scales.map((scale): MyPickItem => ({
|
||||
label: this.zoomLabel(scale),
|
||||
scale
|
||||
}));
|
||||
|
||||
const pick = await vscode.window.showQuickPick(options, {
|
||||
placeHolder: localize('zoomStatusBar.placeholder', "Select zoom level")
|
||||
});
|
||||
if (pick) {
|
||||
this._onDidChangeScale.fire({ scale: pick.scale });
|
||||
}
|
||||
}));
|
||||
|
||||
this.entry.command = selectZoomLevelCommandId;
|
||||
}
|
||||
|
||||
public show(owner: string, scale: Scale) {
|
||||
this.showItem(owner, this.zoomLabel(scale));
|
||||
}
|
||||
|
||||
private zoomLabel(scale: Scale): string {
|
||||
return scale === 'fit'
|
||||
? localize('zoomStatusBar.wholeImageLabel', "Whole Image")
|
||||
: `${Math.round(scale * 100)}%`;
|
||||
}
|
||||
}
|
10
lib/vscode/extensions/image-preview/tsconfig.json
Normal file
10
lib/vscode/extensions/image-preview/tsconfig.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "../shared.tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out",
|
||||
"experimentalDecorators": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
]
|
||||
}
|
46
lib/vscode/extensions/image-preview/yarn.lock
Normal file
46
lib/vscode/extensions/image-preview/yarn.lock
Normal file
@ -0,0 +1,46 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
applicationinsights@1.0.8:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.0.8.tgz#db6e3d983cf9f9405fe1ee5ba30ac6e1914537b5"
|
||||
integrity sha512-KzOOGdphOS/lXWMFZe5440LUdFbrLpMvh2SaRxn7BmiI550KAoSb2gIhiq6kJZ9Ir3AxRRztjhzif+e5P5IXIg==
|
||||
dependencies:
|
||||
diagnostic-channel "0.2.0"
|
||||
diagnostic-channel-publishers "0.2.1"
|
||||
zone.js "0.7.6"
|
||||
|
||||
diagnostic-channel-publishers@0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.2.1.tgz#8e2d607a8b6d79fe880b548bc58cc6beb288c4f3"
|
||||
integrity sha1-ji1geottef6IC1SLxYzGvrKIxPM=
|
||||
|
||||
diagnostic-channel@0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/diagnostic-channel/-/diagnostic-channel-0.2.0.tgz#cc99af9612c23fb1fff13612c72f2cbfaa8d5a17"
|
||||
integrity sha1-zJmvlhLCP7H/8TYSxy8sv6qNWhc=
|
||||
dependencies:
|
||||
semver "^5.3.0"
|
||||
|
||||
semver@^5.3.0:
|
||||
version "5.5.0"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
|
||||
integrity sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==
|
||||
|
||||
vscode-extension-telemetry@0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-extension-telemetry/-/vscode-extension-telemetry-0.1.1.tgz#91387e06b33400c57abd48979b0e790415ae110b"
|
||||
integrity sha512-TkKKG/B/J94DP5qf6xWB4YaqlhWDg6zbbqVx7Bz//stLQNnfE9XS1xm3f6fl24c5+bnEK0/wHgMgZYKIKxPeUA==
|
||||
dependencies:
|
||||
applicationinsights "1.0.8"
|
||||
|
||||
vscode-nls@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.0.0.tgz#4001c8a6caba5cedb23a9c5ce1090395c0e44002"
|
||||
integrity sha512-qCfdzcH+0LgQnBpZA53bA32kzp9rpq/f66Som577ObeuDlFIrtbEJ+A/+CCxjIh4G8dpJYNCKIsxpRAHIfsbNw==
|
||||
|
||||
zone.js@0.7.6:
|
||||
version "0.7.6"
|
||||
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.7.6.tgz#fbbc39d3e0261d0986f1ba06306eb3aeb0d22009"
|
||||
integrity sha1-+7w50+AmHQmG8boGMG6zrrDSIAk=
|
Reference in New Issue
Block a user