root / ui / static / synnefo.js @ adab5d39
History | View | Annotate | Download (19.9 kB)
1 |
//
|
---|---|
2 |
// Copyright 2011 GRNET S.A. All rights reserved.
|
3 |
//
|
4 |
// Redistribution and use in source and binary forms, with or
|
5 |
// without modification, are permitted provided that the following
|
6 |
// conditions are met:
|
7 |
//
|
8 |
// 1. Redistributions of source code must retain the above
|
9 |
// copyright notice, this list of conditions and the following
|
10 |
// disclaimer.
|
11 |
//
|
12 |
// 2. Redistributions in binary form must reproduce the above
|
13 |
// copyright notice, this list of conditions and the following
|
14 |
// disclaimer in the documentation and/or other materials
|
15 |
// provided with the distribution.
|
16 |
//
|
17 |
// THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
|
18 |
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
19 |
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
20 |
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
|
21 |
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
22 |
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
23 |
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
24 |
// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
25 |
// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
26 |
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
27 |
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
28 |
// POSSIBILITY OF SUCH DAMAGE.
|
29 |
//
|
30 |
// The views and conclusions contained in the software and
|
31 |
// documentation are those of the authors and should not be
|
32 |
// interpreted as representing official policies, either expressed
|
33 |
// or implied, of GRNET S.A.
|
34 |
//
|
35 |
var API_URL = "/api/v1.1"; |
36 |
var changes_since = 0, deferred = 0, update_request = false, load_request = false, pending_actions = []; |
37 |
var flavors = [], images = [], servers = [], disks = [], cpus = [], ram = [];
|
38 |
var networks = [], networks_changes_since = 0; |
39 |
var error_timeout = 20000; |
40 |
var last_request = {};
|
41 |
|
42 |
|
43 |
Object.prototype.toString = function(o){ |
44 |
|
45 |
var parse = function(_o){ |
46 |
var a = [], t;
|
47 |
for(var p in _o){ |
48 |
if(_o.hasOwnProperty(p)){
|
49 |
t = _o[p]; |
50 |
if(t && typeof t == "object"){ |
51 |
a[a.length]= p + ":{ " + arguments.callee(t).join(", ") + "}"; |
52 |
} |
53 |
else {
|
54 |
if(typeof t == "string"){ |
55 |
a[a.length] = [ p+ ": \"" + t.toString() + "\"" ]; |
56 |
} |
57 |
else{
|
58 |
a[a.length] = [ p+ ": " + t.toString()];
|
59 |
} |
60 |
} |
61 |
} |
62 |
} |
63 |
return a;
|
64 |
|
65 |
} |
66 |
return "{" + parse(o).join(", ") + "}"; |
67 |
|
68 |
} |
69 |
|
70 |
// http://stackoverflow.com/questions/499126/jquery-set-cursor-position-in-text-area
|
71 |
$.fn.setCursorPosition = function(pos) { |
72 |
if ($(this).get(0).setSelectionRange) { |
73 |
$(this).get(0).setSelectionRange(pos, pos); |
74 |
} else if ($(this).get(0).createTextRange) { |
75 |
var range = $(this).get(0).createTextRange(); |
76 |
range.collapse(true);
|
77 |
range.moveEnd('character', pos);
|
78 |
range.moveStart('character', pos);
|
79 |
range.select(); |
80 |
} |
81 |
} |
82 |
|
83 |
// indexOf prototype for IE
|
84 |
if (!Array.prototype.indexOf) {
|
85 |
Array.prototype.indexOf = function(elt /*, from*/) { |
86 |
var len = this.length; |
87 |
var from = Number(arguments[1]) || 0; |
88 |
from = (from < 0)
|
89 |
? Math.ceil(from) |
90 |
: Math.floor(from); |
91 |
if (from < 0) |
92 |
from += len; |
93 |
|
94 |
for (; from < len; from++) {
|
95 |
if (from in this && |
96 |
this[from] === elt)
|
97 |
return from;
|
98 |
} |
99 |
return -1; |
100 |
}; |
101 |
} |
102 |
|
103 |
// trim prototype for IE
|
104 |
if(typeof String.prototype.trim !== 'function') { |
105 |
String.prototype.trim = function() { |
106 |
return this.replace(/^\s+|\s+$/g, ''); |
107 |
} |
108 |
} |
109 |
|
110 |
// simple string format helper (http://stackoverflow.com/questions/610406/javascript-equivalent-to-printf-string-format)
|
111 |
String.prototype.format = function() { |
112 |
var formatted = this; |
113 |
for (var i = 0; i < arguments.length; i++) { |
114 |
var regexp = new RegExp('\\{'+i+'\\}', 'gi'); |
115 |
formatted = formatted.replace(regexp, arguments[i]);
|
116 |
} |
117 |
return formatted;
|
118 |
}; |
119 |
|
120 |
|
121 |
// Show VNC console
|
122 |
function vnc_attachment(host, port, password) { |
123 |
// FIXME: Must be made into parameters, in settings.py
|
124 |
//vnc = open("", "displayWindow",
|
125 |
// "status=yes,toolbar=yes,menubar=yes");
|
126 |
vd = document.open("application/x-vnc");
|
127 |
|
128 |
vd.writeln("[connection]");
|
129 |
vd.writeln("host=" + host);
|
130 |
vd.writeln("port=" + port);
|
131 |
vd.writeln("password=" + password);
|
132 |
|
133 |
vd.close(); |
134 |
} |
135 |
|
136 |
// connect to machine action
|
137 |
function machine_connect(serverIDs){ |
138 |
return;
|
139 |
if (!serverIDs.length){
|
140 |
//ajax_success('DEFAULT');
|
141 |
return false; |
142 |
} |
143 |
|
144 |
// prefer metadata values for specific options (username, domain)
|
145 |
var username_meta_key = 'user'; |
146 |
var domain_meta_key = "domain"; |
147 |
|
148 |
var serverID = serverIDs.pop();
|
149 |
var machine = get_machine(serverID);
|
150 |
var serverName = machine.name;
|
151 |
|
152 |
try {
|
153 |
var serverIP = machine.addresses.values[0].values[0].addr; |
154 |
} catch (err) { var serverIP = 'undefined'; } |
155 |
|
156 |
try {
|
157 |
var os = os_icon(machine.metadata);
|
158 |
} catch (err) { var os = 'undefined'; } |
159 |
|
160 |
var username = ""; |
161 |
try {
|
162 |
username = machine.metadata.values[username_meta_key]; |
163 |
} catch (err) { username = undefined } |
164 |
|
165 |
var domain = ""; |
166 |
try {
|
167 |
domain = machine.metadata.values[domain_meta_key]; |
168 |
} catch (erro) { domain = undefined } |
169 |
|
170 |
var params_url = '?ip_address=' + serverIP + '&os=' + os + "&host_os=" + $.client.os + "&srv=" + serverID; |
171 |
|
172 |
if (username) {
|
173 |
params_url += "&username=" + username;
|
174 |
} |
175 |
|
176 |
if (domain) {
|
177 |
params_url += "&domain=" + domain;
|
178 |
} |
179 |
|
180 |
//if ($.client.os == "Windows" && os == "windows") {
|
181 |
//// request rdp file
|
182 |
//window.open('machines/connect' + params_url + "&rdp=1");
|
183 |
//return;
|
184 |
//}
|
185 |
|
186 |
// FIXME: I18n ???
|
187 |
var title = 'Connect to: ' + |
188 |
'<span class="machine-title"><img src="static/icons/machines/small/' + os +
|
189 |
'-on.png" /> ' + serverName +
|
190 |
'</span>';
|
191 |
|
192 |
// open msg box and fill it with json data retrieved from connect machine view
|
193 |
try {
|
194 |
// open msg box
|
195 |
msg_box({ |
196 |
title:title,
|
197 |
fixed: true, |
198 |
content:'loading...', |
199 |
extra:'', 'ajax':'machines/connect' + params_url, |
200 |
parse_data:function(data){ |
201 |
var box_content = "<a href='"+data.link.url+"'>"+data.link.title+"</a>"; |
202 |
if (!data.link.url) {
|
203 |
box_content = "<span class='cmd'>"+data.link.title+"</span>"; |
204 |
} |
205 |
data.title = false;
|
206 |
data.content = data.info; |
207 |
data.extra = box_content; |
208 |
return data;
|
209 |
} |
210 |
}); |
211 |
} catch (error) {
|
212 |
// if msg box fails fallback redirecting the user to the connect url
|
213 |
window.open('machines/connect' + params_url);
|
214 |
} |
215 |
|
216 |
|
217 |
// Restore os icon in list view
|
218 |
osIcon = $('#'+serverID).parent().parent().find('.list-logo'); |
219 |
osIcon.attr('src',osIcon.attr('os')); |
220 |
|
221 |
return false; |
222 |
} |
223 |
|
224 |
|
225 |
function msg_box(user_config) { |
226 |
var defaults = {'title':'Info message', 'content': 'this is an info message', 'ajax': false, 'extra':false}; |
227 |
var config = $.extend(defaults, user_config); |
228 |
|
229 |
// prepare the error message
|
230 |
// bring up success notification
|
231 |
var box = $("#notification-box"); |
232 |
box.addClass("notification-box");
|
233 |
box.addClass('success');
|
234 |
box.addClass(config.cls || '');
|
235 |
box.removeClass('error');
|
236 |
|
237 |
var sel = function(s){return $(s, box)}; |
238 |
// reset texts
|
239 |
sel("h3 span.header-box").html(""); |
240 |
sel(".sub-text").html(""); |
241 |
sel(".password-container .password").html(""); |
242 |
sel("div.machine-now-building").html(""); |
243 |
|
244 |
// apply msg box contents
|
245 |
sel("h3 span.header-box").html(config.title);
|
246 |
sel("div.machine-now-building").html(config.content);
|
247 |
sel(".sub-text").html(config.sub_content || ''); |
248 |
sel(".popup-header").removeClass("popup-header-error"); |
249 |
box.removeClass("popup-border-error");
|
250 |
sel(".popup-details").removeClass("popup-details-error"); |
251 |
sel(".popup-separator").removeClass("popup-separator-error"); |
252 |
|
253 |
sel(".password-container").hide();
|
254 |
if (config.extra) {
|
255 |
sel(".password-container .password").html(config.extra);
|
256 |
sel(".password-container").show();
|
257 |
} |
258 |
|
259 |
var conf = {
|
260 |
// some mask tweaks suitable for modal dialogs
|
261 |
mask: '#666', |
262 |
top: '10px', |
263 |
closeOnClick: false, |
264 |
oneInstance: false, |
265 |
load: false, |
266 |
onLoad: config.onLoad || false, |
267 |
fixed: config.fixed || false, |
268 |
onClose: function () { |
269 |
// With partial refresh working properly,
|
270 |
// it is no longer necessary to refresh the whole page
|
271 |
// choose_view();
|
272 |
} |
273 |
} |
274 |
|
275 |
var triggers = $("a#msgbox").overlay(conf); |
276 |
|
277 |
try {
|
278 |
conf = $("a#msgbox").data('overlay').getConf(); |
279 |
conf.fixed = config.fixed || false;
|
280 |
} catch (err) {}
|
281 |
$("a#msgbox").data('overlay').load(); |
282 |
|
283 |
var parse_data = config.parse_data || false; |
284 |
var load_html = config.html || false; |
285 |
var user_success = config.success || false; |
286 |
config.ajax = config.ajax || {}; |
287 |
|
288 |
// requested to show remote data in msg_box
|
289 |
if (config.ajax && !$.isEmptyObject(config.ajax)) { |
290 |
$.ajax($.extend({ |
291 |
url:config.ajax,
|
292 |
success: function(data){ |
293 |
// we want to get our data parsed before
|
294 |
// placing them in content
|
295 |
if (parse_data) {
|
296 |
data = parse_data(data); |
297 |
} |
298 |
|
299 |
// no json response
|
300 |
// load html body
|
301 |
if (load_html) {
|
302 |
sel("div.machine-now-building").html(data);
|
303 |
} else {
|
304 |
|
305 |
if (data.title) {
|
306 |
sel("h3 span.header-box").text(data.title);
|
307 |
} |
308 |
|
309 |
if (data.content) {
|
310 |
sel("div.machine-now-building").html(data.content);
|
311 |
} |
312 |
if (data.extra) {
|
313 |
sel(".password-container .password").html(data.extra);
|
314 |
sel(".password-container").show();
|
315 |
} |
316 |
if (data.subinfo) {
|
317 |
sel(".sub-text").html(data.subinfo);
|
318 |
} else {
|
319 |
sel(".sub-text").html(""); |
320 |
} |
321 |
} |
322 |
|
323 |
if (user_success) {
|
324 |
user_success($("div.machine-now-building")); |
325 |
} |
326 |
}, |
327 |
error: function(xhr, status, err) { |
328 |
ajax_error(-519, "UI Error", "Machine connect", err, this); |
329 |
} |
330 |
}, config.ajax_config)); |
331 |
} |
332 |
return false; |
333 |
} |
334 |
|
335 |
|
336 |
function show_api_overlay() { |
337 |
var config = {
|
338 |
title: window.API_OVERLAY_TITLE,
|
339 |
content: $(".api_overlay_content").html().replace("$api_key", $.cookie("X-Auth-Token")), |
340 |
extra: $.cookie("X-Auth-Token"), |
341 |
sub_content: window.API_OVERLAY_SUBCONTENT,
|
342 |
cls: "api_content", |
343 |
ajax: false |
344 |
} |
345 |
msg_box(config); |
346 |
} |
347 |
|
348 |
function show_invitations() { |
349 |
|
350 |
function display_resend_success(msg) { |
351 |
clear_resend_messages(); |
352 |
$("#invsent .message.success").text(msg).show(); |
353 |
} |
354 |
|
355 |
function display_resend_error(msg) { |
356 |
clear_resend_messages(); |
357 |
$("#invsent .message.errormsg").text(msg).show(); |
358 |
} |
359 |
|
360 |
// clear resent messages
|
361 |
function clear_resend_messages() { |
362 |
$("#invsent .message").hide(); |
363 |
} |
364 |
|
365 |
// register resent click handlers
|
366 |
function register_invitation_resends() { |
367 |
$(".invitations .resend-invitation").click(function() { |
368 |
var invid = $(this).attr("id"); |
369 |
|
370 |
if (invid == null) |
371 |
return;
|
372 |
|
373 |
var id = invid.split("-")[1]; |
374 |
|
375 |
if (id == null) |
376 |
return;
|
377 |
|
378 |
var child = $(this).find("img"); |
379 |
child.attr('src', '/static/progress-tiny.gif'); |
380 |
|
381 |
$.ajax({
|
382 |
type: "POST", |
383 |
url : "/invitations/resend", |
384 |
data : {invid : id}, |
385 |
success: function(msg) { |
386 |
display_resend_success("Invitation has been resent");
|
387 |
child.attr('src', '/static/resend.png'); |
388 |
}, |
389 |
error : function(xhr, status, error) { |
390 |
display_resend_error("Something seems to have gone wrong. " +
|
391 |
"Please try again in a few minutes.");
|
392 |
child.attr('src', '/static/resend.png'); |
393 |
} |
394 |
}); |
395 |
}); |
396 |
} |
397 |
|
398 |
handle_invitations = function(el) { |
399 |
|
400 |
// proper class to identify the overlay block
|
401 |
el.addClass("invitations");
|
402 |
|
403 |
var cont = el;
|
404 |
var form = $(el).find("form"); |
405 |
|
406 |
// remove garbage rows that stay in DOM between requests
|
407 |
$(".removable-field-row:hidden").remove(); |
408 |
|
409 |
// avoid buggy behaviour, close all overlays if something went wrong
|
410 |
try {
|
411 |
// form is in content (form is not displayed if user has no invitations)
|
412 |
if ($("#invform #removable-name-container-1").length) { |
413 |
$("#invform #removable-name-container-1").dynamicField(); |
414 |
} |
415 |
} catch (err) {
|
416 |
close_all_overlays(); |
417 |
} |
418 |
|
419 |
// we copy/paste it on the title no need to show it twice
|
420 |
$(".invitations-left").hide(); |
421 |
|
422 |
// sending finished or first invitations view
|
423 |
$(".invitations .sending").hide(); |
424 |
$(".invitations .submit").show(); |
425 |
$(".invitations #fieldheaders").show(); |
426 |
$(".invitations #fields").show(); |
427 |
|
428 |
// reset title
|
429 |
$("#notification-box .header-box").html(""); |
430 |
$("#notification-box .header-box").html(window.INVITATIONS_TITLE + " " + $($(".invitations-left")[0]).text()); |
431 |
|
432 |
// resend buttons
|
433 |
register_invitation_resends(); |
434 |
clear_resend_messages(); |
435 |
|
436 |
// handle form submit
|
437 |
form.submit(function(evn){
|
438 |
evn.preventDefault(); |
439 |
|
440 |
// sending...
|
441 |
$(".invitations .sending").show(); |
442 |
$(".invitations .submit").hide(); |
443 |
$(".invitations #fieldheaders").hide(); |
444 |
$(".invitations #fields").hide(); |
445 |
|
446 |
// do the post
|
447 |
$.post(form.attr("action"), form.serialize(), function(data) { |
448 |
// replace data
|
449 |
$(cont).html(data);
|
450 |
|
451 |
// append all handlers again (new html data need to redo all changes)
|
452 |
handle_invitations(cont); |
453 |
}); |
454 |
|
455 |
return false; |
456 |
}); |
457 |
} |
458 |
|
459 |
// first time clicked (show the msg box with /invitations content)
|
460 |
msg_box({ |
461 |
title:window.INVITATIONS_TITLE,
|
462 |
content:'', |
463 |
fixed: false, |
464 |
ajax:INVITATIONS_URL,
|
465 |
html:true, |
466 |
success: function(el){ |
467 |
handle_invitations(el) |
468 |
} |
469 |
}); |
470 |
} |
471 |
|
472 |
|
473 |
function get_short_v6(v6, parts_to_keep) { |
474 |
var parts = v6.split(":"); |
475 |
var new_parts = parts.slice(parts.length - parts_to_keep);
|
476 |
return new_parts.join(":"); |
477 |
} |
478 |
|
479 |
function fix_v6_addresses() { |
480 |
|
481 |
// what to prepend
|
482 |
var match = "..."; |
483 |
// long ip min length
|
484 |
var limit = 20; |
485 |
// parts to show after the transformation
|
486 |
// (from the end)
|
487 |
var parts_to_keep_from_end = 4; |
488 |
|
489 |
$(".machine .ipv6-text").each(function(index, el){ |
490 |
var el = $(el); |
491 |
var ip = $(el).text(); |
492 |
|
493 |
// transformation not applyied
|
494 |
// FIXME: use $.data for the condition
|
495 |
if (ip.indexOf(match) == -1 && ip != "pending") { |
496 |
|
497 |
// only too long ips
|
498 |
if (ip.length > 20) { |
499 |
$(el).data("ipstring", ip); |
500 |
$(el).text(match + get_short_v6(ip, parts_to_keep_from_end));
|
501 |
$(el).attr("title", ip); |
502 |
$(el).tooltip({'tipClass':'tooltip ipv6-tip', 'position': 'center center'}); |
503 |
} |
504 |
} else {
|
505 |
if (ip.indexOf(match) == 0) { |
506 |
} else {
|
507 |
// not a long ip anymore
|
508 |
$(el).data("ipstring", undefined); |
509 |
$(el).css({'text-decoration':'none'}); |
510 |
|
511 |
if ($(el).data('tooltip')) { |
512 |
$(el).data('tooltip').show = function () {}; |
513 |
} |
514 |
} |
515 |
} |
516 |
}); |
517 |
} |
518 |
|
519 |
// get stats
|
520 |
function get_server_stats(serverID) { |
521 |
|
522 |
// do not update stats if machine in build state
|
523 |
var vm = get_machine(serverID);
|
524 |
if (vm.status == "BUILD" && vm.stats_timeout) { |
525 |
els = get_current_view_stats_elements(vm.id); |
526 |
els.cpu.img.hide(); |
527 |
els.net.img.hide(); |
528 |
|
529 |
els.cpu.busy.show(); |
530 |
els.net.busy.show(); |
531 |
return;
|
532 |
} |
533 |
|
534 |
$.ajax({
|
535 |
repeated: true, |
536 |
url: API_URL + '/servers/' + serverID + '/stats', |
537 |
cache: false, |
538 |
type: "GET", |
539 |
//async: false,
|
540 |
dataType: "json", |
541 |
timeout: TIMEOUT,
|
542 |
error: function(jqXHR, textStatus, errorThrown) { |
543 |
handle_api_error(-21, undefined, 'Get server stats', jqXHR, textStatus, errorThrown, this); |
544 |
}, |
545 |
success: function(data, textStatus, jqXHR) { |
546 |
//update_machine_stats(serverID, data);
|
547 |
}, |
548 |
|
549 |
// pass server id to ajax settings
|
550 |
serverID: serverID
|
551 |
}); |
552 |
return false; |
553 |
} |
554 |
|
555 |
function get_progress_details(id) { |
556 |
var vm = get_machine(id);
|
557 |
var progress = vm.progress;
|
558 |
|
559 |
// no details for active machines
|
560 |
if (!vm.status == "BUILD") { |
561 |
return false; |
562 |
} |
563 |
|
564 |
// check if images not loaded yet
|
565 |
try {
|
566 |
var image = synnefo.storage.images.get(vm.imageRef).attributes;
|
567 |
var size = image.size;
|
568 |
} catch (err) {
|
569 |
// images not loaded yet (can this really happen ??)
|
570 |
return;
|
571 |
} |
572 |
|
573 |
var to_copy = size;
|
574 |
var copied = (size * progress / 100).toFixed(2); |
575 |
var status = "INIT" |
576 |
|
577 |
// apply state
|
578 |
if (progress > 0) { status = "IMAGE_COPY" } |
579 |
if (progress >= 100) { status = "FINISH" } |
580 |
|
581 |
// user information
|
582 |
var msg = BUILDING_MESSAGES[status];
|
583 |
|
584 |
// image copy state display extended user information
|
585 |
//if (status == "IMAGE_COPY") {
|
586 |
//msg = msg.format(readablizeBytes(copied*(1024*1024)), readablizeBytes(to_copy*(1024*1024)), progress)
|
587 |
//}
|
588 |
|
589 |
var progress_data = {
|
590 |
'percent': vm.progress,
|
591 |
'build_status': status,
|
592 |
'copied': copied,
|
593 |
'to_copy': size,
|
594 |
'msg': msg
|
595 |
} |
596 |
|
597 |
return progress_data;
|
598 |
} |
599 |
|
600 |
// display user friendly bytes amount
|
601 |
function readablizeBytes(bytes) { |
602 |
var s = ['bytes', 'kb', 'MB', 'GB', 'TB', 'PB']; |
603 |
var e = Math.floor(Math.log(bytes)/Math.log(1024)); |
604 |
return (bytes/Math.pow(1024, Math.floor(e))).toFixed(2)+" "+s[e]; |
605 |
} |
606 |
|
607 |
// machines images utils
|
608 |
function set_machine_os_image(machine, machines_view, state, os, skip_reset_states, remove_state) { |
609 |
var views_map = {'single': '.single-image', 'icon': '.logo'}; |
610 |
var states_map = {'on': 'state1', 'off': 'state3', 'hover': 'state4', 'click': 'state2'} |
611 |
var sizes_map = {'single': 'large', 'icon': 'medium'} |
612 |
|
613 |
var size = sizes_map[machines_view];
|
614 |
var img_selector = views_map[machines_view];
|
615 |
var cls = states_map[state];
|
616 |
|
617 |
if (os === "unknown") { os = "okeanos" } ; |
618 |
var new_img = 'url("./static/icons/machines/' + size + '/' + os + '-sprite.png")'; |
619 |
|
620 |
var el = $(img_selector, machine); |
621 |
var current_img = el.css("backgroundImage"); |
622 |
if (os == undefined){ |
623 |
new_img = current_img; |
624 |
} |
625 |
|
626 |
// os changed
|
627 |
el.css("backgroundImage", new_img);
|
628 |
|
629 |
// reset current state
|
630 |
if (skip_reset_states === undefined) |
631 |
{ |
632 |
el.removeClass("single-image-state1");
|
633 |
el.removeClass("single-image-state2");
|
634 |
el.removeClass("single-image-state3");
|
635 |
el.removeClass("single-image-state4");
|
636 |
} |
637 |
|
638 |
if (remove_state !== undefined) |
639 |
{ |
640 |
remove_state = "single-image-" + states_map[remove_state];
|
641 |
el.removeClass(remove_state); |
642 |
return;
|
643 |
} |
644 |
|
645 |
// set proper state
|
646 |
el.addClass("single-image-" + cls);
|
647 |
} |
648 |
|
649 |
// return machine entry from serverID
|
650 |
function get_machine(serverID) { |
651 |
return synnefo.storage.vms.get(serverID).attributes;
|
652 |
} |
653 |
|