]> git.proxmox.com Git - mirror_novnc.git/blame - include/ui.js
API change: Mouse/kbd handling to include/input.js
[mirror_novnc.git] / include / ui.js
CommitLineData
15046f00
JM
1/*
2 * noVNC: HTML5 VNC client
3 * Copyright (C) 2010 Joel Martin
5f409eee 4 * Licensed under LGPL-3 (see LICENSE.txt)
15046f00
JM
5 *
6 * See README.md for usage and integration instructions.
7 */
43cf7bd8 8
15046f00 9"use strict";
43cf7bd8
JM
10/*jslint white: false, browser: true */
11/*global window, $D, Util, WebUtil, RFB, Canvas, Element, Fx */
15046f00 12
f7ec5b2c 13var UI = {
91308399 14
da6dd893
JM
15settingsOpen : false,
16
f7ec5b2c 17// Render default UI and initialize settings menu
91308399 18load: function(target) {
f7ec5b2c 19 var html = '', i, sheet, sheets, llevels;
91308399 20
f7ec5b2c 21 /* Populate the 'target' DOM element with default UI */
e4671910
JM
22 if (!target) {
23 target = $D('vnc');
24 } else if (typeof target === 'string') {
25 target = $D(target);
26 }
91308399 27
e66f3f89
JM
28 if ((!document.createElement('canvas').getContext) &&
29 window.ActiveXObject) {
30 // Suggest Chrome frame for Internet Explorer users
31 html += '<center><div style="text-align: left; width: 400px">';
32 html += ' You are using a version of Internet Explorer ';
33 html += ' that does not have HTML5 Canvas support. ';
34 html += ' To use noVNC you must use a browser with HTML5 ';
35 html += ' Canvas support or install ';
36 html += ' <a href="http://google.com/chromeframe" target="cframe">';
37 html += ' Google Chrome Frame.</a>';
38 html += '</div></center>';
e4671910 39 target.innerHTML = html;
e66f3f89
JM
40 return;
41 }
42
91308399
JM
43 html += '<div id="VNC_controls">';
44 html += ' <ul>';
45 html += ' <li>Host: <input id="VNC_host"></li>';
46 html += ' <li>Port: <input id="VNC_port"></li>';
47 html += ' <li>Password: <input id="VNC_password"';
48 html += ' type="password"></li>';
91308399
JM
49 html += ' <li><input id="VNC_connect_button" type="button"';
50 html += ' value="Loading" disabled></li>';
51 html += ' </ul>';
52 html += '</div>';
53 html += '<div id="VNC_screen">';
63708ff5
JM
54 html += ' <div id="VNC_status_bar" class="VNC_status_bar" style="margin-top: 0px;">';
55 html += ' <table border=0 width=100%><tr>';
56 html += ' <td><div id="VNC_status">Loading</div></td>';
da6dd893
JM
57 html += ' <td width=1%><div class="VNC_buttons_right">';
58 html += ' <input type=button class="VNC_status_button" value="Settings"';
59 html += ' id="menuButton"';
f7ec5b2c 60 html += ' onclick="UI.clickSettingsMenu();">';
da6dd893 61 html += ' <span id="VNC_settings_menu"';
f7ec5b2c
JM
62 html += ' onmouseover="UI.canvasBlur();"';
63 html += ' onmouseout="UI.canvasFocus();">';
da6dd893
JM
64 html += ' <ul>';
65 html += ' <li><input id="VNC_encrypt"';
208c832b 66 html += ' type="checkbox"> Encrypt</li>';
da6dd893
JM
67 html += ' <li><input id="VNC_true_color"';
68 html += ' type="checkbox" checked> True Color</li>';
69 html += ' <li><input id="VNC_cursor"';
31a837d5 70 html += ' type="checkbox"> Local Cursor</li>';
f1a9971c
JM
71 html += ' <li><input id="VNC_shared"';
72 html += ' type="checkbox"> Shared Mode</li>';
ff36b127
JM
73 html += ' <li><input id="VNC_connectTimeout"';
74 html += ' type="input"> Connect Timeout (s)</li>';
da6dd893
JM
75 html += ' <hr>';
76
77 // Stylesheet selection dropdown
78 html += ' <li><select id="VNC_stylesheet" name="vncStyle">';
79 html += ' <option value="default">default</option>';
8d5d2c82
AM
80 sheet = WebUtil.selectStylesheet();
81 sheets = WebUtil.getStylesheets();
8db09746 82 for (i = 0; i < sheets.length; i += 1) {
da6dd893
JM
83 html += '<option value="' + sheets[i].title + '">' + sheets[i].title + '</option>';
84 }
85 html += ' </select> Style</li>';
86
87 // Logging selection dropdown
88 html += ' <li><select id="VNC_logging" name="vncLogging">';
89 llevels = ['error', 'warn', 'info', 'debug'];
8db09746 90 for (i = 0; i < llevels.length; i += 1) {
da6dd893
JM
91 html += '<option value="' + llevels[i] + '">' + llevels[i] + '</option>';
92 }
93 html += ' </select> Logging</li>';
94
95 html += ' <hr>';
96 html += ' <li><input type="button" id="VNC_apply" value="Apply"';
f7ec5b2c 97 html += ' onclick="UI.settingsApply()"></li>';
da6dd893
JM
98 html += ' </ul>';
99 html += ' </span></div></td>';
100 html += ' <td width=1%><div class="VNC_buttons_right">';
101 html += ' <input type=button class="VNC_status_button" value="Send CtrlAltDel"';
160fabf6 102 html += ' id="sendCtrlAltDelButton"';
f7ec5b2c 103 html += ' onclick="UI.sendCtrlAltDel();"></div></td>';
63708ff5
JM
104 html += ' </tr></table>';
105 html += ' </div>';
91308399
JM
106 html += ' <canvas id="VNC_canvas" width="640px" height="20px">';
107 html += ' Canvas not supported.';
108 html += ' </canvas>';
109 html += '</div>';
110 html += '<br><br>';
111 html += '<div id="VNC_clipboard">';
112 html += ' VNC Clipboard:';
113 html += ' <input id="VNC_clipboard_clear_button"';
114 html += ' type="button" value="Clear"';
f7ec5b2c 115 html += ' onclick="UI.clipClear();">';
91308399
JM
116 html += ' <br>';
117 html += ' <textarea id="VNC_clipboard_text" cols=80 rows=5';
f7ec5b2c
JM
118 html += ' onfocus="UI.canvasBlur();"';
119 html += ' onblur="UI.canvasFocus();"';
120 html += ' onchange="UI.clipSend();"></textarea>';
91308399 121 html += '</div>';
e4671910 122 target.innerHTML = html;
91308399 123
da6dd893 124 // Settings with immediate effects
f7ec5b2c
JM
125 UI.initSetting('logging', 'warn');
126 WebUtil.init_logging(UI.getSetting('logging'));
127 UI.initSetting('stylesheet', 'default');
8db09746 128
8d5d2c82 129 WebUtil.selectStylesheet(null); // call twice to get around webkit bug
f7ec5b2c 130 WebUtil.selectStylesheet(UI.getSetting('stylesheet'));
da6dd893 131
91308399 132 /* Populate the controls if defaults are provided in the URL */
f7ec5b2c
JM
133 UI.initSetting('host', '');
134 UI.initSetting('port', '');
135 UI.initSetting('password', '');
136 UI.initSetting('encrypt', false);
137 UI.initSetting('true_color', true);
138 UI.initSetting('cursor', false);
139 UI.initSetting('shared', true);
140 UI.initSetting('connectTimeout', 2);
141
e4671910 142 UI.rfb = RFB({'target': $D('VNC_canvas'),
f7ec5b2c
JM
143 'updateState': UI.updateState,
144 'clipboardReceive': UI.clipReceive});
8db09746
JM
145
146 // Unfocus clipboard when over the VNC area
e4671910 147 $D('VNC_screen').onmousemove = function () {
f7ec5b2c 148 var canvas = UI.rfb.get_canvas();
8db09746 149 if ((! canvas) || (! canvas.get_focused())) {
e4671910 150 $D('VNC_clipboard_text').blur();
3954ae14
JM
151 }
152 };
8db09746 153
91308399
JM
154},
155
da6dd893
JM
156// Read form control compatible setting from cookie
157getSetting: function(name) {
e4671910 158 var val, ctrl = $D('VNC_' + name);
8d5d2c82 159 val = WebUtil.readCookie(name);
da6dd893
JM
160 if (ctrl.type === 'checkbox') {
161 if (val.toLowerCase() in {'0':1, 'no':1, 'false':1}) {
162 val = false;
163 } else {
164 val = true;
165 }
166 }
167 return val;
168},
169
170// Update cookie and form control setting. If value is not set, then
171// updates from control to current cookie setting.
172updateSetting: function(name, value) {
e4671910 173 var i, ctrl = $D('VNC_' + name);
da6dd893
JM
174 // Save the cookie for this session
175 if (typeof value !== 'undefined') {
8d5d2c82 176 WebUtil.createCookie(name, value);
da6dd893
JM
177 }
178
179 // Update the settings control
f7ec5b2c 180 value = UI.getSetting(name);
da6dd893
JM
181 if (ctrl.type === 'checkbox') {
182 ctrl.checked = value;
183 } else if (typeof ctrl.options !== 'undefined') {
8db09746 184 for (i = 0; i < ctrl.options.length; i += 1) {
da6dd893
JM
185 if (ctrl.options[i].value === value) {
186 ctrl.selectedIndex = i;
187 break;
188 }
189 }
190 } else {
191 ctrl.value = value;
192 }
193},
194
195// Save control setting to cookie
196saveSetting: function(name) {
e4671910 197 var val, ctrl = $D('VNC_' + name);
da6dd893
JM
198 if (ctrl.type === 'checkbox') {
199 val = ctrl.checked;
200 } else if (typeof ctrl.options !== 'undefined') {
201 val = ctrl.options[ctrl.selectedIndex].value;
202 } else {
203 val = ctrl.value;
204 }
8d5d2c82 205 WebUtil.createCookie(name, val);
8db09746 206 //Util.Debug("Setting saved '" + name + "=" + val + "'");
da6dd893
JM
207 return val;
208},
209
210// Initial page load read/initialization of settings
211initSetting: function(name, defVal) {
a8edf9d8 212 var val;
da6dd893
JM
213
214 // Check Query string followed by cookie
8d5d2c82 215 val = WebUtil.getQueryVar(name);
da6dd893 216 if (val === null) {
8d5d2c82 217 val = WebUtil.readCookie(name, defVal);
da6dd893 218 }
f7ec5b2c 219 UI.updateSetting(name, val);
8db09746 220 //Util.Debug("Setting '" + name + "' initialized to '" + val + "'");
da6dd893
JM
221 return val;
222},
223
224
225// Toggle the settings menu:
226// On open, settings are refreshed from saved cookies.
227// On close, settings are applied
228clickSettingsMenu: function() {
f7ec5b2c
JM
229 if (UI.settingsOpen) {
230 UI.settingsApply();
da6dd893 231
f7ec5b2c 232 UI.closeSettingsMenu();
da6dd893 233 } else {
f7ec5b2c
JM
234 UI.updateSetting('encrypt');
235 UI.updateSetting('true_color');
236 if (UI.rfb.get_canvas().get_cursor_uri()) {
237 UI.updateSetting('cursor');
da6dd893 238 } else {
f7ec5b2c 239 UI.updateSetting('cursor', false);
e4671910 240 $D('VNC_cursor').disabled = true;
da6dd893 241 }
f7ec5b2c
JM
242 UI.updateSetting('shared');
243 UI.updateSetting('connectTimeout');
244 UI.updateSetting('stylesheet');
245 UI.updateSetting('logging');
da6dd893 246
f7ec5b2c 247 UI.openSettingsMenu();
da6dd893
JM
248 }
249},
250
251// Open menu
252openSettingsMenu: function() {
e4671910 253 $D('VNC_settings_menu').style.display = "block";
f7ec5b2c 254 UI.settingsOpen = true;
da6dd893
JM
255},
256
257// Close menu (without applying settings)
258closeSettingsMenu: function() {
e4671910 259 $D('VNC_settings_menu').style.display = "none";
f7ec5b2c 260 UI.settingsOpen = false;
da6dd893
JM
261},
262
263// Disable/enable controls depending on connection state
b5087acc
JM
264settingsDisabled: function(disabled, rfb) {
265 //Util.Debug(">> settingsDisabled");
e4671910
JM
266 $D('VNC_encrypt').disabled = disabled;
267 $D('VNC_true_color').disabled = disabled;
455e4657 268 if (rfb && rfb.get_canvas() && rfb.get_canvas().get_cursor_uri()) {
e4671910 269 $D('VNC_cursor').disabled = disabled;
da6dd893 270 } else {
f7ec5b2c 271 UI.updateSetting('cursor', false);
e4671910 272 $D('VNC_cursor').disabled = true;
da6dd893 273 }
e4671910
JM
274 $D('VNC_shared').disabled = disabled;
275 $D('VNC_connectTimeout').disabled = disabled;
b5087acc 276 //Util.Debug("<< settingsDisabled");
da6dd893
JM
277},
278
279// Save/apply settings when 'Apply' button is pressed
280settingsApply: function() {
8db09746 281 //Util.Debug(">> settingsApply");
f7ec5b2c
JM
282 UI.saveSetting('encrypt');
283 UI.saveSetting('true_color');
284 if (UI.rfb.get_canvas().get_cursor_uri()) {
285 UI.saveSetting('cursor');
da6dd893 286 }
f7ec5b2c
JM
287 UI.saveSetting('shared');
288 UI.saveSetting('connectTimeout');
289 UI.saveSetting('stylesheet');
290 UI.saveSetting('logging');
da6dd893
JM
291
292 // Settings with immediate (non-connected related) effect
f7ec5b2c
JM
293 WebUtil.selectStylesheet(UI.getSetting('stylesheet'));
294 WebUtil.init_logging(UI.getSetting('logging'));
da6dd893 295
8db09746 296 //Util.Debug("<< settingsApply");
da6dd893
JM
297},
298
299
300
f00b1e37 301setPassword: function() {
e4671910 302 UI.rfb.sendPassword($D('VNC_password').value);
f00b1e37
JM
303 return false;
304},
305
63708ff5 306sendCtrlAltDel: function() {
f7ec5b2c 307 UI.rfb.sendCtrlAltDel();
63708ff5
JM
308},
309
8db09746 310updateState: function(rfb, state, oldstate, msg) {
a7a89626 311 var s, sb, c, cad, klass;
e4671910
JM
312 s = $D('VNC_status');
313 sb = $D('VNC_status_bar');
314 c = $D('VNC_connect_button');
315 cad = $D('sendCtrlAltDelButton');
91308399
JM
316 switch (state) {
317 case 'failed':
f00b1e37 318 case 'fatal':
91308399 319 c.disabled = true;
160fabf6 320 cad.disabled = true;
f7ec5b2c 321 UI.settingsDisabled(true, rfb);
91308399
JM
322 klass = "VNC_status_error";
323 break;
324 case 'normal':
325 c.value = "Disconnect";
f7ec5b2c 326 c.onclick = UI.disconnect;
91308399 327 c.disabled = false;
160fabf6 328 cad.disabled = false;
f7ec5b2c 329 UI.settingsDisabled(true, rfb);
91308399
JM
330 klass = "VNC_status_normal";
331 break;
332 case 'disconnected':
f00b1e37 333 case 'loaded':
91308399 334 c.value = "Connect";
f7ec5b2c 335 c.onclick = UI.connect;
91308399
JM
336
337 c.disabled = false;
160fabf6 338 cad.disabled = true;
f7ec5b2c 339 UI.settingsDisabled(false, rfb);
91308399
JM
340 klass = "VNC_status_normal";
341 break;
f00b1e37
JM
342 case 'password':
343 c.value = "Send Password";
f7ec5b2c 344 c.onclick = UI.setPassword;
f00b1e37
JM
345
346 c.disabled = false;
347 cad.disabled = true;
f7ec5b2c 348 UI.settingsDisabled(true, rfb);
f00b1e37
JM
349 klass = "VNC_status_warn";
350 break;
91308399
JM
351 default:
352 c.disabled = true;
160fabf6 353 cad.disabled = true;
f7ec5b2c 354 UI.settingsDisabled(true, rfb);
91308399
JM
355 klass = "VNC_status_warn";
356 break;
357 }
358
359 if (typeof(msg) !== 'undefined') {
360 s.setAttribute("class", klass);
63708ff5 361 sb.setAttribute("class", klass);
91308399
JM
362 s.innerHTML = msg;
363 }
364
365},
366
8db09746 367clipReceive: function(rfb, text) {
f7ec5b2c 368 Util.Debug(">> UI.clipReceive: " + text.substr(0,40) + "...");
e4671910 369 $D('VNC_clipboard_text').value = text;
f7ec5b2c 370 Util.Debug("<< UI.clipReceive");
8db09746
JM
371},
372
373
91308399 374connect: function() {
f7ec5b2c 375 var host, port, password;
da6dd893 376
f7ec5b2c 377 UI.closeSettingsMenu();
da6dd893 378
e4671910
JM
379 host = $D('VNC_host').value;
380 port = $D('VNC_port').value;
381 password = $D('VNC_password').value;
91308399 382 if ((!host) || (!port)) {
63708ff5 383 throw("Must set host and port");
91308399
JM
384 }
385
f7ec5b2c
JM
386 UI.rfb.set_encrypt(UI.getSetting('encrypt'));
387 UI.rfb.set_true_color(UI.getSetting('true_color'));
388 UI.rfb.set_local_cursor(UI.getSetting('cursor'));
389 UI.rfb.set_shared(UI.getSetting('shared'));
390 UI.rfb.set_connectTimeout(UI.getSetting('connectTimeout'));
da6dd893 391
f7ec5b2c 392 UI.rfb.connect(host, port, password);
91308399
JM
393},
394
395disconnect: function() {
f7ec5b2c 396 UI.closeSettingsMenu();
da6dd893 397
f7ec5b2c 398 UI.rfb.disconnect();
91308399
JM
399},
400
da6dd893 401canvasBlur: function() {
f7ec5b2c 402 UI.rfb.get_canvas().set_focused(false);
91308399
JM
403},
404
da6dd893 405canvasFocus: function() {
f7ec5b2c 406 UI.rfb.get_canvas().set_focused(true);
91308399
JM
407},
408
409clipClear: function() {
e4671910 410 $D('VNC_clipboard_text').value = "";
f7ec5b2c 411 UI.rfb.clipboardPasteFrom("");
91308399
JM
412},
413
414clipSend: function() {
e4671910 415 var text = $D('VNC_clipboard_text').value;
f7ec5b2c
JM
416 Util.Debug(">> UI.clipSend: " + text.substr(0,40) + "...");
417 UI.rfb.clipboardPasteFrom(text);
418 Util.Debug("<< UI.clipSend");
91308399
JM
419}
420
63708ff5 421};