1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-23 22:50:09 +03:00

Feature #507: Improved addition of main tabs. Fixed bugs. Commented code.

This commit is contained in:
Hector Sanjuan 2011-03-23 16:52:31 +01:00
parent 5d00477bf6
commit 7fdac54358
7 changed files with 229 additions and 168 deletions

View File

@ -149,7 +149,13 @@ var dashboard_tab_content =
</table>';
Sunstone.addMainTab('dashboard_tab','Dashboard',dashboard_tab_content,null);
var dashboard_tab = {
title: 'Dashboard',
content: dashboard_tab_content,
condition : True
}
Sunstone.addMainTab('dashboard_tab',dashboard_tab);
$(document).ready(function(){
//Dashboard link listener

View File

@ -322,12 +322,17 @@ var host_info_panel = {
content: ""
}
};
var hosts_tab = {
title: 'Hosts &amp; Clusters',
content: hosts_tab_content,
buttons: host_buttons,
condition: True
}
Sunstone.addActions(host_actions);
// title, content, buttons, id
Sunstone.addMainTab('hosts_tab','Hosts &amp; Clusters',hosts_tab_content,host_buttons);
Sunstone.addMainTab('hosts_tab',hosts_tab);
Sunstone.addInfoPanel("host_info_panel",host_info_panel);

View File

@ -422,8 +422,15 @@ var image_info_panel = {
}
var images_tab = {
title: "Images",
content: images_tab_content,
buttons: image_buttons,
condition: True
}
Sunstone.addActions(image_actions);
Sunstone.addMainTab('images_tab',"Images",images_tab_content,image_buttons);
Sunstone.addMainTab('images_tab',images_tab);
Sunstone.addInfoPanel('image_info_panel',image_info_panel);

View File

@ -119,8 +119,15 @@ var user_buttons = {
}
}
var users_tab = {
title: "Users",
content: users_tab_content,
buttons: user_buttons,
condition: function(){ return uid == 0; }
}
Sunstone.addActions(user_actions);
Sunstone.addMainTab('users_tab',"Users",users_tab_content,user_buttons,false,function(){return uid==0;});
Sunstone.addMainTab('users_tab',users_tab);
function userElementArray(user_json){

View File

@ -805,8 +805,15 @@ var vm_info_panel = {
}
}
var vms_tab = {
title: "Virtual Machines",
content: vms_tab_content,
buttons: vm_buttons,
condition: True
}
Sunstone.addActions(vm_actions);
Sunstone.addMainTab('vms_tab',"Virtual Machines",vms_tab_content,vm_buttons);
Sunstone.addMainTab('vms_tab',vms_tab);
Sunstone.addInfoPanel('vm_info_panel',vm_info_panel);

View File

@ -259,8 +259,15 @@ var vnet_info_panel = {
}
}
var vnets_tab = {
title: "Virtual Networks",
content: vnets_tab_content,
buttons: vnet_buttons,
condition: True
}
Sunstone.addActions(vnet_actions);
Sunstone.addMainTab('vnets_tab',"Virtual Networks",vnets_tab_content, vnet_buttons);
Sunstone.addMainTab('vnets_tab',vnets_tab);
Sunstone.addInfoPanel('vnet_info_panel',vnet_info_panel);

View File

@ -14,69 +14,64 @@
/* 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"/>';
//Sunstone configuration is formed by predifined "actions", main tabs
//and "info_panels". Each tab has "content" and "buttons". Each
//"info_panel" has "tabs" with "content".
var SunstoneCfg = {
"actions" : {
},
"tabs" : {
},
"info_panels" : {
}
"actions" : {},
"tabs" : {},
"info_panels" : {}
};
/* Public plugin interface */
var Sunstone = {
//Adds a predifined action
"addAction" : function (name,action_obj) {
SunstoneCfg["actions"][name] = action_obj;
},
//Replaces a predefined action
"updateAction" : function(name,action_obj) {
SunstoneCfg["actions"][name] = action_obj;
},
//Deletes a predefined action.
"removeAction" : function(action) {
SunstoneCfg["actions"][action] = null;
delete SunstoneCfg["actions"][action];
},
//Adds several actions encapsulated in an js object.
"addActions" : function(actions) {
for (action in actions){
Sunstone.addAction(action,actions[action]);
}
},
"addMainTab" : function(tab_id,title_arg,content_arg, buttons_arg,refresh,condition_f) {
SunstoneCfg["tabs"][tab_id] = {title: title_arg,
content: content_arg,
buttons: buttons_arg,
condition: condition_f
};
//Adds a new main tab. Refreshes the dom if wanted.
"addMainTab" : function(tab_id,tab_obj,refresh) {
SunstoneCfg["tabs"][tab_id] = tab_obj;
if (refresh){
insertTab(tab_id);
}
},
//Updates the content of an info tab and refreshes the DOM if wanted.
"updateMainTabContent" : function(tab_id,content_arg,refresh){
SunstoneCfg["tabs"][tab_id]["content"]=content_arg;
if (refresh){
if (refresh){ //if not present it won't be updated
$('div#'+tab).html(tab_info.content);
}
},
//Replaces the buttons of an info tab and regenerates them if wanted.
"updateMainTabButtons" : function(tab_id,buttons_arg,refresh){
SunstoneCfg["tabs"][tab_id]["buttons"]=buttons_arg;
if (refresh){
@ -85,13 +80,16 @@ var Sunstone = {
}
},
//Removes a tab and refreshes the DOM
"removeMainTab" : function(tab_id,refresh) {
SunstoneCfg["tabs"][tab_id]=null;
delete SunstoneCfg["tabs"][tab_id];
if (refresh) {
$('div#'+tab_name).remove();
}
},
//Generates and returns the HTML div element for an info panel, with
//Jquery tabs.
"getInfoPanelHTML" : function(name,selected_tab){
var info_panel = $('<div id="'+name+'"><ul></ul></div>');
var tabs = SunstoneCfg["info_panels"][name];
@ -108,26 +106,32 @@ var Sunstone = {
},
//Adds a new info panel
"addInfoPanel" : function(name, info_panel){
SunstoneCfg["info_panels"][name]=info_panel;
},
//Replaces an existing info panel
"updateInfoPanel" : function(name, info_panel){
SunstoneCfg["info_panels"][name]=info_panel;
},
//Removes an info panel
"removeInfoPanel" : function(name){
SunstoneCfg["info_panels"][name] = null;
delete SunstoneCfg["info_panels"][name];
},
//Makes an info panel content pop up in the screen.
"popUpInfoPanel" : function(name, selected_tab){
popDialog(Sunstone.getInfoPanelHTML(name, selected_tab));
},
//adds a tab to an info panel.
"addInfoPanelTab" : function(info_panel, tab_name, tab){
SunstoneCfg["info_panels"][info_panel][tab_name] = tab;
},
//Replaces a tab from an info panel. Refreshes the DOM if wanted.
"updateInfoPanelTab" : function(info_panel, tab_name, tab, refresh){
SunstoneCfg["info_panels"][info_panel][tab_name] = tab;
if (refresh){
@ -135,11 +139,14 @@ var Sunstone = {
}
},
//Removes a tab from an info panel configuration.
"removeInfoPanelTab" : function(info_panel,tab_name){
SunstoneCfg["info_panels"][info_panel][tab_name] = null;
delete SunstoneCfg["info_panels"][info_panel][tab_name];
},
//Runs a predefined action. Wraps the calls to opennebula.js and
//can be use to run action depending on conditions and notify them
//if desired.
"runAction" : function(action, data_arg, extra_param){
var actions = SunstoneCfg["actions"];
@ -152,9 +159,13 @@ var Sunstone = {
var notify = action_cfg.notify;
var condition = action_cfg["condition"];
if (condition && !condition() && notify){
//we do not meet the condition to run this action
//Is the condition to run the action met?
//Should we inform if it is not met?
if (condition && !condition()){
if (notify) {
notifyError("This action cannot be run");
}
return;
}
@ -163,19 +174,23 @@ var Sunstone = {
var err = action_cfg["error"];
//Time to close any confirmation dialogs, as the execution may have
//come from them.
$('div#confirm_with_select_dialog').dialog("close");
$('div#confirm_dialog').dialog("close");
//We ease the use of:
// * Create call
// * Confirm and confirm with select calls
// * Calls on multiple elements
// * Other calls
// * "create" calls to opennebula.js
// * "single" element calls to opennebula.js
// * "list" (get the pool of elements) calls to opennebula.js
// * "multiple" - actions to be run on a given list of elements
// (with maybe an extra parameter).
// * The default actions. Simple call the the pre-defined "call"
// function with an extraparam if defined.
switch (action_cfg.type){
case "create":
case "create","register":
call({data:data_arg, success: callback, error:err});
break;
case "single":
@ -195,8 +210,8 @@ var Sunstone = {
});
break;
default:
//we have supposedly altered an action and we want it to do
//something completely different
//This action is complemente handled by the "call" function.
//we pass any data if present.
if (data_arg && extra_param) {call(data_arg,extra_param);}
else if (data_arg) {call(data_arg);}
else {call();}
@ -204,6 +219,9 @@ var Sunstone = {
},
//Runs a predefined action on the selected nodes of a datatable.
//Optionally they are run with an extra_parameter.
//If no datatable is provided, it simply runs the action.
"runActionOnDatatableNodes": function(action,dataTable,extra_param){
if (dataTable != null){
@ -219,11 +237,14 @@ var Sunstone = {
Sunstone.runAction(action,extra_param);
};
},
//returns a button object from the desired tab
"getButton" : function(tab_name,button_name){
var button = null;
var buttons = SunstoneCfg["tabs"][tab_name]["buttons"];
button = buttons[button_name];
if (!button && buttons["action_list"]) //not found, is it in the list then?
//not found, is it in the list then?
if (!button && buttons["action_list"])
{
button = buttons["action_list"]["actions"][button_name];
}
@ -236,17 +257,25 @@ var Sunstone = {
//plugins have done their jobs when we execute this
//Plugins have done their pre-ready jobs when we execute this. That means
//all startup configuration is in place regarding tabs, info panels etc.
$(document).ready(function(){
readCookie();
setLogin();
//Insert the tabs in the DOM and their buttons.
insertTabs();
insertButtons();
//Enhace the look of select buttons
initListButtons();
setupCreateDialogs(); //listener for create
//Prepare the standard confirmation dialogs
setupConfirmDialogs();
//Listen for .action_buttons
//An action buttons runs a predefined action. If it has type
//"multiple" it runs that action on the elements of a datatable.
$('.action_button').live("click",function(){
var table = null;
@ -264,32 +293,35 @@ $(document).ready(function(){
return false;
});
//Listen .confirm_buttons. These buttons show a confirmation dialog
//before running the action.
$('.confirm_button').live("click",function(){
popUpConfirmDialog(this);
return false;
});
//Listen .confirm_buttons. These buttons show a confirmation dialog
//with a select box before running the action.
$('.confirm_with_select_button').live("click",function(){
popUpConfirmWithSelectDialog(this);
return false;
});
//Jquery-enhace the buttons in the DOM
$('button').button();
$('div#select_helpers').hide();
$(".ui-widget-overlay").live("click", function (){
$("div:ui-dialog:visible").dialog("close");
//Close overlay dialogs when clicking outside of them.
$(".ui-widget-overlay").live("click", function (){
$("div:ui-dialog:visible").dialog("close");
});
//Close select lists...
//Close select lists when clicking somewhere else.
$('*:not(.action_list,.list_button)').click(function(){
$('.action_list:visible').hide();
});
//Start with the dashboard (supposing we have one).
showTab('#dashboard_tab');
});
@ -307,8 +339,10 @@ function readCookie(){
});
}
//sets the user info in the top bar and creates a listner in the signout button
//sets the user info in the top bar and creates a listner in the
//signout button
function setLogin(){
//This two variables can be used anywhere
username = cookie["one-user"];
uid = cookie["one-user_id"];
@ -322,128 +356,114 @@ function setLogin(){
});
}
//Inserts all main tabs in the DOM
function insertTabs(){
var tab_info;
for (tab in SunstoneCfg["tabs"]){
tab_info = SunstoneCfg["tabs"][tab];
//skip this tab if we do not meet the condition
if (tab_info.condition && !tab_info.condition()) {continue;}
$("div.inner-center").append('<div id="'+tab+'" class="tab"></div>');
$('div#'+tab).html(tab_info.content);
$('ul#navigation').append('<li><a href="#'+tab+'">'+tab_info.title+'</a></li>');
insertTab(tab);
}
}
//Inserts a main tab in the DOM. This is done by
//adding the content to the proper div and by adding a list item
//link to the navigation menu
function insertTab(tab_name){
var tab_info = SunstoneCfg["tabs"][tab_name];
var condition = tab_info["condition"];
//skip this tab if we do not meet the condition
if (condition && !condition()) {return;}
$("div.inner-center").append('<div id="'+tab_name+'" class="tab"></div>');
$('div#'+tab_name).html(tab_info.content);
$('ul#navigation').append('<li><a href="#'+tab_name+'">'+tab_info.title+'</a></li>');
}
//Inserts the buttons of all tabs.
function insertButtons(){
for (tab in SunstoneCfg["tabs"]){
insertButtonsInTab(tab)
}
}
//If we have defined a block of action buttons in a tab,
//this function takes care of inserting them in the DOM.
function insertButtonsInTab(tab_name){
var buttons = SunstoneCfg["tabs"][tab_name]["buttons"];
var button_code="";
var sel_obj=null;
var condition=null;
if ($('div#'+tab_name+' .action_blocks').length){
//Check if we have included an appropiate space our tab to
//insert them (an .action_blocks div)
if ($('div#'+tab_name+' div.action_blocks').length){
//for every button defined for this tab...
for (button_name in buttons){
button_code = "";
button = buttons[button_name];
if (button.condition()) {
switch (button.type) {
case "select":
button_code = '<select class="multi_action_slct">';
for (sel_name in button.actions){
sel_obj = button["actions"][sel_name];
if (sel_obj.condition()){
button_code += '<option class="'+sel_obj.type+'_button" value="'+sel_name+'">'+sel_obj.text+'</option>';
};
};
button_code += '</select>';
break;
case "image":
button_code = '<a href="#" class="action_button" value="'+button_name+'"><img class="image_button" src="'+button.img+'" alt="'+button.text+'" /></a>';
break;
case "create_dialog":
button_code = '<button class="'+button.type+'_button action_button top_button" value="'+button_name+'">'+button.text+'</button>';
break;
default:
button_code = '<button class="'+button.type+'_button top_button" value="'+button_name+'">'+button.text+'</button>';
condition = button.condition;
//if we meet the condition we proceed. Otherwise we skip it.
if (condition && !condition()) { continue; }
}
//depending on the type of button we generate different
//code. There are 4 possible types:
/*
* select: We need to create a select element with actions inside.
* image: a button consisting of a link with an image inside.
* create: we make sure they have the "action_button" class.
* default: generally buttons have the "<type>_button" class.
*/
switch (button.type) {
case "select":
button_code = '<select class="multi_action_slct">';
//for each subbutton in the list we add an option to the select.
for (sel_name in button.actions){
sel_obj = button["actions"][sel_name];
condition = sel_obj.condition;
//only add if we meet the condition
if (condition && !condition()){ continue; };
button_code += '<option class="'+sel_obj.type+'_button" value="'+sel_name+'">'+sel_obj.text+'</option>';
};
button_code += '</select>';
break;
case "image":
button_code = '<a href="#" class="action_button" value="'+button_name+'"><img class="image_button" src="'+button.img+'" alt="'+button.text+'" /></a>';
break;
case "create_dialog":
button_code = '<button class="'+button.type+'_button action_button top_button" value="'+button_name+'">'+button.text+'</button>';
break;
default:
button_code = '<button class="'+button.type+'_button top_button" value="'+button_name+'">'+button.text+'</button>';
}
$('div#'+tab_name+' .action_blocks').append(button_code);
}//for each button in tab
}//if tab exists
}
// We do not insert info panels code, we generate it dynamicly when
// we need it with getInfoPanelHTML()
//~ function insertInfoPanels(){
//~ var panels = SunstoneCfg["info_panels"];
//~ tabs = null;
//~ //For each defined dialog
//~ for (panel in panels) {
//~ addInfoPanel(panel);
//~ }
//~ }
//~
//~ function addInfoPanel(name){
//~ var tabs = SunstoneCfg["info_panels"][name];
//~ $('#info_panels').append('<div id="'+name+'"></div>');
//~ for (tab in tabs){
//~ addInfoPanelTab(name,tab);
//~ }
//~ //at this point jquery tabs structure is ready, so we enable it
//~ $('div#'+name).tabs();
//~ }
//~
//~ function refreshInfoPanel(name){
//~ $('#info_panels div#'+name).tabs("destroy");
//~ $('#info_panels div#'+name).remove();
//~ $('#info_panels').append('<div id="'+name+'"></div>');
//~ var tabs = SunstoneCfg["info_panels"][name];
//~ for (tab in tabs){
//~ addInfoPanelTab(name,tab);
//~ }
//~ //at this point jquery tabs structure is ready, so we enable it
//~ $('div#'+name).tabs();
//~ }
//~
//~ function addInfoPanelTab(panel_name,tab_name){
//~ var tab = SunstoneCfg["info_panels"][panel_name][tab_name];
//~ if ( !$('div#'+panel_name+' ul').length ) {
//~ $('div#'+panel_name).prepend('<ul></ul>');
//~ }
//~ $('div#'+panel_name+' ul').append('<li><a href="#'+tab_name+'">'+tab.title+'</a></li>');
//~ $('div#'+panel_name).append('<div id="'+tab_name+'">'+tab.content+'</div>');
//~ }
//~
//Tries to refresh a tab content if it is somewhere in the DOM
//Useful for plugins wanting to update certain information.
function refreshInfoPanelTab(panel_name,tab_name){
var tab = SunstoneCfg["info_panels"][panel_name][tab_name];
$('div#'+panel_name+' div#'+tab_name).html(tab.content);
var tab_content = SunstoneCfg["info_panels"][panel_name][tab_name].content;
$('div#'+panel_name+' div#'+tab_name).html(tab_content);
}
//Converts selects into buttons which show a of actions when clicked
//Converts selects into buttons which show a list of actions when
//clicked. This lists have two parts, one for the last action run, and
//another containing a list of actions that can be folded/unfolded.
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();
var buttonset = $('<div style="display:inline-block;" class="top_button"></div');
var 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({
var button2 = $('<button class="list_button" value="">See more</button>').button({
text:false,
icons: { primary: "ui-icon-triangle-1-s" }
});
@ -452,12 +472,12 @@ function initListButtons(){
buttonset.buttonset();
//prepare list
options = $('option', $(this));
list = $('<ul class="action_list"></ul>');
var options = $('option', $(this));
var 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>');
var classes = $(this).attr("class");
var item = $('<li></li>');
var a = $('<a href="#" class="'+classes+'" value="'+$(this).val()+'">'+$(this).text()+'</a>');
a.val($(this).val());
item.html(a);
list.append(item);
@ -476,12 +496,12 @@ function initListButtons(){
});
//listen for events on this buttons and list
//below the listeners for events on these 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'));
var 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");
@ -506,26 +526,15 @@ function initListButtons(){
});
}
//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.
}
//Adds the dialogs bodies
//Prepares the standard confirm dialogs
function setupConfirmDialogs(){
//confirm
//add div to the main body if it isn't present.
if (!($('div#confirm_dialog').length)){
$('div#dialogs').append('<div id="confirm_dialog" title="Confirmation of action"></div>');
};
//add the HTML with the standard question and buttons.
$('div#confirm_dialog').html(
'<form action="javascript:alert(\'js error!\');">\
<div id="confirm_tip">Do you want to proceed?</div>\
@ -547,8 +556,10 @@ function setupConfirmDialogs(){
autoOpen:false
});
//enhace the button look
$('div#confirm_dialog button').button();
//same for the confirm with select dialog.
if (!($('div#confirm_with_select_dialog').length)){
$('div#dialogs').append('<div id="confirm_with_select_dialog" title="Confirmation of action"></div>');
};
@ -564,7 +575,8 @@ function setupConfirmDialogs(){
</div>\
</form>');
//prepare the jquery dialog
//prepare the jquery dialog
$('div#confirm_with_select_dialog').dialog({
resizable:false,
modal:true,
@ -575,12 +587,16 @@ function setupConfirmDialogs(){
$('div#confirm_with_select_dialog button').button();
//if a cancel button is pressed, we close the dialog.
$('button.confirm_cancel').click(function(){
$('div#confirm_with_select_dialog').dialog("close");
$('div#confirm_dialog').dialog("close");
return false;
});
//when we proceed with a "confirm with select" we need to
//find out if we are running an action with a parametre on a datatable
//items or if its just an action
$('button#confirm_with_select_proceed').click(function(){
var value = $(this).val();
var action = SunstoneCfg["actions"][value];
@ -588,7 +604,7 @@ function setupConfirmDialogs(){
if (!action) { notifyError("Action "+value+" not defined."); return false;};
switch (action.type){
case "multiple": //find the datatable
table = SunstoneCfg["actions"][value].dataTable();
var table = SunstoneCfg["actions"][value].dataTable();
Sunstone.runActionOnDatatableNodes(value,table,param);
break;
default:
@ -601,6 +617,11 @@ function setupConfirmDialogs(){
}
//Popup a confirmation dialog.
//In order to find out the dialog action and
//tip for the user we need to access the clicked button
//configuration. We do this by discovering the name of the parent tab
//and with the value of the clicked element.
function popUpConfirmDialog(target_elem){
var value = $(target_elem).val();
var tab_id = $(target_elem).parents('.tab').attr('id');
@ -611,6 +632,9 @@ function popUpConfirmDialog(target_elem){
$('div#confirm_dialog').dialog("open");
}
//Same as previous. This time we need as well to access the updated
//select list, which is done through the pointer of found in the
//config of the button (a function returning the select options).
function popUpConfirmWithSelectDialog(target_elem){
var value = $(target_elem).val();
var tab_id = $(target_elem).parents('.tab').attr('id');
@ -622,8 +646,6 @@ function popUpConfirmWithSelectDialog(target_elem){
$('button#confirm_with_select_proceed').val(value);
$('div#confirm_with_select_dialog').dialog("open");
}