mirror of
https://github.com/OpenNebula/one.git
synced 2025-03-26 06:50:09 +03:00
Feature #507: Started reorganizing code.
* sunstone.js will be the main interface to use by plugins. It will set up the layout on document ready(). It also contains the configuration now. * sunstone-util.js will contain util functions for the plugins and the datatable handling * plugins/* will contain the plugins
This commit is contained in:
parent
2bbf683909
commit
bd8b3b0c01
@ -21,25 +21,28 @@
|
||||
|
||||
var dataTable_hosts=null;
|
||||
//~ var dataTable_clusters=null;
|
||||
var dataTable_vMachines=null;
|
||||
var dataTable_vNetworks=null;
|
||||
var dataTable_users=null;
|
||||
var dataTable_images=null;
|
||||
var host_list_json = {};
|
||||
var cluster_list_json = {};
|
||||
var vmachine_list_json = {};
|
||||
var network_list_json = {};
|
||||
var user_list_json = {};
|
||||
var image_list_json = {};
|
||||
var hosts_select="";
|
||||
var clusters_select="";
|
||||
var vnetworks_select="";
|
||||
var images_select="";
|
||||
//~ var dataTable_vMachines=null;
|
||||
//~ var dataTable_vNetworks=null;
|
||||
//~ var dataTable_users=null;
|
||||
//~ var dataTable_images=null;
|
||||
//~ var host_list_json = {};
|
||||
//~ var cluster_list_json = {};
|
||||
//~ var vmachine_list_json = {};
|
||||
//~ var network_list_json = {};
|
||||
//~ var user_list_json = {};
|
||||
//~ var image_list_json = {};
|
||||
//~ var hosts_select="";
|
||||
//~ var clusters_select="";
|
||||
//~ var vnetworks_select="";
|
||||
//~ var images_select="";
|
||||
var cookie = {};
|
||||
var username = '';
|
||||
var uid = '';
|
||||
var spinner = '<img src="/images/ajax-loader.gif" alt="retrieving" class="loading_img"/>';
|
||||
|
||||
|
||||
|
||||
|
||||
/*######################################################################
|
||||
* DOCUMENT READY FUNCTIONS
|
||||
* ###################################################################*/
|
||||
@ -229,12 +232,12 @@ function initDataTables(){
|
||||
}
|
||||
|
||||
//Adds a listener to checks all the elements of a table
|
||||
function initCheckAllBoxes(){
|
||||
function initCheckAllBoxes(datatable){
|
||||
//not showing nice in that position
|
||||
//$('.check_all').button({ icons: {primary : "ui-icon-check" },
|
||||
// text : true});
|
||||
$('.check_all').css({"border":"2px"});
|
||||
$('.check_all').click(function(){
|
||||
$('.check_all',datatable).css({"border":"2px"});
|
||||
$('.check_all',datatable).click(function(){
|
||||
if ($(this).attr("checked")) {
|
||||
$('tbody input:checkbox',
|
||||
$(this).parents("table")).each(function(){
|
||||
@ -761,6 +764,9 @@ function actionButtonListener(){
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function preloadTables(){
|
||||
dataTable_hosts.fnClearTable();
|
||||
addElement([
|
||||
@ -2180,17 +2186,14 @@ function setupTips(){
|
||||
//Crawls the user dataTable for that. If such user is not found,
|
||||
//we return the uid.
|
||||
function getUserName(uid){
|
||||
nodes = dataTable_users.fnGetData();
|
||||
user = "uid "+uid;
|
||||
if (dataTable_users != null){
|
||||
nodes = dataTable_users.fnGetData();
|
||||
$.each(nodes,function(){
|
||||
if (uid == this[1]) {
|
||||
user = this[2];
|
||||
return false;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$.each(nodes,function(){
|
||||
if (uid == this[1]) {
|
||||
user = this[2];
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return user;
|
||||
|
||||
}
|
||||
@ -2556,13 +2559,13 @@ function emptyDashboard(){
|
||||
$("#dashboard .value_td span").html(spinner);
|
||||
}
|
||||
|
||||
function updateDashboard(what){
|
||||
function updateDashboard(what,json_info){
|
||||
db = $('#dashboard');
|
||||
switch (what){
|
||||
case "hosts":
|
||||
total_hosts=host_list_json.length;
|
||||
total_hosts=json_info.length;
|
||||
active_hosts=0;
|
||||
$.each(host_list_json,function(){
|
||||
$.each(json_info,function(){
|
||||
if (parseInt(this.HOST.STATE) < 3){
|
||||
active_hosts++;}
|
||||
});
|
||||
@ -2570,14 +2573,14 @@ function updateDashboard(what){
|
||||
$('#active_hosts',db).html(active_hosts);
|
||||
break;
|
||||
case "clusters":
|
||||
total_clusters=cluster_list_json.length;
|
||||
total_clusters=json_info.length;
|
||||
$('#total_clusters',db).html(total_clusters);
|
||||
break;
|
||||
case "vms":
|
||||
total_vms=vmachine_list_json.length;
|
||||
total_vms=json_info.length;
|
||||
running_vms=0;
|
||||
failed_vms=0;
|
||||
$.each(vmachine_list_json,function(){
|
||||
$.each(json_info,function(){
|
||||
vm_state = parseInt(this.VM.STATE);
|
||||
if (vm_state == 3){
|
||||
running_vms++;
|
||||
@ -2592,8 +2595,8 @@ function updateDashboard(what){
|
||||
break;
|
||||
case "vnets":
|
||||
public_vnets=0;
|
||||
total_vnets=network_list_json.length;
|
||||
$.each(network_list_json,function(){
|
||||
total_vnets=json_info.length;
|
||||
$.each(json_info,function(){
|
||||
if (parseInt(this.VNET.PUBLIC)){
|
||||
public_vnets++;}
|
||||
});
|
||||
@ -2601,13 +2604,13 @@ function updateDashboard(what){
|
||||
$('#public_vnets',db).html(public_vnets);
|
||||
break;
|
||||
case "users":
|
||||
total_users=user_list_json.length;
|
||||
total_users=json_info.length;
|
||||
$('#total_users',db).html(total_users);
|
||||
break;
|
||||
case "images":
|
||||
total_images=image_list_json.length;
|
||||
total_images=json_info.length;
|
||||
public_images=0;
|
||||
$.each(image_list_json,function(){
|
||||
$.each(json_info,function(){
|
||||
if (parseInt(this.IMAGE.PUBLIC)){
|
||||
public_images++;}
|
||||
});
|
||||
|
444
src/sunstone/public/js/plugins/hosts-tab.js
Normal file
444
src/sunstone/public/js/plugins/hosts-tab.js
Normal file
@ -0,0 +1,444 @@
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org) */
|
||||
/* */
|
||||
/* 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. */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/*Host tab plugin*/
|
||||
|
||||
var host_tab_content =
|
||||
'<form id="form_hosts" action="javascript:alert(\'js errors?!\')">\
|
||||
<div class="action_blocks">\
|
||||
</div>\
|
||||
<table id="datatable_hosts" class="display">\
|
||||
<thead>\
|
||||
<tr>\
|
||||
<th class="check"><input type="checkbox" class="check_all" value="">All</input></th>\
|
||||
<th>ID</th>\
|
||||
<th>Name</th>\
|
||||
<th>Cluster</th>\
|
||||
<th>Running VMs</th>\
|
||||
<th>CPU Use</th>\
|
||||
<th>Memory use</th>\
|
||||
<th>Status</th>\
|
||||
</tr>\
|
||||
</thead>\
|
||||
<tbody id="tbodyhosts">\
|
||||
</tbody>\
|
||||
</table>\
|
||||
</form>';
|
||||
|
||||
var hosts_select="";
|
||||
var host_list_json = {};
|
||||
|
||||
|
||||
//Setup actions
|
||||
var host_actions = {
|
||||
"Host.create" : {
|
||||
type: "create",
|
||||
call : OpenNebula.Host.create,
|
||||
callback = addHostElement,
|
||||
error : onError,
|
||||
notify:true,
|
||||
condition: true
|
||||
},
|
||||
|
||||
"Host.enable" = {
|
||||
type: "multiple",
|
||||
call : OpenNebula.Host.enable,
|
||||
callback = host_update_callback,
|
||||
error : onError,
|
||||
notify:true,
|
||||
condition:true
|
||||
},
|
||||
|
||||
"Host.disable" = {
|
||||
type: "multiple",
|
||||
call : OpenNebula.Host.disable,
|
||||
callback = host_update_callback,
|
||||
error : onError,
|
||||
notify:true,
|
||||
condition:true
|
||||
},
|
||||
|
||||
"Host.delete" = {
|
||||
type: "multiple",
|
||||
call : OpenNebula.Host.create,
|
||||
callback = deleteHostElement,
|
||||
error : onError,
|
||||
notify:true,
|
||||
condition:true
|
||||
},
|
||||
|
||||
"Host.list" = {
|
||||
type: "custom",
|
||||
call : function() {
|
||||
OpenNebula.Host.list({success: updateHostsView, error: onError});
|
||||
OpenNebula.Cluster.list({success: updateClustersView, error: onError});
|
||||
}
|
||||
callback: null,
|
||||
error: onError,
|
||||
notify:true,
|
||||
condition:true
|
||||
},
|
||||
|
||||
"Cluster.create" = {
|
||||
type: "create",
|
||||
call : OpenNebula.Cluster.create,
|
||||
callback = addClusterElement
|
||||
error : onError,
|
||||
notify:true,
|
||||
condition : true
|
||||
},
|
||||
|
||||
"Cluster.delete" = {
|
||||
type: "multiple",
|
||||
call : OpenNebula.Host.create,
|
||||
callback = addHostElement,
|
||||
error : onError,
|
||||
notify:true,
|
||||
condition:true
|
||||
},
|
||||
|
||||
"Cluster.addhost" = {
|
||||
type: "confirm_with_select",
|
||||
select: cluster_select,
|
||||
tip: "Select the cluster in which you would like to place the hosts",
|
||||
call : OpenNebula.Cluster.addhost,
|
||||
callback = updateHostElement,
|
||||
error : onError,
|
||||
notify:true,
|
||||
condition : true
|
||||
},
|
||||
|
||||
"Cluster.removehost" = {
|
||||
type: "multiple",
|
||||
call : OpenNebula.Cluster.removehost,
|
||||
callback = deleteHostElement,
|
||||
error : onError,
|
||||
notify:true,
|
||||
condition:true
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var host_buttons = [
|
||||
{
|
||||
type: "create",
|
||||
text: "+ New host",
|
||||
action: "Host.create",
|
||||
condition : true
|
||||
},
|
||||
{
|
||||
type: "action",
|
||||
text: "Enable",
|
||||
action: "Host.enable",
|
||||
condition : true
|
||||
},
|
||||
{
|
||||
type: "action",
|
||||
text: "Disable",
|
||||
action: "Host.disable",
|
||||
condition : true
|
||||
},
|
||||
{
|
||||
type: "create",
|
||||
text: "+ New Cluster",
|
||||
action: "Cluster.create",
|
||||
condition : true
|
||||
},
|
||||
{
|
||||
type: "action",
|
||||
text: "Delete cluster",
|
||||
action: "Cluster.delete",
|
||||
condition : true
|
||||
}
|
||||
{
|
||||
type: "select",
|
||||
action: [{ text: "Add host to cluster",
|
||||
value: "Cluster.addhost",
|
||||
condition: true},
|
||||
{ text: "Remove host from cluster",
|
||||
value: "Cluster.removehost",
|
||||
condition: true}],
|
||||
condition : true
|
||||
},
|
||||
{
|
||||
type: "action",
|
||||
text: "Delete host",
|
||||
value: "Host.delete",
|
||||
condition : true
|
||||
}]};
|
||||
|
||||
for (action in host_actions){
|
||||
Sunstone.addAction(action,host_actions[action]);
|
||||
}
|
||||
|
||||
Sunstone.addMainTab(hosts_tab_content,'hosts_tab');
|
||||
|
||||
$.each(host_buttons,function(){
|
||||
Sunstone.addButton(this,'#hosts_tab');
|
||||
}
|
||||
|
||||
|
||||
//Setup tab
|
||||
|
||||
|
||||
//Plugin functions
|
||||
function host_update_callback(req){
|
||||
OpenNebula.Host.show({data:{id:req.request.data[0]},success: updateHostElement,error: onError});
|
||||
}
|
||||
|
||||
function hostElementArray(host_json){
|
||||
host = host_json.HOST;
|
||||
acpu = parseInt(host.HOST_SHARE.MAX_CPU);
|
||||
if (!acpu) {acpu=100};
|
||||
acpu = acpu - parseInt(host.HOST_SHARE.CPU_USAGE);
|
||||
|
||||
total_mem = parseInt(host.HOST_SHARE.MAX_MEM);
|
||||
free_mem = parseInt(host.HOST_SHARE.FREE_MEM);
|
||||
|
||||
if (total_mem == 0) {
|
||||
ratio_mem = 0;
|
||||
} else {
|
||||
ratio_mem = Math.round(((total_mem - free_mem) / total_mem) * 100);
|
||||
}
|
||||
|
||||
|
||||
total_cpu = parseInt(host.HOST_SHARE.MAX_CPU);
|
||||
used_cpu = Math.max(total_cpu - parseInt(host.HOST_SHARE.USED_CPU),acpu);
|
||||
|
||||
if (total_cpu == 0) {
|
||||
ratio_cpu = 0;
|
||||
} else {
|
||||
ratio_cpu = Math.round(((total_cpu - used_cpu) / total_cpu) * 100);
|
||||
}
|
||||
|
||||
pb_mem =
|
||||
'<div style="height:10px" class="ratiobar ui-progressbar ui-widget ui-widget-content ui-corner-all" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="'+ratio_mem+'">\
|
||||
<div class="ui-progressbar-value ui-widget-header ui-corner-left ui-corner-right" style="width: '+ratio_mem+'%;"/>\
|
||||
<span style="position:relative;left:45px;top:-4px;font-size:0.6em">'+ratio_mem+'%</span>\
|
||||
</div>\
|
||||
</div>';
|
||||
|
||||
pb_cpu =
|
||||
'<div style="height:10px" class="ratiobar ui-progressbar ui-widget ui-widget-content ui-corner-all" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="'+ratio_cpu+'">\
|
||||
<div class="ui-progressbar-value ui-widget-header ui-corner-left ui-corner-right" style="width: '+ratio_cpu+'%;"/>\
|
||||
<span style="position:relative;left:45px;top:-4px;font-size:0.6em">'+ratio_cpu+'%</span>\
|
||||
</div>\
|
||||
</div>';
|
||||
|
||||
|
||||
return [ '<input type="checkbox" id="host_'+host.ID+'" name="selected_items" value="'+host.ID+'"/>',
|
||||
host.ID,
|
||||
host.NAME,
|
||||
host.CLUSTER,
|
||||
host.HOST_SHARE.RUNNING_VMS, //rvm
|
||||
pb_cpu,
|
||||
pb_mem,
|
||||
OpenNebula.Helper.resource_state("host",host.STATE) ];
|
||||
|
||||
|
||||
//~ return [ '<input type="checkbox" id="host_'+host.ID+'" name="selected_items" value="'+host.ID+'"/>',
|
||||
//~ host.ID,
|
||||
//~ host.NAME,
|
||||
//~ host.CLUSTER,
|
||||
//~ host.HOST_SHARE.RUNNING_VMS, //rvm
|
||||
//~ host.HOST_SHARE.MAX_CPU, //tcpu
|
||||
//~ parseInt(host.HOST_SHARE.MAX_CPU) - parseInt(host.HOST_SHARE.USED_CPU), //fcpu
|
||||
//~ acpu,
|
||||
//~ humanize_size(host.HOST_SHARE.MAX_MEM),
|
||||
//~ humanize_size(host.HOST_SHARE.FREE_MEM),
|
||||
//~ OpenNebula.Helper.resource_state("host",host.STATE) ];
|
||||
}
|
||||
|
||||
|
||||
function hostInfoListener(){
|
||||
$('#tbodyhosts tr').live("click",function(e){
|
||||
|
||||
//do nothing if we are clicking a checkbox!
|
||||
if ($(e.target).is('input')) {return true;}
|
||||
|
||||
popDialogLoading();
|
||||
aData = dataTable_hosts.fnGetData(this);
|
||||
id = $(aData[0]).val();
|
||||
OpenNebula.Host.show({data:{id:id},success: updateHostInfo,error: onError});
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
function updateHostSelect(host_list){
|
||||
|
||||
//update select helper
|
||||
hosts_select="";
|
||||
hosts_select += "<option value=\"\">Select a Host</option>";
|
||||
$.each(host_list, function(){
|
||||
hosts_select += "<option value=\""+this.HOST.ID+"\">"+this.HOST.NAME+"</option>";
|
||||
});
|
||||
|
||||
//update static selectors
|
||||
$('#vm_host').html(hosts_select);
|
||||
}
|
||||
|
||||
|
||||
function updateHostElement(request, host_json){
|
||||
id = host_json.HOST.ID;
|
||||
element = hostElementArray(host_json);
|
||||
updateSingleElement(element,dataTable_hosts,'#host_'+id);
|
||||
}
|
||||
|
||||
function deleteHostElement(req){
|
||||
deleteElement(dataTable_hosts,'#host_'+req.request.data);
|
||||
}
|
||||
|
||||
function addHostElement(request,host_json){
|
||||
id = host_json.HOST.ID;
|
||||
element = hostElementArray(host_json);
|
||||
addElement(element,dataTable_hosts);
|
||||
}
|
||||
|
||||
function updateHostsView (request,host_list){
|
||||
host_list_json = host_list;
|
||||
host_list_array = []
|
||||
|
||||
$.each(host_list,function(){
|
||||
//Grab table data from the host_list
|
||||
host_list_array.push(hostElementArray(this));
|
||||
});
|
||||
|
||||
updateView(host_list_array,dataTable_hosts);
|
||||
updateHostSelect(host_list);
|
||||
updateDashboard("hosts",host_list_json);
|
||||
}
|
||||
|
||||
function updateHostInfo(request,host){
|
||||
host_info = host.HOST
|
||||
rendered_info =
|
||||
'<div id="host_informations">\
|
||||
<ul>\
|
||||
<li><a href="#info_host">Host information</a></li>\
|
||||
<li><a href="#host_template">Host template</a></li>\
|
||||
</ul>\
|
||||
<div id="info_host">\
|
||||
<table id="info_host_table" class="info_table">\
|
||||
<thead>\
|
||||
<tr><th colspan="2">Host information - '+host_info.NAME+'</th></tr>\
|
||||
</thead>\
|
||||
<tr>\
|
||||
<td class="key_td">ID</td>\
|
||||
<td class="value_td">'+host_info.ID+'</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td class="key_td">State</td>\
|
||||
<td class="value_td">'+OpenNebula.Helper.resource_state("host",host_info.STATE)+'</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td class="key_td">Cluster</td>\
|
||||
<td class="value_td">'+host_info.CLUSTER+'</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td class="key_td">IM MAD</td>\
|
||||
<td class="value_td">'+host_info.IM_MAD+'</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td class="key_td">VM MAD</td>\
|
||||
<td class="value_td">'+host_info.VM_MAD+'</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td class="key_td">TM MAD</td>\
|
||||
<td class="value_td">'+host_info.TM_MAD+'</td>\
|
||||
</tr>\
|
||||
</table>\
|
||||
<table id="host_shares_table" class="info_table">\
|
||||
<thead>\
|
||||
<tr><th colspan="2">Host shares</th></tr>\
|
||||
</thead>\
|
||||
<tr>\
|
||||
<td class="key_td">Max Mem</td>\
|
||||
<td class="value_td">'+humanize_size(host_info.HOST_SHARE.MAX_MEM)+'</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td class="key_td">Used Mem (real)</td>\
|
||||
<td class="value_td">'+humanize_size(host_info.HOST_SHARE.USED_MEM)+'</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td class="key_td">Used Mem (allocated)</td>\
|
||||
<td class="value_td">'+humanize_size(host_info.HOST_SHARE.MAX_USAGE)+'</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td class="key_td">Used CPU (real)</td>\
|
||||
<td class="value_td">'+host_info.HOST_SHARE.USED_CPU+'</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td class="key_td">Used CPU(allocated)</td>\
|
||||
<td class="value_td">'+host_info.HOST_SHARE.CPU_USAGE+'</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td class="key_td">Running VMs</td>\
|
||||
<td class="value_td">'+host_info.HOST_SHARE.RUNNING_VMS+'</td>\
|
||||
</tr>\
|
||||
</table>\
|
||||
</div>\
|
||||
<div id="host_template">\
|
||||
<table id="host_template_table" class="info_table">\
|
||||
<thead><tr><th colspan="2">Host template</th></tr></thead>'+
|
||||
prettyPrintJSON(host_info.TEMPLATE)+
|
||||
'</table>\
|
||||
</div>\
|
||||
</div>';
|
||||
popDialog(rendered_info);
|
||||
$('#host_informations').tabs();
|
||||
|
||||
}
|
||||
|
||||
//Document ready
|
||||
$(document).ready(){
|
||||
|
||||
//prepare host datatable
|
||||
var dataTable_hosts = $("#datatable_hosts").dataTable({
|
||||
"bJQueryUI": true,
|
||||
"bSortClasses": false,
|
||||
"bAutoWidth":false,
|
||||
"sPaginationType": "full_numbers",
|
||||
"aoColumnDefs": [
|
||||
{ "bSortable": false, "aTargets": ["check"] },
|
||||
{ "sWidth": "60px", "aTargets": [0,4] },
|
||||
{ "sWidth": "35px", "aTargets": [1] },
|
||||
{ "sWidth": "120px", "aTargets": [5,6] }
|
||||
]
|
||||
});
|
||||
|
||||
//preload it
|
||||
dataTable_hosts.fnClearTable();
|
||||
addElement([
|
||||
spinner,
|
||||
'','','','','','',''],dataTable_hosts);
|
||||
OpenNebula.Host.list({success: updateHostsView,error: onError});
|
||||
|
||||
//set refresh interval
|
||||
setInterval(function(){
|
||||
nodes = $('input:checked',dataTable_hosts.fnGetNodes());
|
||||
filter = $("#datatable_hosts_filter input").attr("value");
|
||||
if (!nodes.length && !filter.length){
|
||||
OpenNebula.Host.list({timeout: true, success: updateHostsView,error: onError});
|
||||
}
|
||||
},interval);
|
||||
|
||||
initCheckAllBoxes(dataTable_hosts);
|
||||
|
||||
//.action button listener
|
||||
$('#hosts_tab .action_button').click(function(){
|
||||
Sunstone.runActionOnDatatableNodes($(this).val(),dataTable_hosts);
|
||||
}
|
||||
|
||||
}
|
260
src/sunstone/public/js/sunstone-util.js
Normal file
260
src/sunstone/public/js/sunstone-util.js
Normal file
@ -0,0 +1,260 @@
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org) */
|
||||
/* */
|
||||
/* 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. */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
/* Some useful functions for Sunstone default plugins */
|
||||
|
||||
function emptyDashboard(){
|
||||
$("#dashboard .value_td span").html(spinner);
|
||||
}
|
||||
|
||||
function updateDashboard(what,json_info){
|
||||
db = $('#dashboard');
|
||||
switch (what){
|
||||
case "hosts":
|
||||
total_hosts=json_info.length;
|
||||
active_hosts=0;
|
||||
$.each(json_info,function(){
|
||||
if (parseInt(this.HOST.STATE) < 3){
|
||||
active_hosts++;}
|
||||
});
|
||||
$('#total_hosts',db).html(total_hosts);
|
||||
$('#active_hosts',db).html(active_hosts);
|
||||
break;
|
||||
case "clusters":
|
||||
total_clusters=json_info.length;
|
||||
$('#total_clusters',db).html(total_clusters);
|
||||
break;
|
||||
case "vms":
|
||||
total_vms=json_info.length;
|
||||
running_vms=0;
|
||||
failed_vms=0;
|
||||
$.each(json_info,function(){
|
||||
vm_state = parseInt(this.VM.STATE);
|
||||
if (vm_state == 3){
|
||||
running_vms++;
|
||||
}
|
||||
else if (vm_state == 7) {
|
||||
failed_vms++;
|
||||
}
|
||||
});
|
||||
$('#total_vms',db).html(total_vms);
|
||||
$('#running_vms',db).html(running_vms);
|
||||
$('#failed_vms',db).html(failed_vms);
|
||||
break;
|
||||
case "vnets":
|
||||
public_vnets=0;
|
||||
total_vnets=json_info.length;
|
||||
$.each(json_info,function(){
|
||||
if (parseInt(this.VNET.PUBLIC)){
|
||||
public_vnets++;}
|
||||
});
|
||||
$('#total_vnets',db).html(total_vnets);
|
||||
$('#public_vnets',db).html(public_vnets);
|
||||
break;
|
||||
case "users":
|
||||
total_users=json_info.length;
|
||||
$('#total_users',db).html(total_users);
|
||||
break;
|
||||
case "images":
|
||||
total_images=json_info.length;
|
||||
public_images=0;
|
||||
$.each(json_info,function(){
|
||||
if (parseInt(this.IMAGE.PUBLIC)){
|
||||
public_images++;}
|
||||
});
|
||||
$('#total_images',db).html(total_images);
|
||||
$('#public_images',db).html(public_images);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function pad(number,length) {
|
||||
var str = '' + number;
|
||||
while (str.length < length)
|
||||
str = '0' + str;
|
||||
return str;
|
||||
}
|
||||
|
||||
function pretty_time(time_seconds)
|
||||
{
|
||||
var d = new Date();
|
||||
d.setTime(time_seconds*1000);
|
||||
|
||||
var secs = pad(d.getSeconds(),2);
|
||||
var hour = pad(d.getHours(),2);
|
||||
var mins = pad(d.getMinutes(),2);
|
||||
var day = pad(d.getDate(),2);
|
||||
var month = pad(d.getMonth(),2);
|
||||
var year = d.getFullYear();
|
||||
|
||||
return hour + ":" + mins +":" + secs + " " + month + "/" + day + "/" + year;
|
||||
}
|
||||
|
||||
function humanize_size(value) {
|
||||
if (typeof(value) === "undefined") {
|
||||
value = 0;
|
||||
}
|
||||
var binarySufix = ["K", "M", "G", "T" ];
|
||||
var i=0;
|
||||
while (value > 1024 && i < 3){
|
||||
value = value / 1024;
|
||||
i++;
|
||||
}
|
||||
value = Math.round(value * 10) / 10;
|
||||
|
||||
if (value - Math.round(value) == 0) {
|
||||
value = Math.round(value);
|
||||
}
|
||||
|
||||
var st = value + binarySufix[i];
|
||||
return st;
|
||||
}
|
||||
|
||||
function deleteElement(data_table,tag){
|
||||
tr = $(tag).parents('tr')[0];
|
||||
data_table.fnDeleteRow(tr);
|
||||
$('input',data_table).trigger("change");
|
||||
}
|
||||
|
||||
function tableCheckboxesListener(dataTable){
|
||||
|
||||
context = dataTable.parents('form');
|
||||
last_action_b = $('.last_action_button',context);
|
||||
$('.top_button, .list_button',context).button("disable");
|
||||
if (last_action_b.length && last_action_b.val().length){
|
||||
last_action_b.button("disable");
|
||||
};
|
||||
$('.new_button',context).button("enable");
|
||||
|
||||
//listen to changes
|
||||
$('input',dataTable).live("change",function(){
|
||||
dataTable = $(this).parents('table').dataTable();
|
||||
context = dataTable.parents('form');
|
||||
last_action_b = $('.last_action_button',context);
|
||||
nodes = dataTable.fnGetNodes();
|
||||
total_length = nodes.length;
|
||||
checked_length = $('input:checked',nodes).length;
|
||||
|
||||
if (total_length == checked_length){
|
||||
$('.check_all',dataTable).attr("checked","checked");
|
||||
} else {
|
||||
$('.check_all',dataTable).removeAttr("checked");
|
||||
}
|
||||
|
||||
if (checked_length){
|
||||
$('.top_button, .list_button',context).button("enable");
|
||||
if (last_action_b.length && last_action_b.val().length){
|
||||
last_action_b.button("enable");
|
||||
};
|
||||
$('.new_button',context).button("enable");
|
||||
} else {
|
||||
$('.top_button, .list_button',context).button("disable");
|
||||
last_action_b.button("disable");
|
||||
$('.new_button',context).button("enable");
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// Updates a data_table, with a 2D array containing
|
||||
// Does a partial redraw, so the filter and pagination are kept
|
||||
function updateView(item_list,data_table){
|
||||
if (data_table!=null) {
|
||||
data_table.fnClearTable();
|
||||
data_table.fnAddData(item_list);
|
||||
data_table.fnDraw(false);
|
||||
};
|
||||
}
|
||||
|
||||
function updateSingleElement(element,data_table,tag){
|
||||
tr = $(tag).parents('tr')[0];
|
||||
position = data_table.fnGetPosition(tr);
|
||||
data_table.fnUpdate(element,position,0);
|
||||
$('input',data_table).trigger("change");
|
||||
|
||||
}
|
||||
|
||||
// Returns an string in the form key=value key=value ...
|
||||
// Does not explore objects in depth.
|
||||
function stringJSON(json){
|
||||
str = ""
|
||||
for (field in json) {
|
||||
str+= field + '=' + json[field] + ' ';
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
// Returns the running time data
|
||||
function str_start_time(vm){
|
||||
return pretty_time(vm.STIME);
|
||||
}
|
||||
|
||||
|
||||
//Notifications
|
||||
function notifySubmit(action, args, extra_param){
|
||||
var action_text = action.replace(/OpenNebula\./,'').replace(/\./,' ');
|
||||
|
||||
var msg = "<h1>Submitted</h1>";
|
||||
msg += action_text + ": " + args;
|
||||
if (extra_param != null)
|
||||
msg += " >> " + extra_param;
|
||||
|
||||
$.jGrowl(msg, {theme: "jGrowl-notify-submit"});
|
||||
}
|
||||
|
||||
function notifyError(msg){
|
||||
msg = "<h1>Error</h1>" + msg;
|
||||
|
||||
$.jGrowl(msg, {theme: "jGrowl-notify-error", sticky: true });
|
||||
}
|
||||
|
||||
// Returns an HTML string with the json keys and values in the form
|
||||
// key: value<br />
|
||||
// It recursively explores objects, and flattens their contents in
|
||||
// the result.
|
||||
function prettyPrintJSON(template_json){
|
||||
str = ""
|
||||
for (field in template_json) {
|
||||
if (typeof template_json[field] == 'object'){
|
||||
str += prettyPrintJSON(template_json[field]) + '<tr><td></td><td></td></tr>';
|
||||
} else {
|
||||
str += '<tr><td class="key_td">'+field+'</td><td class="value_td">'+template_json[field]+'</td></tr>';
|
||||
};
|
||||
};
|
||||
return str;
|
||||
}
|
||||
|
||||
//Adds a listener to checks all the elements of a table
|
||||
function initCheckAllBoxes(datatable){
|
||||
//not showing nice in that position
|
||||
//$('.check_all').button({ icons: {primary : "ui-icon-check" },
|
||||
// text : true});
|
||||
$('.check_all',datatable).css({"border":"2px"});
|
||||
$('.check_all',datatable).click(function(){
|
||||
if ($(this).attr("checked")) {
|
||||
$('tbody input:checkbox',
|
||||
$(this).parents("table")).each(function(){
|
||||
$(this).attr("checked","checked");
|
||||
});
|
||||
|
||||
} else {
|
||||
$('tbody input:checkbox',
|
||||
$(this).parents("table")).each(function(){
|
||||
$(this).removeAttr("checked");
|
||||
}); }
|
||||
});
|
||||
}
|
472
src/sunstone/public/js/sunstone.js
Normal file
472
src/sunstone/public/js/sunstone.js
Normal file
@ -0,0 +1,472 @@
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org) */
|
||||
/* */
|
||||
/* 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. */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
//TODOs: handle confirm and confirm with select dialogs
|
||||
|
||||
var cookie = {};
|
||||
var username = '';
|
||||
var uid = '';
|
||||
var spinner = '<img src="/images/ajax-loader.gif" alt="retrieving" class="loading_img"/>';
|
||||
|
||||
|
||||
var Sunstone = {
|
||||
|
||||
|
||||
"addAction" : function (name,action_obj) {
|
||||
SunstoneCfg.config.actions[name] = action_obj;
|
||||
},
|
||||
|
||||
"updateAction" : function(action,new_action) {
|
||||
|
||||
},
|
||||
|
||||
"removeAction" : function(action) {
|
||||
|
||||
},
|
||||
|
||||
"addMainTab" : function(tab_id,title_arg,content_arg) {
|
||||
SunstoneCfg["tabs"][tab_id] = {title: title_arg,
|
||||
content: content_arg};
|
||||
},
|
||||
|
||||
"updateMainTab" : function(tab_id,new_content){
|
||||
|
||||
},
|
||||
|
||||
"removeMainTab" : function(tab_id) {
|
||||
|
||||
},
|
||||
|
||||
"runAction" : function(action, data_arg, extra_param){
|
||||
|
||||
var actions = Sunstone.actions;
|
||||
if (!actions[action]){
|
||||
notifyError("Action "+action+" not defined");
|
||||
return;
|
||||
}
|
||||
|
||||
var action_cfg = actions[action];
|
||||
|
||||
var call = action_cfg.run;
|
||||
var callback = action_cfg.callback;
|
||||
var err = action_cfg.callback;
|
||||
var notify = action_cfg.notify;
|
||||
|
||||
|
||||
//We ease the use of:
|
||||
// * Create call
|
||||
// * Confirm and confirm with select calls
|
||||
// * Calls on multiple elements
|
||||
// * Other calls
|
||||
switch (actions[action].type){
|
||||
|
||||
case "create","single":
|
||||
call({data:data_arg, success: callback,error:err});
|
||||
break;
|
||||
case "confirm":
|
||||
tip = actions.tip;
|
||||
//popup confirm dialog (action,tip).
|
||||
break;
|
||||
case "confirm_with_select":
|
||||
tip = OpenNebula.Views.Actions[action].tip;
|
||||
select = OpenNebula.Views.Actions[action].select;
|
||||
//popup confirm dialog with select(action,tip,select)
|
||||
break;
|
||||
case "list":
|
||||
call({success: callback, error:err});
|
||||
break;
|
||||
case "multiple":
|
||||
//run on the list of nodes that come on the data
|
||||
$.each(data_arg,function(){
|
||||
if (extra_param){
|
||||
call(this,callback,error)
|
||||
} else {
|
||||
call(this,extra_param,callback,error)
|
||||
}
|
||||
});
|
||||
break;
|
||||
default:
|
||||
//we have supposedly altered an action and we want it to do
|
||||
//something completely different
|
||||
call(data,extra_param);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
"runActionOnDatatableNodes": function(action,datatable){
|
||||
if (dataTable != null){
|
||||
|
||||
//Which rows of the datatable are checked?
|
||||
var nodes = $('input:checked',dataTable.fnGetNodes());
|
||||
var data = [];
|
||||
$.each(nodes,function(){
|
||||
data.push($(this).val());
|
||||
}
|
||||
runAction(action,data);
|
||||
|
||||
} else {
|
||||
notifyError("Unknown datatable");
|
||||
};
|
||||
}//meter coma y seguir aquí
|
||||
|
||||
}
|
||||
|
||||
var SunstoneCfg = {
|
||||
"config" = {
|
||||
|
||||
"actions" : {
|
||||
|
||||
"VM.create" = {
|
||||
|
||||
},
|
||||
|
||||
"VM.deploy" = {
|
||||
|
||||
},
|
||||
|
||||
"VM.migrate" = {
|
||||
|
||||
},
|
||||
|
||||
"VM.livemigrate" = {
|
||||
|
||||
},
|
||||
|
||||
"VM.hold" = {
|
||||
|
||||
},
|
||||
|
||||
"VM.release" = {
|
||||
|
||||
},
|
||||
|
||||
"VM.suspend" = {
|
||||
|
||||
},
|
||||
|
||||
"VM.resume" = {
|
||||
|
||||
},
|
||||
|
||||
"VM.stop" = {
|
||||
|
||||
},
|
||||
|
||||
"VM.restart" = {
|
||||
|
||||
},
|
||||
|
||||
"VM.shutdown" = {
|
||||
|
||||
},
|
||||
|
||||
"VM.cancel" = {
|
||||
|
||||
},
|
||||
|
||||
"VM.delete" = {
|
||||
|
||||
},
|
||||
|
||||
"Network.publish" = {
|
||||
|
||||
},
|
||||
|
||||
"Network.unpublish" = {
|
||||
|
||||
},
|
||||
|
||||
"Network.delete" = {
|
||||
|
||||
},
|
||||
|
||||
"User.create" = {
|
||||
|
||||
},
|
||||
|
||||
"User.delete" = {
|
||||
|
||||
},
|
||||
|
||||
"Image.enable" = {
|
||||
|
||||
},
|
||||
|
||||
"Image.disable" = {
|
||||
|
||||
},
|
||||
|
||||
"Image.persistent" = {
|
||||
|
||||
},
|
||||
|
||||
"Image.nonpersistent" = {
|
||||
|
||||
},
|
||||
|
||||
"Image.publish" = {
|
||||
|
||||
},
|
||||
|
||||
"Image.unpublish" = {
|
||||
|
||||
},
|
||||
|
||||
"Image.delete" = {
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
"tabs" = {
|
||||
|
||||
},
|
||||
|
||||
"info_panels" = {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//plugins have done their jobs when we execute this
|
||||
$(document).ready(){
|
||||
readCookie();
|
||||
setLogin();
|
||||
insertTabs();
|
||||
insertButtons();
|
||||
|
||||
|
||||
initListButtons();
|
||||
setupCreateDialogs(); //listener for create
|
||||
setupTips();
|
||||
|
||||
//action button listener! -> plugins deal with that
|
||||
|
||||
|
||||
$('button').button();
|
||||
$('div#select_helpers').hide();
|
||||
emptyDashboard();
|
||||
|
||||
$(".ui-widget-overlay").live("click", function (){
|
||||
$("div:ui-dialog:visible").dialog("close");
|
||||
});
|
||||
|
||||
//Dashboard link listener
|
||||
$("#dashboard_table h3 a").live("click", function (){
|
||||
var tab = $(this).attr('href');
|
||||
showTab(tab);
|
||||
return false;
|
||||
});
|
||||
|
||||
//Close select lists...
|
||||
$('*:not(.action_list,.list_button)').click(function(){
|
||||
$('.action_list:visible').hide();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
//reads the cookie and places its info in the 'cookie' var
|
||||
function readCookie(){
|
||||
$.each(document.cookie.split("; "), function(i,e){
|
||||
var e_split = e.split("=");
|
||||
var key = e_split[0];
|
||||
var value = e_split[1];
|
||||
cookie[key] = value;
|
||||
});
|
||||
}
|
||||
|
||||
//sets the user info in the top bar and creates a listner in the signout button
|
||||
function setLogin(){
|
||||
username = cookie["one-user"];
|
||||
uid = cookie["one-user_id"];
|
||||
|
||||
$("#user").html(username);
|
||||
$("#logout").click(function(){
|
||||
OpenNebula.Auth.logout({success:function(){
|
||||
window.location.href = "/login";
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function insertTabs(){
|
||||
var tab_info;
|
||||
for (tab in SunstoneCfg["tabs"]){
|
||||
tab_info = SunstoneCfg["tabs"].tab;
|
||||
$("div.inner_center").append('<div id="'+tab_info.tab_id+'" class="tab"></div>');
|
||||
$('div#'+tab_info.tab_id).html(tab_info.content);
|
||||
|
||||
$('ul#navigation').append('<li><a href="'+tab_info.tab_id+'">'+tab+'</a></li>');
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function insertButtons(){
|
||||
var buttons;
|
||||
var tab_id;
|
||||
var button_code;
|
||||
|
||||
for (tab in SunstoneCfg["tabs"]){
|
||||
buttons = SunstoneCfg["tabs"][tab].buttons;
|
||||
content = SunstoneCfg["tabs"][tab].content;
|
||||
if ($('div#'+tab+' .action_blocks').length){
|
||||
$.each(buttons,function(){
|
||||
button_code = "";
|
||||
if (!this.condition()) { return true };
|
||||
|
||||
switch (this.type) {
|
||||
case "action":
|
||||
button_code = '<button class="action_button top_button" value="'+this.action+'">'+this.text+'</button>';
|
||||
break;
|
||||
case "create":
|
||||
button_code = '<button class="create top_button" value="'+this.action+'">'+this.text+'</button>';
|
||||
break;
|
||||
case "select":
|
||||
button_code = '<select class="multi_action_slct">';
|
||||
$.each(this.action,function(){
|
||||
if (this.condition()){
|
||||
button_code += '<option value="'+this.value+'">'+this.text+'</option>';
|
||||
};
|
||||
});
|
||||
button_code = '</select>';
|
||||
break;
|
||||
|
||||
}
|
||||
$('div#'+tab+' .action_blocks').append(button_code);
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Converts selects into buttons which show a of actions when clicked
|
||||
function initListButtons(){
|
||||
|
||||
//for each multi_action select
|
||||
$('.multi_action_slct').each(function(){
|
||||
//prepare replacement buttons
|
||||
buttonset = $('<div style="display:inline-block;" class="top_button"></div');
|
||||
button1 = $('<button class="last_action_button action_button confirm_button confirm_with_select_button" value="">Previous action</button>').button();
|
||||
button1.attr("disabled","disabled");
|
||||
button2 = $('<button class="list_button" value="">See more</button>').button({
|
||||
text:false,
|
||||
icons: { primary: "ui-icon-triangle-1-s" }
|
||||
});
|
||||
buttonset.append(button1);
|
||||
buttonset.append(button2);
|
||||
buttonset.buttonset();
|
||||
|
||||
//prepare list
|
||||
options = $('option', $(this));
|
||||
list = $('<ul class="action_list"></ul>');
|
||||
$.each(options,function(){
|
||||
classes = $(this).attr("class");
|
||||
item = $('<li></li>');
|
||||
a = $('<a href="#" class="'+classes+'" value="'+$(this).val()+'">'+$(this).text()+'</a>');
|
||||
a.val($(this).val());
|
||||
item.html(a);
|
||||
list.append(item);
|
||||
});
|
||||
list.css({
|
||||
"display":"none"
|
||||
});
|
||||
|
||||
|
||||
//replace the select and insert the buttons
|
||||
$(this).before(buttonset);
|
||||
$(this).parents('.action_blocks').append(list);
|
||||
$(this).remove();
|
||||
//$(this).replaceWith(list);
|
||||
|
||||
});
|
||||
|
||||
|
||||
//listen for events on this buttons and list
|
||||
|
||||
//enable run the last action button
|
||||
$('.action_list li a').click(function(){
|
||||
//enable run last action button
|
||||
prev_action_button = $('.last_action_button',$(this).parents('.action_blocks'));
|
||||
prev_action_button.val($(this).val());
|
||||
prev_action_button.removeClass("confirm_with_select_button");
|
||||
prev_action_button.removeClass("confirm_button");
|
||||
prev_action_button.removeClass("action_button");
|
||||
prev_action_button.addClass($(this).attr("class"));
|
||||
prev_action_button.button("option","label",$(this).text());
|
||||
prev_action_button.button("enable");
|
||||
$(this).parents('ul').hide("blind",100);
|
||||
//return false;
|
||||
});
|
||||
|
||||
|
||||
//Show the list of actions in place
|
||||
$('.list_button').click(function(){
|
||||
$('.action_list',$(this).parents('.action_blocks')).css({
|
||||
"left": $(this).prev().position().left,
|
||||
"top": $(this).prev().position().top+13,
|
||||
"width": $(this).parent().outerWidth()-11
|
||||
});
|
||||
$('.action_list',$(this).parents('.action_blocks')).toggle("blind",100);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
//Sets up all the "+ New Thing" dialogs.
|
||||
function setupCreateDialogs(){
|
||||
createHostDialog();
|
||||
createClusterDialog();
|
||||
createVMachineDialog();
|
||||
createVNetworkDialog();
|
||||
createUserDialog();
|
||||
createImageDialog();
|
||||
|
||||
//Todo listener on "create" class to trigger the right dialog.
|
||||
}
|
||||
|
||||
//Replaces all class"tip" divs with an information icon that
|
||||
//displays the tip information on mouseover.
|
||||
function setupTips(){
|
||||
$('div.tip').each(function(){
|
||||
tip = $(this).html();
|
||||
$(this).html('<span class="ui-icon ui-icon-info info_icon"></span>');
|
||||
$(this).append('<span class="tipspan"></span>');
|
||||
|
||||
$(this).append('<span class="ui-icon ui-icon-alert man_icon" />');
|
||||
|
||||
|
||||
$('span.tipspan',this).html(tip);
|
||||
$(this).parent().append('<div class="clear"></div>');
|
||||
$('span.tipspan',this).hide();
|
||||
$('span.info_icon',this).hover(function(e){
|
||||
var top, left;
|
||||
top = e.pageY - 15;// - $(this).parents('#create_vm_dialog').offset().top - 15;
|
||||
left = e.pageX + 15;// - $(this).parents('#create_vm_dialog').offset().left;
|
||||
$(this).next().css(
|
||||
{"top":top+"px",
|
||||
"left":left+"px"});
|
||||
$(this).next().fadeIn();
|
||||
},function(){
|
||||
$(this).next().fadeOut();
|
||||
});
|
||||
});
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user