kui-shell
Version:
This is the monorepo for Kui, the hybrid command-line/GUI electron-based Kubernetes tool
310 lines • 15.6 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = require("path");
const core_1 = require("@kui-shell/core");
const sidecar_selector_1 = require("@kui-shell/core/webapp/views/sidecar-selector");
const sidecar_1 = require("@kui-shell/core/webapp/views/sidecar");
const strings = core_1.i18n('plugin-core-support');
const SECONDS_TILL_AUTO_CLOSE = 10;
const usage = {
strict: 'screenshot',
command: 'screenshot',
title: strings('screenshotUsageTitle'),
header: strings('screenshotUsageHeader'),
example: 'screenshot [which]',
detailedExample: [
{ command: 'screenshot sidecar', docs: strings('screenshotSidecarUsageDocs') },
{ command: 'screenshot repl', docs: strings('screenshotReplUsageDocs') },
{
command: 'screenshot last',
docs: strings('screenshotLastUsageDocs')
},
{
command: 'screenshot full',
docs: strings('screenshotFullUsageDocs')
},
{
command: 'screenshot',
docs: strings('screenshotUsageDocs')
}
],
optional: [
{
name: 'which',
positional: true,
docs: strings('screenshotWhichUsageDocs'),
allowed: ['sidecar', 'repl', 'full', 'last', 'nth']
},
{ name: '--nth', docs: strings('screenshotNUsageDocs'), numeric: true }
]
};
const round = Math.round;
const selectors = {
full: 'body',
default: 'body > .page',
sidecar: (tab) => sidecar_selector_1.default(tab),
repl: (tab) => tab.querySelector('.repl'),
nth: (tab, n) => tab.querySelector(`.repl .repl-block:nth-child(${n}) .repl-output .repl-result`),
'last-full': (tab) => tab.querySelector('.repl .repl-block:nth-last-child(2)'),
last: (tab) => tab.querySelector('.repl .repl-block:nth-last-child(2) .repl-output .repl-result')
};
const hideCurrentReplBlock = [
{
selector: '#main-repl .repl-block.processing',
property: 'display',
value: 'none'
}
];
const squishers = {
sidecar: [
{ selector: 'body.subwindow', css: 'screenshot-squish' },
{ selector: 'body.subwindow .page', css: 'screenshot-squish' },
{ selector: 'body.subwindow .main', css: 'screenshot-squish' },
{ selector: 'tab.visible', css: 'screenshot-squish' }
],
full: hideCurrentReplBlock,
repl: hideCurrentReplBlock
};
const _squish = (tab, which, selector, op) => {
let squisher = squishers[which];
if (typeof squisher === 'function') {
squisher = squisher(selector);
}
if (squisher) {
const impl = (dryRun) => squisher
.map(({ selector, property, value, css }) => {
const element = selector === 'tab.visible'
? tab
: typeof selector === 'string'
? document.querySelector(selector)
: selector;
if (element) {
return op(dryRun, element, property, value, css);
}
})
.find(x => x);
const doNotSquish = impl(true);
if (!doNotSquish) {
impl(false);
}
return doNotSquish;
}
};
const squish = (tab, which, selector) => _squish(tab, which, selector, (dryRun, element, property, value, css) => {
if (dryRun) {
const scrollers = element.querySelectorAll('.overflow-auto');
for (let idx = 0; idx < scrollers.length; idx++) {
const scroller = scrollers[idx];
if (scroller.scrollTop) {
return true;
}
}
}
else {
if (css)
element.classList.add(css);
if (property)
element.style[property] = value;
}
});
const unsquish = (tab, which, selector) => _squish(tab, which, selector, (_, element, property, value, css) => {
if (css)
element.classList.remove(css);
if (property)
element.style[property] = null;
});
const fill = (n) => (n < 10 ? `0${n}` : n);
const dateString = (ts) => `${ts.getUTCFullYear()}-${fill(1 + ts.getUTCMonth())}-${fill(ts.getUTCDate())}`;
const timeString = (ts) => ts.toLocaleTimeString('en-us').replace(/:/g, '.');
exports.default = (commandTree) => __awaiter(void 0, void 0, void 0, function* () {
commandTree.listen('/screenshot', ({ tab, argvNoOptions, parsedOptions }) => new Promise((resolve, reject) => __awaiter(void 0, void 0, void 0, function* () {
if (core_1.Capabilities.inBrowser()) {
const error = new Error(strings('notSupportedInBrowser'));
error['code'] = 500;
reject(error);
}
const options = parsedOptions;
try {
const root = path_1.dirname(require.resolve('@kui-shell/plugin-core-support/package.json'));
core_1.UI.injectCSS(path_1.join(root, 'web/css/screenshot.css'));
const { ipcRenderer, nativeImage, remote, shell } = yield Promise.resolve().then(() => require('electron'));
const { app } = remote;
const which = (argvNoOptions[1] && argvNoOptions[1].toLowerCase()) || (options['nth'] && 'nth') || 'default';
let selector = selectors[which];
const N = options['nth'];
if (typeof selector === 'function') {
selector = selector(tab, N);
}
if (which === 'last' && !selector) {
return reject(new Error(strings('screenshotREPLError')));
}
else if (!selector) {
return reject(new core_1.Errors.UsageError({ usage }));
}
else if (which === 'sidecar' && !sidecar_1.isVisible(tab)) {
return reject(new Error(strings('screenshotSidecarNotOpen')));
}
else if (which === 'nth') {
if (N === undefined) {
return reject(new Error('You must provide a numeric value for the "nth" argument'));
}
}
const dom = selector && typeof selector === 'string' ? document.querySelector(selector) : selector;
if (!dom) {
console.error('bad selector', selector);
return reject(new Error(strings('screenshotInternalError')));
}
const screenshotButton = sidecar_selector_1.default(tab, '.sidecar-screenshot-button');
screenshotButton.classList.add('force-no-hover');
const doNotSquish = squish(tab, which, selector);
const snap = () => {
const domRect = dom.getBoundingClientRect();
const rect = {
x: round(domRect.left) + (options.offset ? parseInt(options.offset, 10) : 0),
y: round(domRect.top),
width: round(domRect.width),
height: round(domRect.height)
};
if (which === 'sidecar') {
rect.x += 1;
rect.width -= 1;
}
const listener = (event, buf) => {
document.body.classList.remove('no-tooltips-anywhere');
const page = document.querySelector('body > .page');
if (!buf) {
screenshotButton.classList.remove('force-no-hover');
return reject(new Error('Internal Error'));
}
if (document.getElementById('screenshot-captured') !== null) {
const prevSnapDom = document.getElementById('screenshot-captured');
if (prevSnapDom.kuiSnapshotTimer) {
clearInterval(prevSnapDom.kuiSnapshotTimer);
}
prevSnapDom.remove();
}
const img = nativeImage.createFromBuffer(buf);
const snapDom = document.createElement('div');
const snapImg = document.createElement('img');
const message = document.createElement('div');
const messageContent = document.createElement('div');
const snapContent = document.createElement('div');
const close = document.createElement('div');
page.appendChild(snapDom);
const finish = () => {
snapDom.classList.add('screenshot-hide');
setTimeout(() => snapDom.classList.remove('screenshot-active'), 0);
setTimeout(() => {
page.removeChild(snapDom);
core_1.UI.getCurrentPrompt(tab).readOnly = false;
core_1.UI.getCurrentPrompt(tab).focus();
}, 1000);
};
const windowSize = document.body.getBoundingClientRect();
const imgSize = img.getSize();
let widthPx = windowSize.width * 0.65;
let heightPx = (imgSize.height / imgSize.width) * widthPx;
if (heightPx > windowSize.height) {
heightPx = windowSize.height * 0.65;
widthPx = (imgSize.width / imgSize.height) * heightPx;
}
snapDom.appendChild(snapImg);
snapDom.appendChild(snapContent);
snapDom.appendChild(close);
snapDom.setAttribute('data-notification', '');
snapDom.setAttribute('role', 'polite');
snapDom.setAttribute('data-notification', '');
snapDom.classList.add('bx--toast-notification');
snapDom.classList.add('bx--toast-notification--warning');
snapDom.classList.add('zoomable');
snapDom.id = 'screenshot-captured';
snapDom.classList.add('screenshot-hide');
snapDom.classList.add('screenshot-active');
setTimeout(() => snapDom.classList.remove('screenshot-hide'), 0);
const saveButton = document.createElement('div');
const ts = new Date();
const filename = `Screen Shot ${dateString(ts)} ${timeString(ts)}.png`;
const location = path_1.join(app.getPath('desktop'), filename);
saveButton.className = 'screenshot-save-button';
saveButton.innerHTML = strings('Save to desktop');
saveButton.onclick = () => {
remote.require('fs').writeFile(location, img.toPNG(), () => __awaiter(void 0, void 0, void 0, function* () {
console.log(`screenshot saved to ${location}`);
try {
shell.showItemInFolder(location);
}
catch (err) {
console.error('error opening screenshot file');
}
}));
};
snapImg.setAttribute('src', img.toDataURL());
snapImg.classList.add('screenshot-image');
snapContent.classList.add('screenshot-content');
message.classList.add('screenshot-success-message');
message.innerText = strings('Screenshot copied to clipboard');
messageContent.classList.add('screenshot-message');
messageContent.appendChild(message);
const closeMessage = document.createElement('div');
closeMessage.classList.add('screenshot-closing-message');
closeMessage.setAttribute('id', 'close-msg');
messageContent.appendChild(closeMessage);
snapContent.append(messageContent);
snapContent.appendChild(saveButton);
const closeButton = document.createElement('div');
close.classList.add('screenshot-close');
close.appendChild(closeButton);
closeButton.innerHTML =
'<div style="display: flex;justify-content:flex-end;align-items:baseline"><svg focusable="false" preserveAspectRatio="xMidYMid meet" style="will-change: transform; cursor:pointer" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 32 32" aria-hidden="true"><path d="M24 9.4L22.6 8 16 14.6 9.4 8 8 9.4l6.6 6.6L8 22.6 9.4 24l6.6-6.6 6.6 6.6 1.4-1.4-6.6-6.6L24 9.4z" stroke="white" fill="white"></path></svg></div>';
closeButton.classList.add('screenshot-close-botton');
let timeleft = SECONDS_TILL_AUTO_CLOSE;
snapDom.kuiSnapshotTimer = setInterval(() => {
if (timeleft <= 0) {
clearInterval(snapDom.kuiSnapshotTimer);
finish();
}
;
snapDom.querySelector('.screenshot-closing-message').innerText = strings('Closing in {0} seconds', timeleft.toString());
timeleft -= 1;
}, 1000);
const hiddenInput = document.createElement('input');
hiddenInput.classList.add('hidden');
hiddenInput.classList.add('grab-focus');
snapDom.appendChild(hiddenInput);
hiddenInput.focus();
hiddenInput.addEventListener('keyup', (evt) => {
if (evt.keyCode === core_1.UI.Keys.Codes.ESCAPE) {
evt.preventDefault();
finish();
}
}, { capture: true, once: true });
closeButton.onclick = finish;
ipcRenderer.removeListener('capture-page-to-clipboard-done', listener);
if (!doNotSquish) {
unsquish(tab, which, selector);
}
screenshotButton.classList.remove('force-no-hover');
resolve(strings('Successfully captured a screenshot to the clipboard'));
};
ipcRenderer.on('capture-page-to-clipboard-done', listener);
ipcRenderer.send('capture-page-to-clipboard', remote.getCurrentWebContents().id, rect);
};
document.body.classList.add('no-tooltips-anywhere');
setTimeout(snap, 100);
}
catch (e) {
console.error(e);
reject(new Error('Internal Error'));
}
})), { usage, noAuthOk: true, incognito: ['popup'], requiresLocal: true });
});
//# sourceMappingURL=screenshot.js.map