/**
* 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 = $('