Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"es6": true
},
"parserOptions": {
"ecmaVersion": 2020,
"sourceType": "module"
},
"extends": "eslint:recommended",
Expand Down
82 changes: 82 additions & 0 deletions app/control-panel-assets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* KasmVNC: HTML5 VNC client
* Copyright (C) 2026 Kasm Technologies
* Licensed under MPL 2.0 (see LICENSE.txt)
*/

import alt from './images/alt.svg';
import clipboard from './images/clipboard.svg';
import connect from './images/connect.svg';
import ctrl from './images/ctrl.svg';
import ctrlAltDel from './images/ctrlaltdel.svg';
import desktop from './images/desktop-regular.svg';
import disconnect from './images/disconnect.svg';
import drag from './images/drag.svg';
import esc from './images/esc.svg';
import expander from './images/expander.svg';
import fullscreen from './images/fullscreen.svg';
import gamepad from './images/gamepad.png';
import handle from './images/handle.svg';
import handleBackground from './images/handle_bg.svg';
import kasmLogo from './images/icons/kasm_logo.svg';
import keyboard from './images/keyboard.svg';
import power from './images/power.svg';
import settings from './images/settings.svg';
import tab from './images/tab.svg';
import toggleExtraKeys from './images/toggleextrakeys.svg';
import windows from './images/windows.svg';
import packageInfo from '../package.json';

const controlPanelAssets = {
alt,
clipboard,
connect,
ctrl,
ctrlAltDel,
desktop,
disconnect,
drag,
esc,
fullscreen,
gamepad,
kasmLogo,
keyboard,
power,
settings,
tab,
toggleExtraKeys,
windows,
};

function cssUrl(asset) {
return `url(${JSON.stringify(asset)})`;
}

export function applyControlPanelAssets() {
document.querySelectorAll('[data-control-panel-src]').forEach((element) => {
const asset = controlPanelAssets[element.dataset.controlPanelSrc];
if (asset) {
element.src = asset;
}
});

const style = document.documentElement.style;
style.setProperty('--noVNC-control-bar-handle-background', cssUrl(handleBackground));
style.setProperty('--noVNC-control-bar-handle', cssUrl(handle));
style.setProperty('--noVNC-control-bar-expander', cssUrl(expander));
style.setProperty('--noVNC-control-panel-font-family', "'Orbitron', 'OrbitronTTF', sans-serif");

document.querySelectorAll('.noVNC_version')
.forEach(element => element.innerText = packageInfo.version);
}

export function applyKeyboardControlAssets() {
const style = document.documentElement.style;
style.setProperty('--noVNC-keyboard-control-ctrl', cssUrl(ctrl));
style.setProperty('--noVNC-keyboard-control-alt', cssUrl(alt));
style.setProperty('--noVNC-keyboard-control-windows', cssUrl(windows));
style.setProperty('--noVNC-keyboard-control-tab', cssUrl(tab));
style.setProperty('--noVNC-keyboard-control-escape', cssUrl(esc));
style.setProperty('--noVNC-keyboard-control-ctrl-alt-del', cssUrl(ctrlAltDel));
style.setProperty('--noVNC-keyboard-control-keyboard', cssUrl(keyboard));
}
22 changes: 11 additions & 11 deletions app/styles/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -437,14 +437,14 @@ select:active {
z-index: -1;
cursor: pointer;
border-radius: 5px;
background-image: url("../images/handle_bg.svg");
background-image: var(--noVNC-control-bar-handle-background, none);
background-repeat: no-repeat;
background-position: right;
}
#noVNC_control_bar_handle:after {
content: "";
transition: transform 0.5s ease-in-out;
background: url("../images/handle.svg");
background-image: var(--noVNC-control-bar-handle, none);
background-repeat: no-repeat;
background-position: center;
position: absolute;
Expand Down Expand Up @@ -646,7 +646,7 @@ select:active {

}
.noVNC_expander::before {
content: url("../images/expander.svg");
content: var(--noVNC-control-bar-expander, "");
display: inline-block;
margin-right: 5px;
transition: 0.2s ease-in-out;
Expand Down Expand Up @@ -937,7 +937,7 @@ select:active {

.noVNC_logo {
color:yellow;
font-family: 'Orbitron', 'OrbitronTTF', sans-serif;
font-family: var(--noVNC-control-panel-font-family, sans-serif);
line-height:90%;
text-shadow: 0.1em 0.1em 0 black;
margin-bottom: 0px;
Expand Down Expand Up @@ -1012,38 +1012,38 @@ body {
}

.keyboard-controls .button.ctrl {
background-image: url("../images/ctrl.svg");
background-image: var(--noVNC-keyboard-control-ctrl, none);
background-size: contain;
}

.keyboard-controls .button.alt {
background-image: url("../images/alt.svg");
background-image: var(--noVNC-keyboard-control-alt, none);
background-size: contain;
}

.keyboard-controls .button.windows {
background-size: contain;
background-image: url("../images/windows.svg");
background-image: var(--noVNC-keyboard-control-windows, none);
}

.keyboard-controls .button.tab {
background-size: contain;
background-image: url("../images/tab.svg");
background-image: var(--noVNC-keyboard-control-tab, none);
}

.keyboard-controls .button.escape {
background-size: contain;
background-image: url("../images/esc.svg");
background-image: var(--noVNC-keyboard-control-escape, none);
}

.keyboard-controls .button.ctrlaltdel {
background-size: contain;
background-image: url("../images/ctrlaltdel.svg");
background-image: var(--noVNC-keyboard-control-ctrl-alt-del, none);
}

.keyboard-controls .button.keyboard {
background-size: contain;
background-image: url("../images/keyboard.svg");
background-image: var(--noVNC-keyboard-control-keyboard, none);
}

.keyboard-controls .button.selected {
Expand Down
44 changes: 27 additions & 17 deletions app/ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,24 @@ const UI = {
},
codecDetector: null,
forcedCodecs: [],
controlPanelAssetsModule: null,

getControlPanelAssetsModule() {
if (!UI.controlPanelAssetsModule) {
UI.controlPanelAssetsModule = import('./control-panel-assets.js');
}
return UI.controlPanelAssetsModule;
},

loadControlPanelAssets() {
return UI.getControlPanelAssetsModule()
.then(module => module.applyControlPanelAssets());
},

loadKeyboardControlAssets() {
return UI.getControlPanelAssetsModule()
.then(module => module.applyKeyboardControlAssets());
},

prime: async () => {
await WebUtil.initSettings();
Expand Down Expand Up @@ -132,30 +150,20 @@ const UI = {
return;
}

if (!WebUtil.isInsideKasmVDI() || WebUtil.getConfigVar('show_control_bar')) {
UI.loadControlPanelAssets()
.catch(err => Log.Error(`Couldn't load control panel assets: ${err}`));
} else {
document.getElementById('noVNC_control_bar_anchor').style.display = 'none';
}

// Initialize settings then apply quality presents
UI.initSettings();
UI.updateQuality();

// Translate the DOM
l10n.translateDOM();

fetch('./package.json')
.then((response) => {
if (!response.ok) {
throw Error("" + response.status + " " + response.statusText);
}
return response.json();
})
.then((packageInfo) => {
Array.from(document.getElementsByClassName('noVNC_version')).forEach(el => el.innerText = packageInfo.version);
})
.catch((err) => {
Log.Error("Couldn't fetch package.json: " + err);
Array.from(document.getElementsByClassName('noVNC_version_wrapper'))
.concat(Array.from(document.getElementsByClassName('noVNC_version_separator')))
.forEach(el => el.style.display = 'none');
});

// Adapt the interface for touch screen devices
if (isTouchDevice) {
document.documentElement.classList.add("noVNC_touch");
Expand Down Expand Up @@ -3279,6 +3287,8 @@ const UI = {
},

showKeyboardControls() {
UI.loadKeyboardControlAssets()
.catch(err => Log.Error(`Couldn't load keyboard control assets: ${err}`));
document.getElementById('noVNC_keyboard_control').classList.add("is-visible");
},

Expand Down
Loading