1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-01-06 13:17:42 +03:00

F #2312: VMRC merged with master (#232)

Signed-off-by: Frederick Borges <fborges@opennebula.io>

Co-authored-by: Tino Vázquez <cvazquez@opennebula.io>
This commit is contained in:
Frederick Borges 2020-09-21 18:44:59 +02:00 committed by Ruben S. Montero
parent 1c3e4a795c
commit 4177637567
No known key found for this signature in database
GPG Key ID: A0CEA6FA880A1D87
44 changed files with 2350 additions and 231 deletions

4
.gitignore vendored
View File

@ -48,6 +48,10 @@ src/sunstone/public/package-lock.json
src/sunstone/guac/node_modules
src/sunstone/guac/dist
src/sunstone/guac/package-lock.json
src/sunstone/vmrc/node_modules
src/sunstone/vmrc/dist
src/sunstone/vmrc/package-lock.json
src/sunstone/vmrc/v8-compile-cache-0/
.tx/config
src/fireedge/node_modules

View File

@ -900,6 +900,7 @@ RUBY_LIB_FILES="src/mad/ruby/ActionManager.rb \
src/oca/ruby/opennebula.rb \
src/sunstone/OpenNebulaVNC.rb \
src/sunstone/OpenNebulaGuac.rb \
src/sunstone/OpenNebulaVMRC.rb \
src/sunstone/OpenNebulaAddons.rb \
src/vmm_mad/remotes/vcenter/vcenter_driver.rb \
src/vmm_mad/remotes/nsx/nsx_driver.rb \
@ -2406,7 +2407,8 @@ SUNSTONE_MODELS_FILES="src/sunstone/models/OpenNebulaJSON.rb \
src/sunstone/models/OpenNebula2FA/SunstoneWebAuthn.rb \
src/sunstone/models/OpenNebula2FA/sunstone_qr_code.rb \
src/sunstone/models/OpenNebula2FA/sunstone_optp.rb \
src/sunstone/models/OpenNebula2FA/sunstone_2f_auth.rb "
src/sunstone/models/OpenNebula2FA/sunstone_2f_auth.rb \
src/sunstone/models/OpenNebulaValidateFireedge.rb"
SUNSTONE_MODELS_JSON_FILES="src/sunstone/models/OpenNebulaJSON/HostJSON.rb \
src/sunstone/models/OpenNebulaJSON/ImageJSON.rb \
@ -2432,6 +2434,7 @@ SUNSTONE_MODELS_JSON_FILES="src/sunstone/models/OpenNebulaJSON/HostJSON.rb \
SUNSTONE_VIEWS_FILES="src/sunstone/views/index.erb \
src/sunstone/views/login.erb \
src/sunstone/views/vnc.erb \
src/sunstone/views/vmrc.erb \
src/sunstone/views/spice.erb \
src/sunstone/views/_login_standard.erb \
src/sunstone/views/_login_x509.erb"

View File

@ -0,0 +1,203 @@
# -------------------------------------------------------------------------- #
# Copyright 2002-2020, OpenNebula Project, OpenNebula Systems #
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
# not use this file except in compliance with the License. You may obtain #
# a copy of the License at #
# #
# http://www.apache.org/licenses/LICENSE-2.0 #
# #
# Unless required by applicable law or agreed to in writing, software #
# distributed under the License is distributed on an "AS IS" BASIS, #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
# See the License for the specific language governing permissions and #
# limitations under the License. #
#--------------------------------------------------------------------------- #
#----------------------------------------------------------------------------#
# This class provides support for launching and stopping a vmrc proxy server #
#----------------------------------------------------------------------------#
require 'rubygems'
require 'json'
require 'opennebula'
require 'base64'
require 'openssl'
require 'vcenter_driver'
require 'fileutils'
if !ONE_LOCATION
VMRC_TICKETS = "/var/lib/one/sunstone_vnc_tokens/vmrc/"
else
VMRC_TICKETS = ONE_LOCATION + "/var/lib/one/sunstone_vnc_tokens/vmrc/"
end
FileUtils.mkdir_p VMRC_TICKETS
VMRC_STATES = [
#0, #LCM_INIT
#1, #PROLOG
#2, #BOOT
"3", #RUNNING
"4", #MIGRATE
#5, #SAVE_STOP
#6, #SAVE_SUSPEND
#7, #SAVE_MIGRATE
#8, #PROLOG_MIGRATE
#9, #PROLOG_RESUME
#10, #EPILOG_STOP
#11, #EPILOG
"12", #SHUTDOWN
"13", #CANCEL
#14, #FAILURE
#15, #CLEANUP_RESUBMIT
"16", #UNKNOWN
"17", #HOTPLUG
"18", #SHUTDOWN_POWEROFF
#19, #BOOT_UNKNOWN
#20, #BOOT_POWEROFF
#21, #BOOT_SUSPENDED
#22, #BOOT_STOPPED
#23, #CLEANUP_DELETE
"24", #HOTPLUG_SNAPSHOT
"25", #HOTPLUG_NIC
"26", #HOTPLUG_SAVEAS
"27", #HOTPLUG_SAVEAS_POWEROFF
"28", #HOTPLUG_SAVEAS_SUSPENDED
"29", #SHUTDOWN_UNDEPLOY
#30, #EPILOG_UNDEPLOY
#31, #PROLOG_UNDEPLOY
#32, #BOOT_UNDEPLOY
#33, #HOTPLUG_PROLOG_POWEROFF
#34, #HOTPLUG_EPILOG_POWEROFF
#35, #BOOT_MIGRATE
#36, #BOOT_FAILURE
#37, #BOOT_MIGRATE_FAILURE
#38, #PROLOG_MIGRATE_FAILURE
#39, #PROLOG_FAILURE
#40, #EPILOG_FAILURE
#41, #EPILOG_STOP_FAILURE
#42, #EPILOG_UNDEPLOY_FAILURE
#43, #PROLOG_MIGRATE_POWEROFF
#44, #PROLOG_MIGRATE_POWEROFF_FAILURE
#45, #PROLOG_MIGRATE_SUSPEND
#46, #PROLOG_MIGRATE_SUSPEND_FAILURE
#47, #BOOT_UNDEPLOY_FAILURE
#48, #BOOT_STOPPED_FAILURE
#49, #PROLOG_RESUME_FAILURE
#50, #PROLOG_UNDEPLOY_FAILURE
#51, #DISK_SNAPSHOT_POWEROFF
#52, #DISK_SNAPSHOT_REVERT_POWEROFF
#53, #DISK_SNAPSHOT_DELETE_POWEROFF
#54, #DISK_SNAPSHOT_SUSPENDED
#55, #DISK_SNAPSHOT_REVERT_SUSPENDED
#56, #DISK_SNAPSHOT_DELETE_SUSPENDED
"57", #DISK_SNAPSHOT
"58", #DISK_SNAPSHOT_REVERT
#59, #DISK_SNAPSHOT_DELETE
#60, #PROLOG_MIGRATE_UNKNOWN
#61, #PROLOG_MIGRATE_UNKNOWN_FAILURE
"62" #DISK_RESIZE
#63, #DISK_RESIZE_POWEROFF
#64 #DISK_RESIZE_UNDEPLOYED
#65 #HOTPLUG_NIC_POWEROFF
]
class OpenNebulaVMRC
attr_reader :proxy_port
def initialize(config, logger, options = {})
opts={ :json_errors => true }.merge(options)
@options = opts
@logger = logger
end
def sanitize(ticket)
# Bad as defined by wikipedia: https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words
# Also have to escape the backslash
bad_chars = [ '/', '\\', '?', '%', '*', ':', '|', '"', '<', '>', '.', ' ' ]
bad_chars.each do |bad_char|
ticket.gsub!(bad_char, '_')
end
ticket
end
def proxy(vm_resource)
# Check configurations and VM attributes
unless is_running?
return error(400, "Fireedge Server is not running, please contact your cloud administrator")
end
# Check configurations and VM attributes
unless VMRC_STATES.include?(vm_resource['LCM_STATE'])
return error(400, "Wrong state (#{vm_resource['LCM_STATE']}) to open a VMRC session")
end
if vm_resource['USER_TEMPLATE/HYPERVISOR'] == "vcenter"
if vm_resource['MONITORING/VCENTER_ESX_HOST']
hostname = vm_resource['MONITORING/VCENTER_ESX_HOST']
else
return error(400,"Could not determine the vCenter ESX host where the VM is running.
Wait till the VCENTER_ESX_HOST attribute is retrieved once the host has been monitored")
end
else
return error(400, "VMRC Connection is only for vcenter hipervisor")
end
vm_id = vm_resource['ID']
one_vm = VCenterDriver::VIHelper.one_item(OpenNebula::VirtualMachine, vm_id)
vm_ref = one_vm['DEPLOY_ID']
host_id = one_vm['HISTORY_RECORDS/HISTORY[last()]/HID'].to_i
vi_client = VCenterDriver::VIClient.new_from_host(host_id)
vm = VCenterDriver::VirtualMachine.new(vi_client, vm_ref, vm_id)
parameters = vm.get_html_console_parameters
data = {
:host => parameters[:host],
:port => parameters[:port],
:ticket => parameters[:ticket]
}
File.open(VMRC_TICKETS + sanitize(data[:ticket]), 'w') { |file| file.write("https://" + data[:host] + ":" + data[:port].to_s ) }
[200, { :data => data }.to_json]
end
def status
if is_running?
STDOUT.puts "VMRC server is running"
true
else
STDOUT.puts "VMRC server is NOT running"
false
end
end
private
def error(code, msg)
if @options[:json_errors]
[code, OpenNebula::Error.new(msg).to_json]
else
[code,msg]
end
end
def is_running?
if $conf[:fireedge_up]
return true
end
false
end
alias_method :get_vmrc_pid, :is_running?
end

View File

@ -161,6 +161,10 @@
:guac_port: 29877
:guacd_port: 4822
:vmrc_port: 2616
:fireedge_server_endpoint: "http://localhost:2616"
:max_waiting_tries: 5
# Login Session Length in seconds, defaults to 1 hour.
#:session_expire_time: 3600
@ -264,4 +268,4 @@
################################################################################
:zeromq_server: tcp://localhost:2101
:autorefresh_ip: 127.0.0.1
:autorefresh_ip: 127.0.0.1

View File

@ -419,6 +419,7 @@ tabs:
VM.edit_labels: true
VM.menu_labels: true
VM.startvnc: true
VM.startvmrc: true
VM.startspice: true
VM.vnc: true
VM.ssh: true

View File

@ -92,6 +92,7 @@ tabs:
VM.lockU: true
VM.unlock: true
VM.startvnc: true
VM.startvmrc: true
VM.startspice: true
VM.vnc: true
VM.ssh: true

View File

@ -418,6 +418,7 @@ tabs:
VM.edit_labels: true
VM.menu_labels: true
VM.startvnc: true
VM.startvmrc: true
VM.startspice: true
VM.vnc: true
VM.ssh: true

View File

@ -411,6 +411,7 @@ tabs:
VM.edit_labels: true
VM.menu_labels: true
VM.startvnc: true
VM.startvmrc: true
VM.startspice: true
VM.vnc: true
VM.ssh: true

View File

@ -419,6 +419,7 @@ tabs:
VM.edit_labels: true
VM.menu_labels: true
VM.startvnc: true
VM.startvmrc: true
VM.startspice: true
VM.vnc: true
VM.ssh: true

View File

@ -92,6 +92,7 @@ tabs:
VM.lockU: true
VM.unlock: true
VM.startvnc: true
VM.startvmrc: true
VM.startspice: true
VM.vnc: true
VM.ssh: true

View File

@ -418,6 +418,7 @@ tabs:
VM.edit_labels: true
VM.menu_labels: true
VM.startvnc: true
VM.startvmrc: true
VM.startspice: true
VM.vnc: true
VM.ssh: true

View File

@ -411,6 +411,7 @@ tabs:
VM.edit_labels: true
VM.menu_labels: true
VM.startvnc: true
VM.startvmrc: true
VM.startspice: true
VM.vnc: true
VM.ssh: true

View File

@ -417,6 +417,7 @@ tabs:
VM.edit_labels: true
VM.menu_labels: true
VM.startvnc: true
VM.startvmrc: true
VM.startspice: true
VM.vnc: true
VM.ssh: true

View File

@ -93,6 +93,7 @@ tabs:
VM.lockU: true
VM.unlock: true
VM.startvnc: true
VM.startvmrc: true
VM.startspice: true
VM.vnc: true
VM.ssh: true

View File

@ -418,6 +418,7 @@ tabs:
VM.edit_labels: true
VM.menu_labels: true
VM.startvnc: true
VM.startvmrc: true
VM.startspice: true
VM.vnc: true
VM.ssh: true

View File

@ -411,6 +411,7 @@ tabs:
VM.edit_labels: true
VM.menu_labels: true
VM.startvnc: true
VM.startvmrc: true
VM.startspice: true
VM.vnc: true
VM.ssh: true

View File

@ -0,0 +1,63 @@
# -------------------------------------------------------------------------- #
# Copyright 2002-2020, OpenNebula Project, OpenNebula Systems #
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
# not use this file except in compliance with the License. You may obtain #
# a copy of the License at #
# #
# http://www.apache.org/licenses/LICENSE-2.0 #
# #
# Unless required by applicable law or agreed to in writing, software #
# distributed under the License is distributed on an "AS IS" BASIS, #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
# See the License for the specific language governing permissions and #
# limitations under the License. #
#--------------------------------------------------------------------------- #
require 'CloudServer'
require 'net/http'
class ValidateFireedge < CloudServer
def initialize(config, logger)
super(config, logger)
@time = 1
@max_tries = config[:max_waiting_tries]
end
def send_request(url)
response = nil
uri = URI(url)
begin
Net::HTTP.start(uri.host, uri.port) do |http|
request = Net::HTTP::Get.new uri
response = http.request request
end
return response.kind_of? Net::HTTPSuccess
rescue
return false
end
end
def validate_fireedge_running
fireedge_endpoint = $conf[:fireedge_server_endpoint]
if (fireedge_endpoint)
tries = 0
while (!$conf[:fireedge_up] || tries <= max_tries) do
if (!$conf[:fireedge_up] && send_request(fireedge_endpoint))
$conf[:fireedge_up] = true;
else
sleep 1
end
tries = tries + 1
end
else
$conf[:fireedge_up] = false;
end
end
end

View File

@ -21,6 +21,7 @@ include OpenNebulaJSON
require 'OpenNebulaVNC'
require 'OpenNebulaGuac'
require 'OpenNebulaVMRC'
require 'OpenNebulaAddons'
require 'OpenNebulaJSON/JSONUtils'
#include JSONUtils
@ -330,6 +331,34 @@ class SunstoneServer < CloudServer
return guac.proxy(resource, type_connection)
end
########################################################################
# VMRC
########################################################################
def startvmrc(id, vmrc)
resource = retrieve_resource("vm", id)
if OpenNebula.is_error?(resource)
return [404, resource.to_json]
end
client = @client
vm_pool = VirtualMachinePool.new(client, -1)
user_pool = UserPool.new(client)
rc = user_pool.info
if OpenNebula.is_error?(rc)
puts rc.message
exit -1
end
rc = vm_pool.info
if OpenNebula.is_error?(rc)
puts rc.message
exit -1
end
return vmrc.proxy(resource)
end
########################################################################
# Accounting & Monitoring
########################################################################

View File

@ -84,148 +84,16 @@ module.exports = function(grunt) {
include: ["almond"],
insertRequire: ["console/vnc"]
},
{
name: "console/vmrc",
include: ["almond"],
insertRequire: ["console/vmrc"]
},
{
name: "console/spice",
include: ["almond"],
insertRequire: ["console/spice"]
}
/*{
name: 'main'
excludeShallow: [
'app'
],
include: [
'jquery',
'datatables',
'foundation-datatables',
'jgrowl',
'foundation.core',
'foundation.abide',
'foundation.accordion',
'foundation.alert',
'foundation.clearing',
'foundation.dropdown',
'foundation.equalizer',
'foundation.interchange',
'foundation.joyride',
'foundation.magellan',
'foundation.offcanvas',
'foundation.orbit',
'foundation.reveal',
'foundation.slider',
'foundation.tab',
'foundation.tooltip',
'foundation.topbar',
'hbs',
'jquery.cookie',
'fastclick',
'modernizr',
'placeholder',
'resumable',
'flot',
'flot.stack',
'flot.resize',
'flot.time',
'flot.tooltip',
'nouislider',
'vnc-util',
'spice-main',
'spice-spicearraybuffer',
'spice-enums',
'spice-atKeynames',
'spice-utils',
'spice-png',
'spice-lz',
'spice-quic',
'spice-bitmap',
'spice-spicedataview',
'spice-spicetype',
'spice-spicemsg',
'spice-wire',
'spice-spiceconn',
'spice-display',
'spice-inputs',
'spice-webm',
'spice-playback',
'spice-simulatecursor',
'spice-cursor',
'spice-jsbn',
'spice-rsa',
'spice-prng4',
'spice-rng',
'spice-sha1',
'spice-ticket',
'spice-resize',
'spice-filexfer'
]
},
{
name: 'app',
exclude: [
'jquery',
'datatables',
'foundation-datatables',
'jgrowl',
'foundation.core',
'foundation.abide',
'foundation.accordion',
'foundation.alert',
'foundation.clearing',
'foundation.dropdown',
'foundation.equalizer',
'foundation.interchange',
'foundation.joyride',
'foundation.magellan',
'foundation.offcanvas',
'foundation.orbit',
'foundation.reveal',
'foundation.slider',
'foundation.tab',
'foundation.tooltip',
'foundation.topbar',
'hbs',
'jquery.cookie',
'fastclick',
'modernizr',
'placeholder',
'resumable',
'flot',
'flot.stack',
'flot.resize',
'flot.time',
'flot.tooltip',
'nouislider',
'vnc-util',
'spice-main',
'spice-spicearraybuffer',
'spice-enums',
'spice-atKeynames',
'spice-utils',
'spice-png',
'spice-lz',
'spice-quic',
'spice-bitmap',
'spice-spicedataview',
'spice-spicetype',
'spice-spicemsg',
'spice-wire',
'spice-spiceconn',
'spice-display',
'spice-inputs',
'spice-webm',
'spice-playback',
'spice-simulatecursor',
'spice-cursor',
'spice-jsbn',
'spice-rsa',
'spice-prng4',
'spice-rng',
'spice-sha1',
'spice-ticket',
'spice-resize',
'spice-filexfer'
]
}*/
]
}
}

View File

@ -0,0 +1,139 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2020, OpenNebula Project, OpenNebula Systems */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
define(function(require) {
require("jquery");
require("jquery-ui");
var WMKS = require("wmks");
var Config = require("sunstone-config");
var _wmks;
var _is_encrypted = "";
function setStatus(message="", status=""){
$(".VMRC_message").text(message);
$("#VMRC_status").text(status);
}
function connected(){
setStatus(null, "VMRC " + _wmks.connectionState + " (" + _is_encrypted + ") to: " + _wmks.vm_name);
}
function disconnectedFromServer(e){
if (e.detail.clean) {
setStatus(null, "VMRC " + _wmks.connectionState + " (" + _is_encrypted + ") to: " + _wmks.vm_name);
} else {
setStatus("Something went wrong, connection is closed", "Failed");
}
}
function desktopNameChange(name) {
if (e.detail.name) {
setStatus(null, "VMRC " + _wmks.connectionState + " (" + _is_encrypted + ") to: " + name);
}
}
function credentialsRequired(e) {
setStatus("Something went wrong, more credentials must be given to continue", "Failed");
}
function sendCtrlAltDel() {
if (_wmks) { _wmks.sendCAD(); }
}
function updateState(state, msg) {
var s, sb, cad, level;
s = document.querySelector("#VMRC_status");
sb = document.querySelector("#VMRC_status_bar");
cad = document.querySelector("#sendCtrlAltDelButton");
switch (state) {
case "failed": level = "error"; break;
case "fatal": level = "error"; break;
case "normal": level = "normal"; break;
case "disconnected": level = "normal"; break;
case "loaded": level = "normal"; break;
default: level = "warn"; break;
}
if (state === "normal") {
cad.disabled = false;
} else {
cad.disabled = true;
xvpInit(0);
}
if (typeof(msg) !== "undefined") {
sb.setAttribute("class", "VMRC_status_" + level);
s.innerHTML = msg;
}
}
function getQueryVariable(variable)
{
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
if(pair[0] == variable){return pair[1];}
}
return(false);
}
var URL = "";
var host = getQueryVariable("host");
var port = getQueryVariable("port");
var ticket = getQueryVariable("ticket");
var vm_name = getQueryVariable("name");
if (window.location.protocol === "https:") {
URL = "wss";
_is_encrypted = "encrypted";
} else {
URL = "ws";
_is_encrypted = "unencrypted";
}
URL += "://" + host;
URL += ":" + port;
URL += "/vmrc/" + ticket;
document.querySelector("#sendCtrlAltDelButton").style.display = "inline";
document.querySelector("#sendCtrlAltDelButton").onclick = sendCtrlAltDel;
if ((!host) || (!port)) {
updateState("failed",
"Must specify host and port in URL");
return;
}
try{
_wmks = WMKS.createWMKS("wmksContainer", {})
.register(WMKS.CONST.Events.CONNECTION_STATE_CHANGE,
function (event, data) {
if (typeof cons !== 'undefined' && data.state == cons.ConnectionState.CONNECTED) {
console.log("connection state change : connected");
}
}
);
_wmks.eventHandlers["connectionstatechange"].push(connected);
_wmks.eventHandlers["disconnect"] = disconnectedFromServer;
_wmks.connect(URL);
_wmks["vm_name"] = vm_name;
}catch(err){
setStatus("Something went wrong, connection is closed", "Failed");
console.log("error start VMRC ", err);
}
});

View File

@ -25,6 +25,8 @@ require.config({
/* jQuery */
"jquery": "../bower_components/jquery/dist/jquery",
"jquery-ui": "../bower_components/jquery-ui/jquery-ui",
/* WMKS */
"wmks" : "../bower_components/wmks/wmks_AMD.min",
/** Wickedpicker */
"wickedpicker": "../bower_components/wickedpicker/dist/wickedpicker.min",
@ -36,29 +38,12 @@ require.config({
"datatables.net": "../bower_components/datatables/media/js/jquery.dataTables",
"datatables.foundation": "../bower_components/datatables/media/js/dataTables.foundation",
/* DataTables */
/* jqrowl notfications */
"jgrowl": "../bower_components/jgrowl/jquery.jgrowl",
/* Foundation */
"foundation": "../bower_components/foundation-sites/dist/foundation",
//'foundation.core': '../bower_components/foundation/js/foundation/foundation',
//'foundation.abide': '../bower_components/foundation/js/foundation/foundation.abide',
//'foundation.accordion': '../bower_components/foundation/js/foundation/foundation.accordion',
//'foundation.alert': '../bower_components/foundation/js/foundation/foundation.alert',
//'foundation.clearing': '../bower_components/foundation/js/foundation/foundation.clearing',
//'foundation.dropdown': '../bower_components/foundation/js/foundation/foundation.dropdown',
//'foundation.equalizer': '../bower_components/foundation/js/foundation/foundation.equalizer',
//'foundation.interchange': '../bower_components/foundation/js/foundation/foundation.interchange',
//'foundation.joyride': '../bower_components/foundation/js/foundation/foundation.joyride',
//'foundation.magellan': '../bower_components/foundation/js/foundation/foundation.magellan',
//'foundation.offcanvas': '../bower_components/foundation/js/foundation/foundation.offcanvas',
//'foundation.orbit': '../bower_components/foundation/js/foundation/foundation.orbit',
//'foundation.reveal': '../bower_components/foundation/js/foundation/foundation.reveal',
//'foundation.slider': '../bower_components/foundation/js/foundation/foundation.slider',
//'foundation.tab': '../bower_components/foundation/js/foundation/foundation.tab',
//'foundation.tooltip': '../bower_components/foundation/js/foundation/foundation.tooltip',
//'foundation.topbar': '../bower_components/foundation/js/foundation/foundation.topbar',
/* Handlebars */
"hbs": "../bower_components/require-handlebars-plugin/hbs",
@ -122,6 +107,8 @@ require.config({
deps: [
"jquery",
"foundation",
"jquery-ui",
"wmks",
"tabs/provision-tab",
"tabs/dashboard-tab",
"tabs/system-top-tab",
@ -171,76 +158,23 @@ require.config({
deps: ["jquery"]
},
/* JQuery-UI */
"jquery-ui": {
deps: ["jquery"]
},
/* Foundation */
"foundation": {
deps: ["jquery"]
},
//'foundation.core': {
// deps: ['jquery', 'modernizr'],
// exports: 'Foundation'
//},
//'foundation.abide': {
// deps: ['foundation.core']
//},
//'foundation.accordion': {
// deps: ['foundation.core']
//},
//'foundation.alert': {
// deps: ['foundation.core']
//},
//'foundation.clearing': {
// deps: ['foundation.core']
//},
//'foundation.dropdown': {
// deps: ['foundation.core']
//},
//'foundation.equalizer': {
// deps: ['foundation.core']
//},
//'foundation.interchange': {
// deps: ['foundation.core']
//},
//'foundation.joyride': {
// deps: ['foundation.core', 'jquery.cookie']
//},
//'foundation.magellan': {
// deps: ['foundation.core']
//},
//'foundation.offcanvas': {
// deps: ['foundation.core']
//},
//'foundation.orbit': {
// deps: ['foundation.core']
//},
//'foundation.reveal': {
// deps: ['foundation.core']
//},
//'foundation.slider': {
// deps: ['foundation.core']
//},
//'foundation.tab': {
// deps: ['foundation.core']
//},
//'foundation.tooltip': {
// deps: ['foundation.core']
//},
//'foundation.topbar': {
// deps: ['foundation.core']
//},
/* Vendor Scripts */
//'jquery.cookie': {
// deps: ['jquery']
//},
//'fastclick': {
// exports: 'FastClick'
//},
//'modernizr': {
// exports: 'Modernizr'
//},
//'placeholder': {
// exports: 'Placeholders'
//},
/* WMKS */
"wmks": {
deps: [
"jquery",
"jquery-ui"
],
exports: "WMKS"
},
/* Flot Graphs */
"flot": {

View File

@ -533,6 +533,26 @@ define(function(require) {
}
});
},
"vmrc" : function(params) {
var callback = params.success;
var callback_error = params.error;
var id = params.data.id;
var resource = RESOURCE;
var request = OpenNebulaHelper.request(resource, null, params.data);
$.ajax({
url: "vm/" + id + "/startvmrc",
type: "POST",
dataType: "json",
success: function(response) {
return callback ? callback(request, response) : null;
},
error: function(response) {
return callback_error ?
callback_error(request, OpenNebulaError(response)) : null;
}
});
},
"append": function(params) {
var action_obj = {"template_raw" : params.data.extra_param, append : true};
OpenNebulaAction.simple_action(params, RESOURCE, "update", action_obj);
@ -688,6 +708,7 @@ define(function(require) {
"isNICAttachSupported": isNICAttachSupported,
"isVNCSupported": isVNCSupported,
"isConnectionSupported": isConnectionSupported,
"isVMRCSupported": isVMRCSupported,
"isSPICESupported": isSPICESupported,
"isWFileSupported": isWFileSupported,
"hasConnection": hasConnection,
@ -952,6 +973,14 @@ define(function(require) {
? true : false;
}
// returns true if the vmrc button should be enabled
function isVMRCSupported(element) {
var action_enabled = Config.isTabActionEnabled("vms-tab", "VM.startvmrc");
var graphics = graphicSupported(element, "vmrc");
return (action_enabled && graphics)
? true : false;
}
function isSPICESupported(element) {
return (Config.isTabActionEnabled("vms-tab", "VM.startspice") && graphicSupported(element, "spice"))
? true : false;

View File

@ -170,6 +170,7 @@ define(function(require) {
"filterView": _config["view"]["filter-view"],
"doCountAnimation": _config["view"]["do_count_animation"],
"guacPort": _config["user_config"]["guac_port"],
"vmrcPort": _config["user_config"]["vmrc_port"],
"allTabs": function() {
return Object.keys(_config["view"]["tabs"]);

View File

@ -28,6 +28,8 @@
<label class="hypervisor only_kvm not_lxd" for="radioSdlType{{uniqueId}}">SDL</label>
<input type="radio" wizard_field="TYPE" name="graphics_type" ID="radioSpiceType{{uniqueId}}" value="SPICE" class="hypervisor only_kvm not_lxd" >
<label class="hypervisor only_kvm not_lxd" for="radioSpiceType{{uniqueId}}">SPICE</label>
<input type="radio" wizard_field="TYPE" name="graphics_type" ID="radioVMRCType{{uniqueId}}" value="VMRC" class="hypervisor only_vcenter" >
<label class="hypervisor only_vcenter" for="radioVMRCType{{uniqueId}}">VMRC</label>
</div>
</div>
<br>

View File

@ -36,6 +36,7 @@ define(function(require) {
require("./vms-tab/dialogs/snapshot"),
require("./vms-tab/dialogs/revert"),
require("./vms-tab/dialogs/vnc"),
require("./vms-tab/dialogs/vmrc"),
require("./vms-tab/dialogs/spice"),
require("./vms-tab/dialogs/guac"),
require("./vms-tab/dialogs/saveas-template")

View File

@ -22,6 +22,7 @@ define(function(require) {
var OpenNebulaVM = require('opennebula/vm');
var CommonActions = require('utils/common-actions');
var Vnc = require('utils/vnc');
var Vmrc = require('utils/vmrc');
var Spice = require('utils/spice');
var Files = require('utils/files');
@ -30,6 +31,7 @@ define(function(require) {
var DEPLOY_DIALOG_ID = require('./dialogs/deploy/dialogId');
var MIGRATE_DIALOG_ID = require('./dialogs/migrate/dialogId');
var VNC_DIALOG_ID = require('./dialogs/vnc/dialogId');
var VMRC_DIALOG_ID = require('./dialogs/vmrc/dialogId');
var SPICE_DIALOG_ID = require('./dialogs/spice/dialogId');
var GUAC_DIALOG_ID = require('./dialogs/guac/dialogId');
var SAVE_AS_TEMPLATE_DIALOG_ID = require('./dialogs/saveas-template/dialogId');
@ -283,6 +285,36 @@ define(function(require) {
},
notify: true
},
"VM.startvmrc" : {
type: "custom",
call: function() {
$.each(Sunstone.getDataTable(TAB_ID).elements(), function(index, elem) {
if (!Vmrc.lockStatus()) {
Vmrc.lock();
var vm_name = OpenNebulaVM.getName(elem);
Sunstone.runAction("VM.startvmrc_action", elem, vm_name);
} else {
Notifier.notifyError(Locale.tr("VMRC Connection in progress"))
return false;
}
});
}
},
"VM.startvmrc_action" : {
type: "single",
call: OpenNebulaVM.vmrc,
callback: function(request, response) {
var dialog = Sunstone.getDialog(VMRC_DIALOG_ID);
response["vm_name"] = request.request.data[0].extra_param;
dialog.setElement(response);
dialog.show();
},
error: function(req, resp) {
Notifier.onError(req, resp);
Vmrc.unlock();
},
notify: true
},
"VM.startspice" : {
type: "custom",
call: function() {

View File

@ -200,6 +200,12 @@ define(function(require) {
layout: "vmsremote_buttons",
custom_classes: "only-sunstone-info vnc-sunstone-info"
},
"VM.startvmrc" : {
type: "action",
text: Locale.tr("VMRC"),
layout: "vmsremote_buttons",
custom_classes: "only-sunstone-info vmrc-sunstone-info"
},
"VM.startspice" : {
type: "action",
text: Locale.tr("SPICE"),

View File

@ -0,0 +1,95 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2020, OpenNebula Project, OpenNebula Systems */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
define(function(require) {
/*
DEPENDENCIES
*/
var BaseDialog = require('utils/dialogs/dialog');
var TemplateHTML = require('hbs!./vmrc/html');
var Sunstone = require('sunstone');
var Vmrc = require('utils/vmrc');
/*
CONSTANTS
*/
var DIALOG_ID = require('./vmrc/dialogId');
var TAB_ID = require('../tabId')
/*
CONSTRUCTOR
*/
function Dialog() {
this.dialogId = DIALOG_ID;
BaseDialog.call(this);
};
Dialog.DIALOG_ID = DIALOG_ID;
Dialog.prototype = Object.create(BaseDialog.prototype);
Dialog.prototype.constructor = Dialog;
Dialog.prototype.html = _html;
Dialog.prototype.onShow = _onShow;
Dialog.prototype.onClose = _onClose;
Dialog.prototype.setup = _setup;
Dialog.prototype.setElement = _setElement;
return Dialog;
/*
FUNCTION DEFINITIONS
*/
function _html() {
return TemplateHTML({
'dialogId': this.dialogId
});
}
function _setup(context) {
var that = this;
$("#open_in_a_new_window", context).on("click", function() {
var dialog = Sunstone.getDialog(DIALOG_ID);
dialog.hide();
});
$('#sendCtrlAltDelButton', context).click(function() {
Vmrc.sendCtrlAltDel();
return false;
});
return false;
}
function _onShow(context) {
Vmrc.vmrcCallback(this.element);
return false;
}
function _onClose(context) {
Vmrc.disconnect();
Vmrc.unlock();
return false;
}
function _setElement(element) {
this.element = element
}
});

View File

@ -0,0 +1,19 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2020, OpenNebula Project, OpenNebula Systems */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
define(function(require) {
return 'vmrcVMDialog';
});

View File

@ -0,0 +1,39 @@
{{! -------------------------------------------------------------------------- }}
{{! Copyright 2002-2020, OpenNebula Project, OpenNebula Systems }}
{{! }}
{{! Licensed under the Apache License, Version 2.0 (the "License"); you may }}
{{! not use this file except in compliance with the License. You may obtain }}
{{! a copy of the License at }}
{{! }}
{{! http://www.apache.org/licenses/LICENSE-2.0 }}
{{! }}
{{! Unless required by applicable law or agreed to in writing, software }}
{{! distributed under the License is distributed on an "AS IS" BASIS, }}
{{! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }}
{{! See the License for the specific language governing permissions and }}
{{! limitations under the License. }}
{{! -------------------------------------------------------------------------- }}
<div id="{{dialogId}}" class="reveal full" data-reveal>
<div class="row text-center">
<div class="large-12 columns">
<h5 class="subheader" id="vmrc_dialog">
<span id="VMRC_status"></span>
<span id="VMRC_buttons" class="right">
<button class="button alert" value="Send CtrlAltDel"
id="sendCtrlAltDelButton">{{tr "Send CtrlAltDel"}}</button>
<a class="button" id="open_in_a_new_window" href="" target="_blank" title="{{tr "Open in a new window"}}">
<i class="fas fa-external-link-alt detach-vmrc-icon" />
</a>
<button class="button secondary" data-close aria-label="{{tr "Close modal"}}" type="button"
title="Close VMRC">
<i class="fas fa-times-circle"></i>
</button>
</span>
</h5>
</div>
</div>
<div class="reveal-body text-center" style="width:100%; overflow-x:auto">
<div id="wmksContainer" style="position:absolute;width:100%;height:100%; left:0em"></div>
</div>
</div>

View File

@ -45,7 +45,8 @@ define(function(require) {
isSPICESupported = Boolean(OpenNebulaVM.isSPICESupported(element)),
isWFileSupported = Boolean(OpenNebulaVM.isWFileSupported(element)),
isRDPSupported = Boolean(OpenNebulaVM.isConnectionSupported(element, 'rdp')),
isSSHSupported = Boolean(OpenNebulaVM.isConnectionSupported(element, 'ssh'));
isSSHSupported = Boolean(OpenNebulaVM.isConnectionSupported(element, 'ssh')),
isVMRCSupported = Boolean(OpenNebulaVM.isVMRCSupported(element));
// All remote buttons are disabled
var allDisabled = (
@ -53,21 +54,33 @@ define(function(require) {
!isSPICESupported &&
!isWFileSupported &&
!isRDPSupported &&
!isSSHSupported
!isSSHSupported &&
!isVMRCSupported
);
$("#vmsremote_buttons").toggle(!allDisabled);
if (isVNCSupported) {
$(".vnc-sunstone-info").show();
$(".spice-sunstone-info").hide();
$(".vmrc-sunstone-info").hide();
}
else if (isSPICESupported) {
$(".spice-sunstone-info").show();
$(".vnc-sunstone-info").hide();
$(".vmrc-sunstone-info").hide();
}
else if (isVMRCSupported){
$(".vmrc-sunstone-info").show();
$(".vnc-sunstone-info").hide();
$(".spice-sunstone-info").hide();
}
else {
$(".spice-sunstone-info").hide();
$(".vnc-sunstone-info").hide();
$(".vmrc-sunstone-info").hide();
}
// Show / hide virt-viewer button

View File

@ -171,6 +171,20 @@ define(function(require) {
TemplateTable.setup(strippedTemplate, RESOURCE, this.element.ID, context, unshownValues, strippedTemplateVcenter);
TemplateTableVcenter.setup(strippedTemplateVcenter, RESOURCE, this.element.ID, context, unshownValues, strippedTemplate);
if (config.system_config &&
config.system_config.is_fireedge_up &&
config.system_config.is_fireedge_up === "false"){
$("a.vmrc-sunstone-info").attr("data-toggle",'tooltip');
$("a.vmrc-sunstone-info").attr("title",'Fireedge Server is not running, please contact your cloud administrator');
$("a.vmrc-sunstone-info").css("color",'gray');
}
else{
$("a.vmrc-sunstone-info").removeAttr("data-toggle");
$("a.vmrc-sunstone-info").removeAttr("title");
$("a.vmrc-sunstone-info").css("color",'');
}
Websocket.subscribe(this.element.ID);
}

View File

@ -0,0 +1,149 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2020, OpenNebula Project, OpenNebula Systems */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
define(function (require) {
var WMKS = require("wmks");
var Config = require("sunstone-config");
var _lock = false;
var _wmks;
var _is_encrypted = "";
return {
"lockStatus": lockStatus,
"lock": lock,
"unlock": unlock,
"vmrcCallback": vmrcCallback,
"disconnect": disconnect,
"sendCtrlAltDel": sendCtrlAltDel
};
function lockStatus() {
return _lock;
}
function lock() {
_lock = true;
}
function unlock() {
_lock = false;
}
function setStatus(message = "", status = "") {
$(".VMRC_message").text(message);
$("#VMRC_status").text(status);
}
function connected() {
setStatus(null, "VMRC " + _wmks.connectionState + " (" + _is_encrypted + ") to: " + _wmks.vm_name);
}
function disconnectedFromServer(e) {
if (e.detail.clean) {
setStatus(null, "VMRC " + _wmks.connectionState + " (" + _is_encrypted + ") to: " + _wmks.vm_name);
} else {
setStatus("Something went wrong, connection is closed", "Failed");
}
}
function desktopNameChange(e) {
if (e.detail.name) {
setStatus(null, "VMRC " + _wmks.connectionState + " (" + _is_encrypted + ") to: " /*+ e.detail.name*/);
}
}
function credentialsRequired(e) {
setStatus("Something went wrong, more credentials must be given to continue", "Failed");
}
function render(ticket, host_vmrc, port_vmrc, response){
var URL = "";
var hostname = window.location.hostname;
var port = window.location.port;
var protocol = window.location.protocol;
var vmrc_port = Config.vmrcPort;
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
// Content of response.data
var ticket = ticket ? ticket : urlParams.get('ticket');
var host_vmrc = host_vmrc ? host_vmrc : urlParams.get('host');
var port_vmrc = port_vmrc ? port_vmrc : urlParams.get('port');
if (protocol === "https:") {
URL = "wss";
_is_encrypted ="encrypted";
} else {
URL = "ws";
_is_encrypted ="unencrypted";
}
URL += "://" + hostname;
URL += ":" + vmrc_port + "/";
var re = new RegExp("^(ws|wss):\\/\\/[\\w\\D]*?\\/", "gi");
var link = URL.replace(re, protocol + "//" + hostname + ":" + port + "/vmrc?");
URL += "vmrc/" + ticket;
link += "host=" + hostname;
link += "&port=" + vmrc_port;
link += "&ticket=" + ticket;
try {
_wmks = WMKS.createWMKS("wmksContainer", {})
.register(WMKS.CONST.Events.CONNECTION_STATE_CHANGE,
function (event, data) {
if (typeof cons !== 'undefined' && data.state == cons.ConnectionState.CONNECTED) {
console.log("connection state change : connected");
}
}
);
_wmks.eventHandlers["connectionstatechange"].push(connected);
_wmks.eventHandlers["disconnect"] = disconnectedFromServer;
_wmks.connect(URL);
_wmks["vm_name"] = response.vm_name ? response.vm_name:"";
link += "&name=" + _wmks["vm_name"];
$("#VMRC_buttons #open_in_a_new_window").attr("href",link);
} catch (err) {
setStatus("Something went wrong, connection is closed", "Failed");
console.log("error start VMRC ", err);
}
}
function vmrcCallback(response) {
if (response.data){
render(response.data.ticket,
response.data.host,
response.data.port,
response);
}
}
function disconnect() {
if (_wmks) { _wmks.disconnect(); }
}
function sendCtrlAltDel() {
if (_wmks) { _wmks.sendCAD(); }
}
});

View File

@ -0,0 +1,314 @@
/******************************************************************************
* Copyright 2013 VMware, Inc. All rights reserved.
*****************************************************************************/
/*
* extended-keypad.css
*
* Defines style for the virtual keys on the control pane.
*/
.ctrl-pane-wrapper {
width: 290px !important; /* Needed as the default is a bit larger than this */
border: 1px solid #333 !important;
-moz-border-radius: 6px; -webkit-border-radius: 6px; -khtml-border-radius: 6px; border-radius: 6px;
background: rgb(170,171,182); /* Old browsers */
background: -webkit-linear-gradient(top, rgba(170,171,182,.93) 0%,rgba(123,123,133,.93) 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, rgba(170,171,182,.93) 0%,rgba(123,123,133,.93) 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, rgba(170,171,182,.93) 0%,rgba(123,123,133,.93) 100%); /* IE10+ */
background: linear-gradient(top, rgba(170,171,182,.93) 0%,rgba(123,123,133,.93) 100%); /* W3C */
}
.fnKey-pane-wrapper {
width: 427px;
border: 1px solid #333;
-moz-border-radius: 6px; -webkit-border-radius: 6px; -khtml-border-radius: 6px; border-radius: 6px;
background: #c1c4d1; /* Old browsers */
background: -webkit-linear-gradient(top, #c1c4d1 0%,#b0b1bd 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #c1c4d1 0%,#b0b1bd 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #c1c4d1 0%,#b0b1bd 100%); /* IE10+ */
background: linear-gradient(top, #c1c4d1 0%, #b0b1bd 100%); /* W3C */
position: absolute;
padding: 0;
-moz-box-shadow: 0px 5px 7px rgba(0,0,0,.5);
-webkit-box-shadow: 0px 5px 7px rgba(0,0,0,.5);
box-shadow: 0px 5px 7px rgba(0,0,0,.5);
}
.fnKey-pane-wrapper-down {
width: 427px;
border: 1px solid #333;
-moz-border-radius: 6px; -webkit-border-radius: 6px; -khtml-border-radius: 6px; border-radius: 6px;
background: #6e6e77; /* Old browsers */
background: -webkit-linear-gradient(top, #6e6e77 0%,#656565 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #6e6e77 0%,#656565 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #6e6e77 0%,#656565 100%); /* IE10+ */
background: linear-gradient(top, #6e6e77 0%, #656565 100%); /* W3C */
position: absolute;
padding: 0;
-moz-box-shadow: 0px 5px 7px rgba(0,0,0,.5);
-webkit-box-shadow: 0px 5px 7px rgba(0,0,0,.5);
box-shadow: 0px 5px 7px rgba(0,0,0,.5);
}
/* Hide jquery ui title bar. */
.ctrl-pane-wrapper .ui-dialog-titlebar {
border-top: 1px solid #ccc;
border-left: 1px solid #aaa;
border-right: 1px solid #aaa;
border-bottom: 0;
padding: .6em .8em 0 .8em;
background: none !important;
-moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; -khtml-border-top-left-radius: 5px; border-top-left-radius: 5px;
-moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; -khtml-border-top-right-radius: 5px; border-top-right-radius: 5px;
}
/* Replace jquery ui title bar close icon. */
.ctrl-pane-wrapper .ui-dialog-titlebar-close {
margin-top: -9px;
border: 0 !important;
background: none !important;
}
/* Background-image is defined along with touch-sprite in 1 place. */
.ctrl-pane-wrapper .ui-dialog-titlebar-close .ui-icon {
background-position: -9px -239px;
background-repeat: no-repeat;
}
.ctrl-pane-wrapper .ui-dialog-titlebar-close .ui-icon:active {
background-position-x: -24px;
background-repeat: no-repeat;
}
/* The grabber icon indicating the dialog could be moved around */
.ctrl-pane-wrapper .ui-dialog-titlebar .ui-dialog-title {
background-position: -10px -255px;
background-repeat: no-repeat;
width: 40px;
height: 14px;
margin: 0 0 0 42%;
}
.ctrl-pane-wrapper .ui-dialog-titlebar .ui-dialog-title:active {
background-position-x: -52px;
}
.ctrl-pane-wrapper .ui-dialog-content {
background: none !important;
padding: 0 0;
border-style: solid;
border-color: #aaaaaa;
border-width: 0 1px 1px 1px;
-moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; -khtml-border-bottom-left-radius: 5px; border-bottom-left-radius: 5px;
-moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; -khtml-border-bottom-right-radius: 5px; border-bottom-right-radius: 5px;
}
.fnKey-inner-border-helper {
position: relative;
background: none !important;
border-style: solid;
border-color: #d5d5d5;
border-width: 1px;
-moz-border-radius: 5px; -webkit-border-radius: 5px; -khtml-border-radius: 5px; border-radius: 5px;
pointer-events:none;
}
.ctrl-pane-wrapper .ctrl-pane {
padding: 3px 0 3px 6px;
height: 140px;
width: 280px;
}
.ctrl-pane .baseKey {
float: left;
border: 0;
padding: 0;
width: 57px;
height: 57px;
margin: 6px;
-moz-border-radius: 6px; -webkit-border-radius: 6px; -khtml-border-radius: 6px; border-radius: 6px;
font-family: "HelveticaNeue", "Helvetica Neue", "HelveticaNeue", "Helvetica Neue", 'TeXGyreHeros', "Helvetica", "Tahoma", "Geneva", "Arial", sans-serif;
font-size: 18px;
text-shadow: 0 1px 1px #eeeeee;
-moz-box-shadow: 0px 1px 3px rgba(0, 0, 0, .7);
-webkit-box-shadow: 0px 1px 3px rgba(0,0,0,.7);
box-shadow: 0px 1px 3px rgba(0,0,0,.7);
}
.ctrl-pane .ctrl-key-top-row {
background: -webkit-linear-gradient(top, #fff 0%,#f3f5fb 2%,#d2d2d8 98%,#999 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #fff 0%,#f3f5fb 2%,#d2d2d8 98%,#999 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #fff 0%,#f3f5fb 2%,#d2d2d8 98%,#999 100%); /* IE10+ */
background: linear-gradient(top, #fff 0%,#f3f5fb 2%,#d2d2d8 98%,#999 100%); /* W3C */
}
.ctrl-pane .ctrl-key-bottom-row {
background: -webkit-linear-gradient(top, #fff 0%,#e1e1e3 2%,#d1d1d4 50%,#bebec3 98%,#838387 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #fff 0%,#e1e1e3 2%,#d1d1d4 50%,#bebec3 98%,#838387 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #fff 0%,#e1e1e3 2%,#d1d1d4 50%,#bebec3 98%,#838387 100%); /* IE10+ */
background: linear-gradient(top, #fff 0%,#e1e1e3 2%,#d1d1d4 50%,#bebec3 98%,#838387 100%); /* W3C */
}
.ctrl-pane .up-position .fn-key-top-row {
color:#333;
background: #ffffff; /* Old browsers */
background: -webkit-linear-gradient(top, #ffffff 0%,#f7f7f7 2%,#dcdde3 96%,#999999 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #ffffff 0%,#f7f7f7 2%,#dcdde3 96%,#999999 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #ffffff 0%,#f7f7f7 2%,#dcdde3 96%,#999999 100%); /* IE10+ */
background: linear-gradient(top, #ffffff 0%,#f7f7f7 2%,#dcdde3 96%,#999999 100%); /* W3C */
}
.ctrl-pane .up-position .fn-key-bottom-row {
color:#333;
background: #ffffff; /* Old browsers */
background: -webkit-linear-gradient(top, #ffffff 0%,#f3f5fb 2%,#d2d2d8 98%,#999999 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #ffffff 0%,#f3f5fb 2%,#d2d2d8 98%,#999999 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #ffffff 0%,#f3f5fb 2%,#d2d2d8 98%,#999999 100%); /* IE10+ */
background: linear-gradient(top, #ffffff 0%,#f3f5fb 2%,#d2d2d8 98%,#999999 100%); /* W3C */
}
.ctrl-pane .down-position .fn-key-top-row {
color:#333;
background: #ffffff; /* Old browsers */
background: -webkit-linear-gradient(top, #ffffff 0%,#e1e1e3 4%,#d1d1d4 45%,#b7b8bd 98%,#838387 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #ffffff 0%,#e1e1e3 4%,#d1d1d4 45%,#b7b8bd 98%,#838387 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #ffffff 0%,#e1e1e3 4%,#d1d1d4 45%,#b7b8bd 98%,#838387 100%); /* IE10+ */
background: linear-gradient(top, #ffffff 0%,#e1e1e3 4%,#d1d1d4 45%,#b7b8bd 98%,#838387 100%); /* W3C */
}
.ctrl-pane .down-position .fn-key-bottom-row {
color:#333;
background: #ffffff; /* Old browsers */
background: -webkit-linear-gradient(top, #ffffff 0%,#d9dadd 4%,#c8c8cd 45%,#b0b0b7 98%,#838387 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #ffffff 0%,#d9dadd 4%,#c8c8cd 45%,#b0b0b7 98%,#838387 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #ffffff 0%,#d9dadd 4%,#c8c8cd 45%,#b0b0b7 98%,#838387 100%); /* IE10+ */
background: linear-gradient(top, #ffffff 0%,#d9dadd 4%,#c8c8cd 45%,#b0b0b7 98%,#838387 100%); /* W3C */
}
.ctrl-pane .fn-key-top-row {
margin: 12px 6px 6px 6px;
}
.ctrl-pane .border-key-top-left .fn-key-top-row {
margin: 12px 6px 6px 12px;
}
.ctrl-pane .border-key-top-right .fn-key-top-row {
margin: 12px 12px 6px 6px;
}
.ctrl-pane .fn-key-bottom-row {
margin: 5px 6px 12px 6px;
}
.ctrl-pane .border-key-bottom-left .fn-key-bottom-row {
margin: 5px 6px 12px 12px;
}
.ctrl-pane .border-key-bottom-right .fn-key-bottom-row {
margin: 5px 12px 12px 6px;
}
.ctrl-pane .ctrl-key-top-row:active, .ctrl-pane .fn-key-top-row:active,
.ctrl-pane .ctrl-key-bottom-row:active, .ctrl-pane .fn-key-bottom-row:active {
background: #bbbbbb;
background: -webkit-linear-gradient(bottom, #888888 25%, #CCCCCC 68%);
background: -ms-linear-gradient(bottom, #888888 25%, #CCCCCC 68%);
background: -o-linear-gradient(bottom, #888888 25%, #CCCCCC 68%);
background: linear-gradient(bottom, #888888 25%, #CCCCCC 68%);
}
.ctrl-pane .ctrl-key-top-row div, .ctrl-pane .ctrl-key-bottom-row div,
.ctrl-pane .fn-key-top-row div, .ctrl-pane .fn-key-bottom-row div {
width: 100%;
text-align: center;
padding-top: 17px;
overflow-x: hidden;
}
/* Highlight selected modifier key */
.ctrl-pane .ab-modifier-key-down {
color: #4D8DFF;
}
.ctrl-pane .baseKey img { /* use .touch-sprite for image */
background-repeat: no-repeat;
width: 57px;
height: 57px;
border: 0;
-moz-border-radius: 6px; -webkit-border-radius: 6px; -khtml-border-radius: 6px; border-radius: 6px;
}
.ctrl-pane .baseKey .right-arrow {
background-position: -242px -182px;
}
.ctrl-pane .baseKey .left-arrow {
background-position: -126px -182px;
}
.ctrl-pane .baseKey .up-arrow {
background-position: -299px -182px;
}
.ctrl-pane .baseKey .down-arrow {
background-position: -183px -182px;
}
.ctrl-pane .baseKey .more-keys {
background-position: -10px -182px;
}
/* Ctrl - pane flip transition. */
.ctrl-pane.flip-container {
perspective: 1000;
-webkit-perspective: 1000;
-moz-perspective: 1000;
-ms-perspective: 1000;
}
/* flip the ctrl-pane when this class toggles. */
.flip-container.perform-flip .flipper {
transform: rotateY(180deg);
-webkit-transform: rotateY(180deg);
-moz-transform: rotateY(180deg);
-ms-transform: rotateY(180deg);
}
/* flip speed goes here */
.flip-container .flipper {
transition: 0.6s;
transform-style: preserve-3d;
-webkit-transition: 0.6s;
-webkit-transform-style: preserve-3d;
-moz-transition: 0.6s;
-moz-transform-style: preserve-3d;
-ms-transition: 0.6s;
-ms-transform-style: preserve-3d;
position: relative;
}
/* hide back of pane during swap */
.flip-container .front, .flip-container .back {
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
-ms-backface-visibility: hidden;
position: absolute;
top: 0;
left: 0;
}
/* front pane, placed above back */
.flip-container .front {
z-index: 200;
}
/* back, initially hidden pane */
.flip-container .back {
transform: rotateY(180deg);
-webkit-transform: rotateY(180deg);
-moz-transform: rotateY(180deg);
-ms-transform: rotateY(180deg);
}

View File

@ -0,0 +1,155 @@
/******************************************************************************
* Copyright 2013 VMware, Inc. All rights reserved.
*****************************************************************************/
/*
* main-ui.css
*
* Defines style for the wmks ui widgets.
*
* Use CSS3 for touch devices as jquery effects break when browser handles
* orientation changes, or page bouncing.
*
* TODO: Need to handle Retina mode for iPad.
*/
/*
* jQuery UI Dialog 1.8.16
*/
.ui-dialog {
padding: 0;
box-shadow: 0px 5px 7px rgba(0,0,0,.5);
}
.ui-dialog .ui-dialog-titlebar {
padding: .8em .8em;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.ui-dialog .ui-dialog-titlebar-close {
right: .4em;
margin-top: -11px;
}
.ui-widget-content {
border: 0;
background: #ffffff;
color: #333333;
}
.ui-widget-header a {
color: #333333;
}
/* Touch feedback indicator */
.ui-touch-feedback-icon {
background-image: url('../img/touch_sprite_feedback.png');
width: 300px;
height: 120px;
position: absolute;
left: -9999px;
top: -9999px;
z-index: 2;
}
.feedback-container {
z-index: 2;
position: absolute;
display: none;
}
.feedback-container.cursor-icon {
background: url('../img/touch_sprite_feedback.png') -260px -15px no-repeat;
width: 17px;
height: 23px;
}
.feedback-container.tap-icon {
background: url('../img/touch_sprite_feedback.png') -300px -15px no-repeat;
width: 36px;
height: 36px;
}
.feedback-container.drag-icon {
background: url('../img/touch_sprite_feedback.png') -10px -10px no-repeat;
width: 100px;
height: 100px;
}
.feedback-container.pulse-icon {
background: url('../img/touch_sprite_feedback.png') -111px -10px no-repeat;
width: 100px;
height: 100px;
}
.feedback-container.scroll-icon {
background: url('../img/touch_sprite_feedback.png') -212px -10px no-repeat;
width: 27px;
height: 100px;
}
/* CSS3 feedback indicator animation. Keep it simple (uses lower cpu cycles)
as there may be multiple animation requests made in quick successions. */
.animate-feedback-indicator {
display: block;
opacity: 0;
animation-name: showfadeout;
animation-duration: 350ms;
-webkit-animation-name: showfadeout;
-webkit-animation-duration: 350ms;
-moz-animation-name: showfadeout;
-moz-animation-duration: 350ms;
-ms-animation-name: showfadeout;
-ms-animation-duration: 350ms;
}
@-webkit-keyframes showfadeout {
0% { opacity: 1; }
100% { opacity: 0; }
}
@-moz-keyframes showfadeout {
0% { opacity: 1; }
100% { opacity: 0; }
}
@-ms-keyframes showfadeout {
0% { opacity: 1; }
100% { opacity: 0; }
}
.animate-double-feedback-indicator {
display: block;
opacity: 0;
animation-name: showdoublefadeout;
animation-duration: 400ms;
-webkit-animation-name: showdoublefadeout;
-webkit-animation-duration: 400ms;
-moz-animation-name: showdoublefadeout;
-moz-animation-duration: 400ms;
-ms-animation-name: showdoublefadeout;
-ms-animation-duration: 400ms;
}
@-webkit-keyframes showdoublefadeout {
0% { opacity: 1; }
40% { opacity: 0; }
70% { opacity: 1; }
100% { opacity: 0; }
}
@-moz-keyframes showdoublefadeout {
0% { opacity: 1; }
40% { opacity: 0; }
70% { opacity: 1; }
100% { opacity: 0; }
}
@-ms-keyframes showdoublefadeout {
0% { opacity: 1; }
40% { opacity: 0; }
70% { opacity: 1; }
100% { opacity: 0; }
}

View File

@ -0,0 +1,192 @@
/******************************************************************************
* Copyright 2013 VMware, Inc. All rights reserved.
*****************************************************************************/
/*
* trackpad.css
*
* Defines style for the trackpad widget.
*/
/*
* jQuery UI Dialog 1.8.16
*/
.ui-dialog {
padding: 0;
box-shadow: 0px 5px 7px rgba(0,0,0,.5);
}
.ui-dialog .ui-dialog-titlebar {
padding: .8em .8em;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.ui-dialog .ui-dialog-titlebar-close {
right: .4em;
margin-top: -11px;
}
.ui-widget-content {
border: 0;
background: #ffffff;
color: #333333;
}
.ui-widget-header a {
color: #333333;
}
/*
* Touch sprite is loaded in a single class (as we have disabled caching images).
* We do this for the iOS case, due to extreme limitations in terms of image size.
* This form of grouped declaration forces all these definitions to load the same
* sprite. (This is also loaded upfront for the navbar so its always visible).
* For details see PR - 978390.
*/
.trackpad-wrapper .ui-dialog-titlebar-close .ui-icon,
.trackpad-wrapper .ui-dialog-titlebar .ui-dialog-title,
.touch-sprite {
background-image: url('../img/touch_sprite.png');
}
/* Replace jquery ui title bar close icon. */
.trackpad-wrapper .ui-dialog-titlebar-close {
margin-top: -9px;
border: 0 !important;
background: none !important;
}
.trackpad-wrapper .ui-dialog-titlebar-close {
margin-top: -11px;
}
/* Background-image is defined along with touch-sprite in 1 place. */
.trackpad-wrapper .ui-dialog-titlebar-close .ui-icon {
background-position: -9px -239px;
background-repeat: no-repeat;
}
.trackpad-wrapper .ui-dialog-titlebar-close .ui-icon:active {
background-position-x: -24px;
background-repeat: no-repeat;
}
/* The grabber icon indicating the dialog could be moved around */
.trackpad-wrapper .ui-dialog-titlebar .ui-dialog-title {
background-position: -10px -255px;
background-repeat: no-repeat;
width: 40px;
height: 14px;
margin: 0 0 0 42%;
}
.trackpad-wrapper .ui-dialog-titlebar .ui-dialog-title:active {
background-position-x: -52px;
}
.trackpad-wrapper {
width: 289px !important; /* As this is less than the default value */
border: 1px solid #333 !important;
background: none !important;
border-radius: 6px;
box-shadow: 0px 4px 9px rgba(0,0,0,.6);
}
.trackpad-wrapper .ui-dialog-titlebar {
border-top: 1px solid #ccc;
border-left: 1px solid #aaa;
border-right: 1px solid #aaa;
border-bottom: 0;
padding: .5em .8em .4em .8em;
background: rgb(175,176,187); /* Old browsers */
background: -webkit-linear-gradient(top, rgba(175,176,187,.93) 0%,rgba(170,171,182,.93) 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, rgba(175,176,187,.93) 0%,rgba(170,171,182,.93) 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, rgba(175,176,187,.93) 0%,rgba(170,171,182,.93) 100%); /* IE10+ */
background: linear-gradient(top, rgba(175,176,187,.93) 0%,rgba(170,171,182,.93) 100%); /* W3C */
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}
.trackpad-wrapper .trackpad-container {
padding: 0 !important;
}
.trackpad-wrapper .left-border {
background: rgb(170,171,182); /* Old browsers */
background: -webkit-linear-gradient(top, rgba(170,171,182,.93) 0%,rgba(123,123,133,.93) 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, rgba(170,171,182,.93) 0%,rgba(123,123,133,.93) 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, rgba(170,171,182,.93) 0%,rgba(123,123,133,.93) 100%); /* IE10+ */
background: linear-gradient(top, rgba(170,171,182,.93) 0%,rgba(123,123,133,.93) 100%); /* W3C */
margin-top: -1px;
float: left;
width: 12px;
height: 209px;
border: 0;
}
.trackpad-wrapper .touch-area {
background: rgba(255,255,255,0.8);
background: -webkit-linear-gradient(-70deg, rgba(255,255,255,0.8) 0%, rgba(238,238,240,0.8) 22%, rgba(210,210,216,0.8) 71%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(-70deg, rgba(255,255,255,0.8) 0%, rgba(238,238,240,0.8) 22%, rgba(210,210,216,0.8) 71%); /* Opera 11.10+ */
background: -ms-linear-gradient(-70deg, rgba(255,255,255,0.8) 0%, rgba(238,238,240,0.8) 22%, rgba(210,210,216,0.8) 71%); /* IE10+ */
background: linear-gradient(110deg, rgba(255,255,255,0.8) 0%, rgba(238,238,240,0.8) 22%, rgba(210,210,216,0.8) 71%); /* W3C */
border: 1px solid #555;
box-shadow: 0 2px 6px 1px #888 inset;
float: left;
width: 263px;
height: 206px;
}
.trackpad-wrapper .right-border {
background: rgb(170,171,182); /* Old browsers */
background: -webkit-linear-gradient(top, rgba(170,171,182,.93) 0%,rgba(123,123,133,.93) 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, rgba(170,171,182,.93) 0%,rgba(123,123,133,.93) 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, rgba(170,171,182,.93) 0%,rgba(123,123,133,.93) 100%); /* IE10+ */
background: linear-gradient(top, rgba(170,171,182,.93) 0%,rgba(123,123,133,.93) 100%); /* W3C */
margin-top: -1px;
float: left;
width: 12px;
height: 209px;
border: 0;
}
.trackpad-wrapper .bottom-border {
background: rgb(123,123,133); /* Old browsers */
background: -webkit-linear-gradient(top, rgba(123,123,133,.93) 0%,rgba(110,110,119,.93) 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, rgba(123,123,133,.93) 0%,rgba(110,110,119,.93) 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, rgba(123,123,133,.93) 0%,rgba(110,110,119,.93) 100%); /* IE10+ */
background: linear-gradient(top, rgba(123,123,133,.93) 0%,rgba(110,110,119,.93) 100%); /* W3C */
width: 289px;
height: 73px;
margin-top: 208px;
border: 0;
}
.trackpad-wrapper .button-left, .trackpad-wrapper .button-right {
background: rgb(255,255,255); /* Old browsers */
background: -webkit-linear-gradient(top, rgba(255,255,255,.7) 0%,rgba(225,225,227,.7) 3%,rgba(204,204,204,.7) 45%,rgba(190,190,195,.7) 96%,rgba(131,131,135,.7) 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, rgba(255,255,255,.7) 0%,rgba(225,225,227,.7) 3%,rgba(204,204,204,.7) 45%,rgba(190,190,195,.7) 96%,rgba(131,131,135,.7) 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, rgba(255,255,255,.7) 0%,rgba(225,225,227,.7) 3%,rgba(204,204,204,.7) 45%,rgba(190,190,195,.7) 96%,rgba(131,131,135,.7) 100%); /* IE10+ */
background: linear-gradient(top, rgba(255,255,255,.7) 0%,rgba(225,225,227,.7) 3%,rgba(204,204,204,.7) 45%,rgba(190,190,195,.7) 96%,rgba(131,131,135,.7) 100%); /* W3C */
border-radius: 6px;
box-shadow: 0 2px 5px #333;
float: left;
width: 126px;
height: 47px;
}
.trackpad-wrapper .button-left {
margin: 12px 0px auto 12px;
}
.trackpad-wrapper .button-right {
margin: 12px;
}
.trackpad-wrapper .button-left.button-highlight,
.trackpad-wrapper .button-right.button-highlight {
background: -webkit-linear-gradient(top, rgba(170,171,182,.7) 0%,rgba(123,123,133,.7) 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, rgba(170,171,182,.7) 0%,rgba(123,123,133,.7) 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, rgba(170,171,182,.7) 0%,rgba(123,123,133,.7) 100%); /* IE10+ */
background: linear-gradient(top, rgba(170,171,182,.7) 0%,rgba(123,123,133,.7) 100%); /* W3C */
}

View File

@ -0,0 +1,661 @@
/******************************************************************************
* Copyright 2013 VMware, Inc. All rights reserved.
*****************************************************************************/
/*
* main-ui.css
*
* Defines style for the wmks ui widgets.
*
* Use CSS3 for touch devices as jquery effects break when browser handles
* orientation changes, or page bouncing.
*
* TODO: Need to handle Retina mode for iPad.
*/
/*
* jQuery UI Dialog 1.8.16
*/
.ui-dialog {
padding: 0;
box-shadow: 0px 5px 7px rgba(0,0,0,.5);
}
.ui-dialog .ui-dialog-titlebar {
padding: .8em .8em;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.ui-dialog .ui-dialog-titlebar-close {
right: .4em;
margin-top: -11px;
}
.ui-widget-content {
border: 0;
background: #ffffff;
color: #333333;
}
.ui-widget-header a {
color: #333333;
}
/* Touch feedback indicator */
.ui-touch-feedback-icon {
background-image: url('../img/touch_sprite_feedback.png');
width: 300px;
height: 120px;
position: absolute;
left: -9999px;
top: -9999px;
z-index: 2;
}
.feedback-container {
z-index: 2;
position: absolute;
display: none;
}
.feedback-container.cursor-icon {
background: url('../img/touch_sprite_feedback.png') -260px -15px no-repeat;
width: 17px;
height: 23px;
}
.feedback-container.tap-icon {
background: url('../img/touch_sprite_feedback.png') -300px -15px no-repeat;
width: 36px;
height: 36px;
}
.feedback-container.drag-icon {
background: url('../img/touch_sprite_feedback.png') -10px -10px no-repeat;
width: 100px;
height: 100px;
}
.feedback-container.pulse-icon {
background: url('../img/touch_sprite_feedback.png') -111px -10px no-repeat;
width: 100px;
height: 100px;
}
.feedback-container.scroll-icon {
background: url('../img/touch_sprite_feedback.png') -212px -10px no-repeat;
width: 27px;
height: 100px;
}
/* CSS3 feedback indicator animation. Keep it simple (uses lower cpu cycles)
as there may be multiple animation requests made in quick successions. */
.animate-feedback-indicator {
display: block;
opacity: 0;
animation-name: showfadeout;
animation-duration: 350ms;
-webkit-animation-name: showfadeout;
-webkit-animation-duration: 350ms;
-moz-animation-name: showfadeout;
-moz-animation-duration: 350ms;
-ms-animation-name: showfadeout;
-ms-animation-duration: 350ms;
}
@-webkit-keyframes showfadeout {
0% { opacity: 1; }
100% { opacity: 0; }
}
@-moz-keyframes showfadeout {
0% { opacity: 1; }
100% { opacity: 0; }
}
@-ms-keyframes showfadeout {
0% { opacity: 1; }
100% { opacity: 0; }
}
.animate-double-feedback-indicator {
display: block;
opacity: 0;
animation-name: showdoublefadeout;
animation-duration: 400ms;
-webkit-animation-name: showdoublefadeout;
-webkit-animation-duration: 400ms;
-moz-animation-name: showdoublefadeout;
-moz-animation-duration: 400ms;
-ms-animation-name: showdoublefadeout;
-ms-animation-duration: 400ms;
}
@-webkit-keyframes showdoublefadeout {
0% { opacity: 1; }
40% { opacity: 0; }
70% { opacity: 1; }
100% { opacity: 0; }
}
@-moz-keyframes showdoublefadeout {
0% { opacity: 1; }
40% { opacity: 0; }
70% { opacity: 1; }
100% { opacity: 0; }
}
@-ms-keyframes showdoublefadeout {
0% { opacity: 1; }
40% { opacity: 0; }
70% { opacity: 1; }
100% { opacity: 0; }
}
/******************************************************************************
* Copyright 2013 VMware, Inc. All rights reserved.
*****************************************************************************/
/*
* trackpad.css
*
* Defines style for the trackpad widget.
*/
/*
* jQuery UI Dialog 1.8.16
*/
.ui-dialog {
padding: 0;
box-shadow: 0px 5px 7px rgba(0,0,0,.5);
}
.ui-dialog .ui-dialog-titlebar {
padding: .8em .8em;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.ui-dialog .ui-dialog-titlebar-close {
right: .4em;
margin-top: -11px;
}
.ui-widget-content {
border: 0;
background: #ffffff;
color: #333333;
}
.ui-widget-header a {
color: #333333;
}
/*
* Touch sprite is loaded in a single class (as we have disabled caching images).
* We do this for the iOS case, due to extreme limitations in terms of image size.
* This form of grouped declaration forces all these definitions to load the same
* sprite. (This is also loaded upfront for the navbar so its always visible).
* For details see PR - 978390.
*/
.trackpad-wrapper .ui-dialog-titlebar-close .ui-icon,
.trackpad-wrapper .ui-dialog-titlebar .ui-dialog-title,
.touch-sprite {
background-image: url('../img/touch_sprite.png');
}
/* Replace jquery ui title bar close icon. */
.trackpad-wrapper .ui-dialog-titlebar-close {
margin-top: -9px;
border: 0 !important;
background: none !important;
}
.trackpad-wrapper .ui-dialog-titlebar-close {
margin-top: -11px;
}
/* Background-image is defined along with touch-sprite in 1 place. */
.trackpad-wrapper .ui-dialog-titlebar-close .ui-icon {
background-position: -9px -239px;
background-repeat: no-repeat;
}
.trackpad-wrapper .ui-dialog-titlebar-close .ui-icon:active {
background-position-x: -24px;
background-repeat: no-repeat;
}
/* The grabber icon indicating the dialog could be moved around */
.trackpad-wrapper .ui-dialog-titlebar .ui-dialog-title {
background-position: -10px -255px;
background-repeat: no-repeat;
width: 40px;
height: 14px;
margin: 0 0 0 42%;
}
.trackpad-wrapper .ui-dialog-titlebar .ui-dialog-title:active {
background-position-x: -52px;
}
.trackpad-wrapper {
width: 289px !important; /* As this is less than the default value */
border: 1px solid #333 !important;
background: none !important;
border-radius: 6px;
box-shadow: 0px 4px 9px rgba(0,0,0,.6);
}
.trackpad-wrapper .ui-dialog-titlebar {
border-top: 1px solid #ccc;
border-left: 1px solid #aaa;
border-right: 1px solid #aaa;
border-bottom: 0;
padding: .5em .8em .4em .8em;
background: rgb(175,176,187); /* Old browsers */
background: -webkit-linear-gradient(top, rgba(175,176,187,.93) 0%,rgba(170,171,182,.93) 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, rgba(175,176,187,.93) 0%,rgba(170,171,182,.93) 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, rgba(175,176,187,.93) 0%,rgba(170,171,182,.93) 100%); /* IE10+ */
background: linear-gradient(top, rgba(175,176,187,.93) 0%,rgba(170,171,182,.93) 100%); /* W3C */
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}
.trackpad-wrapper .trackpad-container {
padding: 0 !important;
}
.trackpad-wrapper .left-border {
background: rgb(170,171,182); /* Old browsers */
background: -webkit-linear-gradient(top, rgba(170,171,182,.93) 0%,rgba(123,123,133,.93) 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, rgba(170,171,182,.93) 0%,rgba(123,123,133,.93) 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, rgba(170,171,182,.93) 0%,rgba(123,123,133,.93) 100%); /* IE10+ */
background: linear-gradient(top, rgba(170,171,182,.93) 0%,rgba(123,123,133,.93) 100%); /* W3C */
margin-top: -1px;
float: left;
width: 12px;
height: 209px;
border: 0;
}
.trackpad-wrapper .touch-area {
background: rgba(255,255,255,0.8);
background: -webkit-linear-gradient(-70deg, rgba(255,255,255,0.8) 0%, rgba(238,238,240,0.8) 22%, rgba(210,210,216,0.8) 71%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(-70deg, rgba(255,255,255,0.8) 0%, rgba(238,238,240,0.8) 22%, rgba(210,210,216,0.8) 71%); /* Opera 11.10+ */
background: -ms-linear-gradient(-70deg, rgba(255,255,255,0.8) 0%, rgba(238,238,240,0.8) 22%, rgba(210,210,216,0.8) 71%); /* IE10+ */
background: linear-gradient(110deg, rgba(255,255,255,0.8) 0%, rgba(238,238,240,0.8) 22%, rgba(210,210,216,0.8) 71%); /* W3C */
border: 1px solid #555;
box-shadow: 0 2px 6px 1px #888 inset;
float: left;
width: 263px;
height: 206px;
}
.trackpad-wrapper .right-border {
background: rgb(170,171,182); /* Old browsers */
background: -webkit-linear-gradient(top, rgba(170,171,182,.93) 0%,rgba(123,123,133,.93) 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, rgba(170,171,182,.93) 0%,rgba(123,123,133,.93) 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, rgba(170,171,182,.93) 0%,rgba(123,123,133,.93) 100%); /* IE10+ */
background: linear-gradient(top, rgba(170,171,182,.93) 0%,rgba(123,123,133,.93) 100%); /* W3C */
margin-top: -1px;
float: left;
width: 12px;
height: 209px;
border: 0;
}
.trackpad-wrapper .bottom-border {
background: rgb(123,123,133); /* Old browsers */
background: -webkit-linear-gradient(top, rgba(123,123,133,.93) 0%,rgba(110,110,119,.93) 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, rgba(123,123,133,.93) 0%,rgba(110,110,119,.93) 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, rgba(123,123,133,.93) 0%,rgba(110,110,119,.93) 100%); /* IE10+ */
background: linear-gradient(top, rgba(123,123,133,.93) 0%,rgba(110,110,119,.93) 100%); /* W3C */
width: 289px;
height: 73px;
margin-top: 208px;
border: 0;
}
.trackpad-wrapper .button-left, .trackpad-wrapper .button-right {
background: rgb(255,255,255); /* Old browsers */
background: -webkit-linear-gradient(top, rgba(255,255,255,.7) 0%,rgba(225,225,227,.7) 3%,rgba(204,204,204,.7) 45%,rgba(190,190,195,.7) 96%,rgba(131,131,135,.7) 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, rgba(255,255,255,.7) 0%,rgba(225,225,227,.7) 3%,rgba(204,204,204,.7) 45%,rgba(190,190,195,.7) 96%,rgba(131,131,135,.7) 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, rgba(255,255,255,.7) 0%,rgba(225,225,227,.7) 3%,rgba(204,204,204,.7) 45%,rgba(190,190,195,.7) 96%,rgba(131,131,135,.7) 100%); /* IE10+ */
background: linear-gradient(top, rgba(255,255,255,.7) 0%,rgba(225,225,227,.7) 3%,rgba(204,204,204,.7) 45%,rgba(190,190,195,.7) 96%,rgba(131,131,135,.7) 100%); /* W3C */
border-radius: 6px;
box-shadow: 0 2px 5px #333;
float: left;
width: 126px;
height: 47px;
}
.trackpad-wrapper .button-left {
margin: 12px 0px auto 12px;
}
.trackpad-wrapper .button-right {
margin: 12px;
}
.trackpad-wrapper .button-left.button-highlight,
.trackpad-wrapper .button-right.button-highlight {
background: -webkit-linear-gradient(top, rgba(170,171,182,.7) 0%,rgba(123,123,133,.7) 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, rgba(170,171,182,.7) 0%,rgba(123,123,133,.7) 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, rgba(170,171,182,.7) 0%,rgba(123,123,133,.7) 100%); /* IE10+ */
background: linear-gradient(top, rgba(170,171,182,.7) 0%,rgba(123,123,133,.7) 100%); /* W3C */
}
/******************************************************************************
* Copyright 2013 VMware, Inc. All rights reserved.
*****************************************************************************/
/*
* extended-keypad.css
*
* Defines style for the virtual keys on the control pane.
*/
.ctrl-pane-wrapper {
width: 290px !important; /* Needed as the default is a bit larger than this */
border: 1px solid #333 !important;
-moz-border-radius: 6px; -webkit-border-radius: 6px; -khtml-border-radius: 6px; border-radius: 6px;
background: rgb(170,171,182); /* Old browsers */
background: -webkit-linear-gradient(top, rgba(170,171,182,.93) 0%,rgba(123,123,133,.93) 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, rgba(170,171,182,.93) 0%,rgba(123,123,133,.93) 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, rgba(170,171,182,.93) 0%,rgba(123,123,133,.93) 100%); /* IE10+ */
background: linear-gradient(top, rgba(170,171,182,.93) 0%,rgba(123,123,133,.93) 100%); /* W3C */
}
.fnKey-pane-wrapper {
width: 427px;
border: 1px solid #333;
-moz-border-radius: 6px; -webkit-border-radius: 6px; -khtml-border-radius: 6px; border-radius: 6px;
background: #c1c4d1; /* Old browsers */
background: -webkit-linear-gradient(top, #c1c4d1 0%,#b0b1bd 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #c1c4d1 0%,#b0b1bd 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #c1c4d1 0%,#b0b1bd 100%); /* IE10+ */
background: linear-gradient(top, #c1c4d1 0%, #b0b1bd 100%); /* W3C */
position: absolute;
padding: 0;
-moz-box-shadow: 0px 5px 7px rgba(0,0,0,.5);
-webkit-box-shadow: 0px 5px 7px rgba(0,0,0,.5);
box-shadow: 0px 5px 7px rgba(0,0,0,.5);
}
.fnKey-pane-wrapper-down {
width: 427px;
border: 1px solid #333;
-moz-border-radius: 6px; -webkit-border-radius: 6px; -khtml-border-radius: 6px; border-radius: 6px;
background: #6e6e77; /* Old browsers */
background: -webkit-linear-gradient(top, #6e6e77 0%,#656565 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #6e6e77 0%,#656565 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #6e6e77 0%,#656565 100%); /* IE10+ */
background: linear-gradient(top, #6e6e77 0%, #656565 100%); /* W3C */
position: absolute;
padding: 0;
-moz-box-shadow: 0px 5px 7px rgba(0,0,0,.5);
-webkit-box-shadow: 0px 5px 7px rgba(0,0,0,.5);
box-shadow: 0px 5px 7px rgba(0,0,0,.5);
}
/* Hide jquery ui title bar. */
.ctrl-pane-wrapper .ui-dialog-titlebar {
border-top: 1px solid #ccc;
border-left: 1px solid #aaa;
border-right: 1px solid #aaa;
border-bottom: 0;
padding: .6em .8em 0 .8em;
background: none !important;
-moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; -khtml-border-top-left-radius: 5px; border-top-left-radius: 5px;
-moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; -khtml-border-top-right-radius: 5px; border-top-right-radius: 5px;
}
/* Replace jquery ui title bar close icon. */
.ctrl-pane-wrapper .ui-dialog-titlebar-close {
margin-top: -9px;
border: 0 !important;
background: none !important;
}
/* Background-image is defined along with touch-sprite in 1 place. */
.ctrl-pane-wrapper .ui-dialog-titlebar-close .ui-icon {
background-position: -9px -239px;
background-repeat: no-repeat;
}
.ctrl-pane-wrapper .ui-dialog-titlebar-close .ui-icon:active {
background-position-x: -24px;
background-repeat: no-repeat;
}
/* The grabber icon indicating the dialog could be moved around */
.ctrl-pane-wrapper .ui-dialog-titlebar .ui-dialog-title {
background-position: -10px -255px;
background-repeat: no-repeat;
width: 40px;
height: 14px;
margin: 0 0 0 42%;
}
.ctrl-pane-wrapper .ui-dialog-titlebar .ui-dialog-title:active {
background-position-x: -52px;
}
.ctrl-pane-wrapper .ui-dialog-content {
background: none !important;
padding: 0 0;
border-style: solid;
border-color: #aaaaaa;
border-width: 0 1px 1px 1px;
-moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; -khtml-border-bottom-left-radius: 5px; border-bottom-left-radius: 5px;
-moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; -khtml-border-bottom-right-radius: 5px; border-bottom-right-radius: 5px;
}
.fnKey-inner-border-helper {
position: relative;
background: none !important;
border-style: solid;
border-color: #d5d5d5;
border-width: 1px;
-moz-border-radius: 5px; -webkit-border-radius: 5px; -khtml-border-radius: 5px; border-radius: 5px;
pointer-events:none;
}
.ctrl-pane-wrapper .ctrl-pane {
padding: 3px 0 3px 6px;
height: 140px;
width: 280px;
}
.ctrl-pane .baseKey {
float: left;
border: 0;
padding: 0;
width: 57px;
height: 57px;
margin: 6px;
-moz-border-radius: 6px; -webkit-border-radius: 6px; -khtml-border-radius: 6px; border-radius: 6px;
font-family: "HelveticaNeue", "Helvetica Neue", "HelveticaNeue", "Helvetica Neue", 'TeXGyreHeros', "Helvetica", "Tahoma", "Geneva", "Arial", sans-serif;
font-size: 18px;
text-shadow: 0 1px 1px #eeeeee;
-moz-box-shadow: 0px 1px 3px rgba(0, 0, 0, .7);
-webkit-box-shadow: 0px 1px 3px rgba(0,0,0,.7);
box-shadow: 0px 1px 3px rgba(0,0,0,.7);
}
.ctrl-pane .ctrl-key-top-row {
background: -webkit-linear-gradient(top, #fff 0%,#f3f5fb 2%,#d2d2d8 98%,#999 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #fff 0%,#f3f5fb 2%,#d2d2d8 98%,#999 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #fff 0%,#f3f5fb 2%,#d2d2d8 98%,#999 100%); /* IE10+ */
background: linear-gradient(top, #fff 0%,#f3f5fb 2%,#d2d2d8 98%,#999 100%); /* W3C */
}
.ctrl-pane .ctrl-key-bottom-row {
background: -webkit-linear-gradient(top, #fff 0%,#e1e1e3 2%,#d1d1d4 50%,#bebec3 98%,#838387 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #fff 0%,#e1e1e3 2%,#d1d1d4 50%,#bebec3 98%,#838387 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #fff 0%,#e1e1e3 2%,#d1d1d4 50%,#bebec3 98%,#838387 100%); /* IE10+ */
background: linear-gradient(top, #fff 0%,#e1e1e3 2%,#d1d1d4 50%,#bebec3 98%,#838387 100%); /* W3C */
}
.ctrl-pane .up-position .fn-key-top-row {
color:#333;
background: #ffffff; /* Old browsers */
background: -webkit-linear-gradient(top, #ffffff 0%,#f7f7f7 2%,#dcdde3 96%,#999999 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #ffffff 0%,#f7f7f7 2%,#dcdde3 96%,#999999 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #ffffff 0%,#f7f7f7 2%,#dcdde3 96%,#999999 100%); /* IE10+ */
background: linear-gradient(top, #ffffff 0%,#f7f7f7 2%,#dcdde3 96%,#999999 100%); /* W3C */
}
.ctrl-pane .up-position .fn-key-bottom-row {
color:#333;
background: #ffffff; /* Old browsers */
background: -webkit-linear-gradient(top, #ffffff 0%,#f3f5fb 2%,#d2d2d8 98%,#999999 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #ffffff 0%,#f3f5fb 2%,#d2d2d8 98%,#999999 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #ffffff 0%,#f3f5fb 2%,#d2d2d8 98%,#999999 100%); /* IE10+ */
background: linear-gradient(top, #ffffff 0%,#f3f5fb 2%,#d2d2d8 98%,#999999 100%); /* W3C */
}
.ctrl-pane .down-position .fn-key-top-row {
color:#333;
background: #ffffff; /* Old browsers */
background: -webkit-linear-gradient(top, #ffffff 0%,#e1e1e3 4%,#d1d1d4 45%,#b7b8bd 98%,#838387 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #ffffff 0%,#e1e1e3 4%,#d1d1d4 45%,#b7b8bd 98%,#838387 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #ffffff 0%,#e1e1e3 4%,#d1d1d4 45%,#b7b8bd 98%,#838387 100%); /* IE10+ */
background: linear-gradient(top, #ffffff 0%,#e1e1e3 4%,#d1d1d4 45%,#b7b8bd 98%,#838387 100%); /* W3C */
}
.ctrl-pane .down-position .fn-key-bottom-row {
color:#333;
background: #ffffff; /* Old browsers */
background: -webkit-linear-gradient(top, #ffffff 0%,#d9dadd 4%,#c8c8cd 45%,#b0b0b7 98%,#838387 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #ffffff 0%,#d9dadd 4%,#c8c8cd 45%,#b0b0b7 98%,#838387 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #ffffff 0%,#d9dadd 4%,#c8c8cd 45%,#b0b0b7 98%,#838387 100%); /* IE10+ */
background: linear-gradient(top, #ffffff 0%,#d9dadd 4%,#c8c8cd 45%,#b0b0b7 98%,#838387 100%); /* W3C */
}
.ctrl-pane .fn-key-top-row {
margin: 12px 6px 6px 6px;
}
.ctrl-pane .border-key-top-left .fn-key-top-row {
margin: 12px 6px 6px 12px;
}
.ctrl-pane .border-key-top-right .fn-key-top-row {
margin: 12px 12px 6px 6px;
}
.ctrl-pane .fn-key-bottom-row {
margin: 5px 6px 12px 6px;
}
.ctrl-pane .border-key-bottom-left .fn-key-bottom-row {
margin: 5px 6px 12px 12px;
}
.ctrl-pane .border-key-bottom-right .fn-key-bottom-row {
margin: 5px 12px 12px 6px;
}
.ctrl-pane .ctrl-key-top-row:active, .ctrl-pane .fn-key-top-row:active,
.ctrl-pane .ctrl-key-bottom-row:active, .ctrl-pane .fn-key-bottom-row:active {
background: #bbbbbb;
background: -webkit-linear-gradient(bottom, #888888 25%, #CCCCCC 68%);
background: -ms-linear-gradient(bottom, #888888 25%, #CCCCCC 68%);
background: -o-linear-gradient(bottom, #888888 25%, #CCCCCC 68%);
background: linear-gradient(bottom, #888888 25%, #CCCCCC 68%);
}
.ctrl-pane .ctrl-key-top-row div, .ctrl-pane .ctrl-key-bottom-row div,
.ctrl-pane .fn-key-top-row div, .ctrl-pane .fn-key-bottom-row div {
width: 100%;
text-align: center;
padding-top: 17px;
overflow-x: hidden;
}
/* Highlight selected modifier key */
.ctrl-pane .ab-modifier-key-down {
color: #4D8DFF;
}
.ctrl-pane .baseKey img { /* use .touch-sprite for image */
background-repeat: no-repeat;
width: 57px;
height: 57px;
border: 0;
-moz-border-radius: 6px; -webkit-border-radius: 6px; -khtml-border-radius: 6px; border-radius: 6px;
}
.ctrl-pane .baseKey .right-arrow {
background-position: -242px -182px;
}
.ctrl-pane .baseKey .left-arrow {
background-position: -126px -182px;
}
.ctrl-pane .baseKey .up-arrow {
background-position: -299px -182px;
}
.ctrl-pane .baseKey .down-arrow {
background-position: -183px -182px;
}
.ctrl-pane .baseKey .more-keys {
background-position: -10px -182px;
}
/* Ctrl - pane flip transition. */
.ctrl-pane.flip-container {
perspective: 1000;
-webkit-perspective: 1000;
-moz-perspective: 1000;
-ms-perspective: 1000;
}
/* flip the ctrl-pane when this class toggles. */
.flip-container.perform-flip .flipper {
transform: rotateY(180deg);
-webkit-transform: rotateY(180deg);
-moz-transform: rotateY(180deg);
-ms-transform: rotateY(180deg);
}
/* flip speed goes here */
.flip-container .flipper {
transition: 0.6s;
transform-style: preserve-3d;
-webkit-transition: 0.6s;
-webkit-transform-style: preserve-3d;
-moz-transition: 0.6s;
-moz-transform-style: preserve-3d;
-ms-transition: 0.6s;
-ms-transform-style: preserve-3d;
position: relative;
}
/* hide back of pane during swap */
.flip-container .front, .flip-container .back {
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
-ms-backface-visibility: hidden;
position: absolute;
top: 0;
left: 0;
}
/* front pane, placed above back */
.flip-container .front {
z-index: 200;
}
/* back, initially hidden pane */
.flip-container .back {
transform: rotateY(180deg);
-webkit-transform: rotateY(180deg);
-moz-transform: rotateY(180deg);
-ms-transform: rotateY(180deg);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because one or more lines are too long

View File

@ -20,7 +20,8 @@
"jquery-ui": "~1.12.1",
"wickedpicker": "https://github.com/OpenNebula/sunstone-deps.git#9398b3f",
"guacamole-common-js": "https://github.com/OpenNebula/sunstone-deps.git#1633556e63",
"webauthn-json": "https://registry.npmjs.org/@github/webauthn-json/-/webauthn-json-0.4.1.tgz"
"webauthn-json": "https://registry.npmjs.org/@github/webauthn-json/-/webauthn-json-0.4.1.tgz",
"wmks": "https://github.com/OpenNebula/sunstone-deps.git#cb0251c"
},
"authors": [
"Daniel Molina <dmolina@opennebula.org>",

View File

@ -122,6 +122,7 @@ require "sunstone_2f_auth"
require 'CloudAuth'
require 'SunstoneServer'
require 'SunstoneViews'
require 'OpenNebulaValidateFireedge'
require 'sinatra-websocket'
require 'eventmachine'
@ -147,6 +148,8 @@ rescue Exception => e
exit 1
end
$conf[:fireedge_up] = false
if $conf[:one_xmlrpc_timeout]
ENV['ONE_XMLRPC_TIMEOUT'] = $conf[:one_xmlrpc_timeout].to_s unless ENV['ONE_XMLRPC_TIMEOUT']
end
@ -227,6 +230,12 @@ use Rack::Deflater
include CloudLogger
logger=enable_logging(SUNSTONE_LOG, $conf[:debug_level].to_i)
@ValidateFireedge = ValidateFireedge.new($conf, logger)
Thread.new do
@ValidateFireedge.validate_fireedge_running
end
begin
ENV["ONE_CIPHER_AUTH"] = SUNSTONE_AUTH
$cloud_auth = CloudAuth.new($conf, logger)
@ -263,9 +272,13 @@ $vnc = OpenNebulaVNC.new($conf, logger)
#init Guacamole server
$guac = OpenNebulaGuac.new($conf, logger)
#init VMRC server
$vmrc = OpenNebulaVMRC.new($conf, logger)
configure do
set :run, false
set :vnc, $vnc
set :vmrc, $vmrc
set :erb, :trim => '-'
end
@ -546,7 +559,7 @@ before do
@request_body = request.body.read
request.body.rewind
unless %w(/ /login /vnc /spice /version /webauthn_options_for_get /ws).include?(request.path)
unless %w(/ /login /vnc /spice /version /webauthn_options_for_get /ws /vmrc).include?(request.path)
halt [401, "csrftoken"] unless authorized? && valid_csrftoken?
end
@ -744,6 +757,20 @@ get '/vnc' do
end
end
get '/vmrc' do
content_type 'text/html', :charset => 'utf-8'
if !authorized?
erb :login
else
erb :vmrc, :locals => {
:logos_conf => $conf[:locals][:logos_conf],
:oned_conf => $conf[:locals][:oned_conf],
:support => $conf[:locals][:support],
:upgrade => $conf[:locals][:upgrade]
}
end
end
get '/spice' do
content_type 'text/html', :charset => 'utf-8'
if !authorized?
@ -1106,6 +1133,14 @@ post '/vm/:id/guac/:type' do
@SunstoneServer.startguac(vm_id, type_connection, $guac)
end
##############################################################################
# Start VMRC Session for a target VM
##############################################################################
post '/vm/:id/startvmrc' do
vm_id = params[:id]
@SunstoneServer.startvmrc(vm_id, $vmrc)
end
##############################################################################
# Perform an action on a Resource
##############################################################################

View File

@ -42,9 +42,10 @@
'threshold_low' : '<%= $conf[:threshold_low] %>',
'threshold_high' : '<%= $conf[:threshold_high] %>',
'guac_port' : '<%= $conf[:guac_port] %>',
'vmrc_port' : '<%= $conf[:vmrc_port] %>',
},
'system_config' : {
'paginate': '<%= $conf[:paginate] %>',
'paginate': '<%= $conf[:paginate] %>',
'marketplace_url' : '<%= $conf[:marketplace_url] %>',
'vnc_request_password' : <%= $conf[:vnc_request_password] || false %>,
'vnc_proxy_port' : '<%= $vnc.proxy_port %>',
@ -57,7 +58,7 @@
'autorefresh_wss': '<%= session[:autorefresh_wss] %>',
'autorefresh_ip': '<%= $conf[:autorefresh_ip] %>',
'autorefresh_port': '<%= $conf[:port] %>',
'is_fireedge_up': '<%= $conf[:fireedge_up] %>',
},
'view' : view,
'available_views' : available_views,
@ -118,7 +119,6 @@
<div class="large-12 columns" id="dialogs"></div>
</div>
<% if $conf[:env] == 'dev' %>
<script src="bower_components/requirejs/require.js" data-main="app/main"></script>
<% else %>

View File

@ -0,0 +1,96 @@
<!DOCTYPE html>
<html>
<head>
<title><%= params['vm_name']%></title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<link rel="apple-touch-startup-image" href="images/screen_320x460.png" />
<link rel="apple-touch-icon" href="images/screen_57x57.png">
<!-- Stylesheets -->
<link rel="stylesheet" type="text/css" href="css/novnc-custom.css" title="plain">
<% view = $views_config.view(session[:user], session[:user_gname], session[:default_view]) %>
<!-- JQuery -->
<script src="bower_components/jquery/dist/jquery.min.js"></script>
<script src="bower_components/jquery-ui/jquery-ui.min.js"></script>
<!-- Scripts -->
<script type="text/javascript">
var csrftoken = '<%= session[:csrftoken] %>';
var view = JSON.parse('<%= view.to_json %>')
var available_views = JSON.parse('["<%=
$views_config.available_views(session[:user], session[:user_gname]).join('","')
%>"]')
var all_labels = JSON.parse('["<%=
$views_config.get_all_labels(session[:user_gname]).join('","')
%>"]')
var all_views = JSON.parse('["<%=
$views_config.get_all_views.join('","')
%>"]')
if ('<%= $conf[:addons] %>'){
var addons = JSON.parse('<%= $conf[:addons].to_json %>');
}
var config = {
'user_config' : {
'lang' : '<%= session[:lang] %>',
'vnc_wss' : '<%= session[:vnc_wss] %>',
'table_order' : '<%= session[:table_order] %>',
'default_view' : '<%= session[:default_view] %>',
'page_length' : '<%= session[:page_length] %>'
},
'system_config' : {
'marketplace_url' : '<%= $conf[:marketplace_url] %>',
'vnc_request_password' : <%= $conf[:vnc_request_password] || false %>,
'vnc_proxy_port' : '<%= $vnc.proxy_port %>',
'vnc_client_port' : '<%= $conf[:vnc_client_port] %>',
'max_upload_file_size' : <%= $conf[:max_upload_file_size] ? $conf[:max_upload_file_size] : "undefined" %>
},
'view' : view,
'available_views' : available_views,
'all_labels' : all_labels,
'all_views' : all_views,
'user_id' : '<%= session[:user_id] %>',
'user_gid' : '<%= session[:user_gid] %>',
'display_name' : '<%= session[:display_name] %>',
'zone_name' : '<%= session[:zone_name] %>',
'zone_id' : '<%= session[:zone_id] %>',
'federation_mode' : '<%= session[:federation_mode] %>',
'vm_logos' : <%= logos_conf.to_json %>,
'oned_conf' : <%= oned_conf.to_json %>,
'support' : <%= support.to_json %>,
'upgrade' : <%= upgrade.to_json %>,
'mode' : '<%= session[:mode] %>'
};
</script>
<script src="bower_components/wmks/wmks.min.js"></script>
<script src="dist/console/vmrc.js?v=<%= OpenNebula::VERSION %>"></script>
</head>
<body style="margin: 0px;">
<div id="VMRC_screen">
<div style="background: #f7f7f7; border-bottom: 1px solid #dfdfdf; padding: 10px 0px 15px 0px">
<div id="VMRC_status_bar" class="VMRC_status_bar" style="margin-top: 0px;">
<table border="0" width="100%">
<tr>
<td width="1%" >
<img src="images/one_small_logo.png" style="height:40px; vertical-align:top; margin-left: 30px"></td>
<td>
<div id="VMRC_status" style="position: relative; height: auto; color: #000; text-align:center;">Loading</div>
</td>
<td width="1%" >
<div id="VMRC_buttons" style="margin-right: 30px">
<input type=button value="Send CtrlAltDel"
id="sendCtrlAltDelButton">
</div>
</td>
</tr>
</table>
</div>
</div>
<div id="wmksContainer" style="position:absolute;width:100%;height:100%; left:0em"></div>
<div id="VMRC_canvas" width="640px" height="20px">
<div class="VMRC_message"></div>
</div>
</div>
</body>
</html>