diff --git a/src/sunstone/public/js/plugins/dashboard-tab.js b/src/sunstone/public/js/plugins/dashboard-tab.js index edb303c51f..b6bc6fb2ac 100644 --- a/src/sunstone/public/js/plugins/dashboard-tab.js +++ b/src/sunstone/public/js/plugins/dashboard-tab.js @@ -149,7 +149,13 @@ var dashboard_tab_content = '; -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 diff --git a/src/sunstone/public/js/plugins/hosts-tab.js b/src/sunstone/public/js/plugins/hosts-tab.js index dd1c937765..21c45e5e0d 100644 --- a/src/sunstone/public/js/plugins/hosts-tab.js +++ b/src/sunstone/public/js/plugins/hosts-tab.js @@ -322,12 +322,17 @@ var host_info_panel = { content: "" } }; - + + +var hosts_tab = { + title: 'Hosts & Clusters', + content: hosts_tab_content, + buttons: host_buttons, + condition: True +} Sunstone.addActions(host_actions); - -// title, content, buttons, id -Sunstone.addMainTab('hosts_tab','Hosts & Clusters',hosts_tab_content,host_buttons); +Sunstone.addMainTab('hosts_tab',hosts_tab); Sunstone.addInfoPanel("host_info_panel",host_info_panel); diff --git a/src/sunstone/public/js/plugins/images-tab.js b/src/sunstone/public/js/plugins/images-tab.js index ea6eef4c36..de4ab5a5cd 100644 --- a/src/sunstone/public/js/plugins/images-tab.js +++ b/src/sunstone/public/js/plugins/images-tab.js @@ -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); diff --git a/src/sunstone/public/js/plugins/users-tab.js b/src/sunstone/public/js/plugins/users-tab.js index e9f1411f12..1c9f2039a6 100644 --- a/src/sunstone/public/js/plugins/users-tab.js +++ b/src/sunstone/public/js/plugins/users-tab.js @@ -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){ diff --git a/src/sunstone/public/js/plugins/vms-tab.js b/src/sunstone/public/js/plugins/vms-tab.js index 9c149e43ae..3fd1622da0 100644 --- a/src/sunstone/public/js/plugins/vms-tab.js +++ b/src/sunstone/public/js/plugins/vms-tab.js @@ -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); diff --git a/src/sunstone/public/js/plugins/vnets-tab.js b/src/sunstone/public/js/plugins/vnets-tab.js index 08845611d7..030202981c 100644 --- a/src/sunstone/public/js/plugins/vnets-tab.js +++ b/src/sunstone/public/js/plugins/vnets-tab.js @@ -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); diff --git a/src/sunstone/public/js/sunstone.js b/src/sunstone/public/js/sunstone.js index 1473526406..e425a3a308 100644 --- a/src/sunstone/public/js/sunstone.js +++ b/src/sunstone/public/js/sunstone.js @@ -14,69 +14,64 @@ /* limitations under the License. */ /* -------------------------------------------------------------------------- */ - -//TODOs: handle confirm and confirm with select dialogs - var cookie = {}; var username = ''; var uid = ''; var spinner = 'retrieving'; + +//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 = $('
'); 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#'+tab).html(tab_info.content); - - $('ul#navigation').append('
  • '+tab_info.title+'
  • '); - + 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#'+tab_name).html(tab_info.content); + + $('ul#navigation').append('
  • '+tab_info.title+'
  • '); +} + + +//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 = ''; - break; - case "image": - button_code = ''+button.text+''; - break; - case "create_dialog": - button_code = ''; - break; - default: - button_code = ''; + 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 "_button" class. + */ + switch (button.type) { + case "select": + button_code = ''; + break; + case "image": + button_code = ''+button.text+''; + break; + case "create_dialog": + button_code = ''; + break; + default: + button_code = ''; + } + $('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('
    '); - //~ 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('
    '); - //~ 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(''); - //~ } - //~ $('div#'+panel_name+' ul').append('
  • '+tab.title+'
  • '); - //~ $('div#'+panel_name).append('
    '+tab.content+'
    '); -//~ } -//~ - - //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 = $('
    Previous action').button(); + var buttonset = $('
    Previous action').button(); button1.attr("disabled","disabled"); - button2 = $('').button({ + var button2 = $('').button({ text:false, icons: { primary: "ui-icon-triangle-1-s" } }); @@ -452,12 +472,12 @@ function initListButtons(){ buttonset.buttonset(); //prepare list - options = $('option', $(this)); - list = $('
      '); + var options = $('option', $(this)); + var list = $('
        '); $.each(options,function(){ - classes = $(this).attr("class"); - item = $('
      • '); - a = $(''+$(this).text()+''); + var classes = $(this).attr("class"); + var item = $('
      • '); + var a = $(''+$(this).text()+''); 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('
        '); }; + //add the HTML with the standard question and buttons. $('div#confirm_dialog').html( '
        \
        Do you want to proceed?
        \ @@ -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('
        '); }; @@ -564,7 +575,8 @@ function setupConfirmDialogs(){
        \ '); - //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"); - - }