/** * Create dynamic list view based on data callbacks */ (function($, cloudStack) { /** * Add 'pending' notification */ var addNotification = function(notification, success, successArgs, error, errorArgs) { if (!notification) { success(successArgs); return false; }; var $notifications = $('div.notifications'); if (!notification.poll) { $notifications.notifications('add', { section: notification.section, desc: notification.desc, interval: 0, poll: function(args) { success(successArgs); args.complete(); } }); } else { $notifications.notifications('add', { section: notification.section, desc: notification.desc, interval: 5000, _custom: notification._custom, poll: function(args) { var complete = args.complete; notification.poll({ _custom: args._custom, complete: function(args) { success($.extend(successArgs, args)); complete(args); }, error: function(args) { if (args.message) { cloudStack.dialog.notice({ message: args.message }); } error($.extend(errorArgs, args)); complete(args); } }); } }); } return true; }; var uiActions = { standard: function($instanceRow, args, additional) { var listViewArgs = $instanceRow.closest('div.list-view').data('view-args'); var notification = args.action.notification ? args.action.notification : {}; var messages = args.action ? args.action.messages : {}; var messageArgs = { name: $instanceRow.find('td.name span').html() }; var action = args.action ? args.action.action : {}; var section; var data = { id: $instanceRow.data('list-view-item-id'), jsonObj: $instanceRow.data('jsonObj') }; var $listView = $instanceRow.closest('.list-view'); if (args.data) $.extend(true, data, args.data); if (listViewArgs) section = listViewArgs.section; notification.desc = messages ? messages.notification(messageArgs) : null; if (listViewArgs) notification.section = listViewArgs.id; var performAction = function(data, options) { if (!options) options = {}; var $form = options.$form; $instanceRow = options.$item ? options.$item : $instanceRow; var $item = options.$item; var context = $.extend(true, {}, listViewArgs.context); context[ listViewArgs.activeSection ] = [$instanceRow.data('jsonObj')]; if (action.custom && !action.noAdd) { action.custom({ data: data, ref: options.ref, context: context, $instanceRow: $instanceRow, complete: function(args) { args = args ? args : {}; var $item = args.$item; notification.desc = messages.notification(args.messageArgs); notification._custom = args._custom; addNotification( notification, function(args) { if ($item.is(':visible')) { replaceItem( $item, args.data, args.actionFilter ? args.actionFilter : $instanceRow.next().data('list-view-action-filter') ); } }, {}, // Error function(args) { $item.remove(); } ); } }); } else if (action.uiCustom) { action.uiCustom({ $item: $instanceRow }); } else { var actionArgs = { data: data, ref: options.ref, context: options.context, $form: $form, response: { success: function(args) { args = args ? args : {}; var $prevRow, $newRow; // Make copy of previous row, in case data is needed $prevRow = $instanceRow.clone(); $prevRow.data($instanceRow.data()); // Set loading appearance if (args.data) { $instanceRow = replaceItem( $instanceRow, $.extend($instanceRow.data('json-obj'), args.data), $instanceRow.data('list-view-action-filter') ); } $instanceRow.find('td:last').children().remove(); $instanceRow.find('td:last').append($('
').addClass('loading')); $instanceRow.addClass('loading'); if (options.$item) $instanceRow.data('list-view-new-item', true); // Disable any clicking/actions for row $instanceRow.bind('click', function() { return false; }); notification._custom = args._custom; if (additional && additional.success) additional.success(args); addNotification( notification, // Success function(args) { if (!args) args = {}; if ($instanceRow.is(':visible')) { if (args.data) { $newRow = replaceItem( $instanceRow, $.extend($instanceRow.data('json-obj'), args.data), $instanceRow.data('list-view-action-filter') ); } else { // Nothing new, so just put in existing data $newRow = replaceItem( $instanceRow, $instanceRow.data('json-obj'), $instanceRow.data('list-view-action-filter') ); } if (additional && additional.complete) additional.complete(args, $newRow); } if (messages.complete) { cloudStack.dialog.notice({ message: messages.complete(args.data) }); } }, {}, // Error function(args) { if ($instanceRow.data('list-view-new-item')) { // For create forms $instanceRow.remove(); } else { // For standard actions replaceItem( $instanceRow, $.extend($instanceRow.data('json-obj'), args.data), args.actionFilter ? args.actionFilter : $instanceRow.data('list-view-action-filter') ); } } ); }, error: function(data){ if (data.message) cloudStack.dialog.notice({ message: data.message }); } } }; if (action.custom && action.noAdd) { action.custom({ data: data, ref: options.ref, context: context, $instanceRow: $instanceRow, complete: actionArgs.response.success }); } else { action(actionArgs); } } }; var context = $.extend({}, listViewArgs.context); context[ listViewArgs.activeSection ] = [$instanceRow.data('jsonObj')]; if (!args.action.createForm && !action.custom && !action.uiCustom) cloudStack.dialog.confirm({ message: messages.confirm(messageArgs), action: function() { performAction({ id: $instanceRow.data('list-view-item-id') }, { context: context }); } }); else if (action.custom || action.uiCustom) performAction(); else { var addRow = args.action.addRow == "false" ? false : true; var createFormContext = $.extend({}, context); cloudStack.dialog.createForm({ form: args.action.createForm, after: function(args) { var $newItem; if (addRow != false) { $newItem = $listView.listView('prependItem', { data: [ $.extend(args.data, { state: 'Creating', status: 'Creating', allocationstate: 'Creating' }) ] }); } else { $newItem = $instanceRow; } performAction(args.data, { ref: args.ref, context: createFormContext, $item: $newItem, $form: args.$form }); }, ref: listViewArgs.ref, context: createFormContext }); } }, edit: function($instanceRow, args) { var $td = $instanceRow.find('td.editable'); var $edit = $td.find('div.edit'); var $editInput = $edit.find('input'); var $label = $td.find('span'); var $listView = $instanceRow.closest('.list-view'); var listViewArgs = $listView.data('view-args'); // Hide label, show edit field var showEditField = function() { $edit.css({ opacity: 1 }); $label.fadeOut('fast', function() { $edit.fadeIn(); $editInput.focus(); $instanceRow.closest('div.data-table').dataTable('refresh'); }); }; // Hide edit field, validate and save changes var showLabel = function(val) { var oldVal = $label.html(); if (val) $label.html(val); var data = { id: $instanceRow.data('list-view-item-id'), jsonObj: $instanceRow.data('jsonObj') }; data[$td.data('list-view-item-field')] = $editInput.val(); var context = $.extend({}, listViewArgs.context); context[ listViewArgs.activeSection ] = $instanceRow.data('jsonObj'); args.callback({ data: data, context: context, response: { success: function(args) { $edit.hide(); $label.fadeIn(); $instanceRow.closest('div.data-table').dataTable('refresh'); }, error: function(args) { if (args.message) { cloudStack.dialog.notice({ message: args.message }); $edit.hide(), $label.html(oldVal).fadeIn(); $instanceRow.closest('div.data-table').dataTable('refresh'); } } } }); }; if (args.cancel) { showLabel(); return false; } if ($label.is(':visible')) { showEditField(); } else if ($editInput.val() != $label.html()) { $edit.animate({ opacity: 0.5 }); var originalName = $label.html(); var newName = $editInput.val(); addNotification( { section: $instanceRow.closest('div.view').data('view-args').id, desc: 'Renamed ' + originalName + ' to ' + newName }, function(data) { showLabel(newName); }, [{ name: newName }] ); } else { showLabel(); } return $instanceRow; } }; /** * Edit field text * * @param $td {jQuery} to put input field into */ var createEditField = function($td) { $td.addClass('editable'); // Put label into a span var value = $td.html(); $('').html(value).appendTo($td.html('')); var $editArea = $('
').addClass('edit'); var $editField = $('').addClass('edit').attr({ type: 'text', value: value }); var $actionButton = $('
').addClass('action'); var $saveButton = $actionButton.clone().addClass('save').attr({ 'title': 'Save' }); var $cancelButton = $actionButton.clone().addClass('cancel').attr({ 'title': 'Cancel edit' }); $([$editField, $saveButton, $cancelButton]).each(function() { this.appendTo($editArea); }); return $editArea.hide(); }; var createHeader = function(fields, $table, actions) { var $thead = $('').appendTo($table); $.each(fields, function(key) { var field = this; var $th = $('').appendTo($thead); if ($th.index()) $th.addClass('reduced-hide'); $th.html(field.label); }); if (actions) { $thead.append( $('') .html('Actions') .addClass('actions reduced-hide') ); } return $thead; }; var createFilters = function($toolbar, filters) { if (!filters) return false; var $filters = $('
').addClass('filters reduced-hide'); $filters.append(''); var $filterSelect = $('').appendTo($filters); if (filters) $.each(filters, function(key) { var $option = $('