This commit is contained in:
prachi 2012-07-23 15:34:41 -07:00
commit b80c3dc9c6
6 changed files with 530 additions and 10 deletions

View File

@ -8952,6 +8952,204 @@ div.panel.ui-dialog div.list-view div.fixed-header {
background: #DFE1E3; background: #DFE1E3;
} }
/*Tagger*/
.tagger {
width: 94%;
margin: auto;
padding-bottom: 12px;
background: #F2F0F0;
border: 1px solid #CFC9C9;
/*+placement:shift -4px 0px;*/
position: relative;
left: -4px;
top: 0px;
}
.tagger .field {
width: 179px;
float: left;
position: relative;
}
.tagger .tag-info {
font-size: 11px;
color: #757575;
margin-top: 12px;
margin-left: 8px;
}
.tagger .tag-info.title {
font-size: 11px;
color: #6F9BF0;
margin-bottom: 5px;
}
.tagger form {
margin: 12px 9px 0px;
}
.tagger.readonly form {
display: none;
}
.tagger form label {
display: block;
float: left;
width: 28px;
text-align: right;
font-size: 10px;
color: #394552;
margin-right: 9px;
/*+placement:shift 5px 8px;*/
position: relative;
left: 5px;
top: 8px;
}
.tagger form label.error {
position: absolute;
color: #FF0000;
left: 42px;
top: 29px;
/*[empty]background-color:;*/
}
.tagger form input {
padding: 4px;
background: #FFFFFF;
border: 1px solid #808080;
/*+border-radius:4px;*/
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
-khtml-border-radius: 4px;
border-radius: 4px;
}
.tagger form input[type=submit] {
background: url(../images/bg-gradients.png) repeat-x 0px -220px;
cursor: pointer;
color: #FFFFFF;
/*+text-shadow:0px -1px 2px #000000;*/
-moz-text-shadow: 0px -1px 2px #000000;
-webkit-text-shadow: 0px -1px 2px #000000;
-o-text-shadow: 0px -1px 2px #000000;
text-shadow: 0px -1px 2px #000000;
border: none;
/*+border-radius:4px;*/
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
-khtml-border-radius: 4px;
border-radius: 4px;
padding: 7px 25px 7px 26px;
margin-left: 16px;
}
.tagger form input[type=submit]:hover {
background-position: 0px -946px;
}
.tagger ul {
display: block;
width: 96%;
margin: 16px auto auto;
/*+border-radius:2px;*/
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
-khtml-border-radius: 2px;
border-radius: 2px;
overflow: auto;
padding-bottom: 10px;
border: 1px solid #D2D2D2;
background: #FFFFFF;
/*+box-shadow:inset 0px 0px 10px #DCDCDC;*/
-moz-box-shadow: inset 0px 0px 10px #DCDCDC;
-webkit-box-shadow: inset 0px 0px 10px #DCDCDC;
-o-box-shadow: inset 0px 0px 10px #DCDCDC;
box-shadow: inset 0px 0px 10px #DCDCDC;
}
.tagger.readonly ul {
}
.tagger ul li {
background: #DFDFDF 0px 4px;
height: 15px;
padding: 0px 18px 0 7px;
display: inline-block;
float: left;
margin-left: 7px;
margin-right: 2px;
margin-top: 5px;
/*+border-radius:4px;*/
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
-khtml-border-radius: 4px;
border-radius: 4px;
/*+placement:shift 0px 2px;*/
position: relative;
left: 0px;
top: 2px;
}
.tagger ul li span {
color: #000000;
}
.tagger ul li span.label {
font-size: 10px;
position: relative;
left: 15px;
top: -2px;
}
.tagger.readonly ul li span.label {
left: 6px;
}
.tagger ul li span.remove {
width: 15px !important;
overflow: hidden !important;
height: 11px !important;
background: #DFDFDF url(../images/sprites.png) no-repeat -596px -1183px;
display: block;
top: 0px !important;
left: -3px !important;
text-indent: 4px;
padding: 4px 0px 0px 8px;
font-size: 8px;
font-weight: bold;
cursor: pointer;
position: absolute !important;
color: #5B5B5B;
}
.tagger.readonly ul li span.remove {
display: none;
}
.tagger ul li span.remove:hover {
color: #000000;
}
/** Dialog tagger*/
.ui-dialog .tagger {
}
.ui-dialog .tagger .field {
width: 119px !important;
}
.ui-dialog .tagger input.key,
.ui-dialog .tagger input.value {
width: 66px !important;
height: 15px;
font-size: 11px !important;
}
.ui-dialog .tagger input[type=submit] {
padding: 6px 15px;
}
/*VPC / vApps*/ /*VPC / vApps*/
.vpc-chart { .vpc-chart {
width: 100%; width: 100%;

View File

@ -1614,7 +1614,8 @@
<script type="text/javascript" src="scripts/ui/widgets/listView.js?t=<%=now%>"></script> <script type="text/javascript" src="scripts/ui/widgets/listView.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/ui/widgets/detailView.js?t=<%=now%>"></script> <script type="text/javascript" src="scripts/ui/widgets/detailView.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/ui/widgets/treeView.js?t=<%=now%>"></script> <script type="text/javascript" src="scripts/ui/widgets/treeView.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/ui/widgets/notifications.js?t=<%=now%>"></script> <script type="text/javascript" src="scripts/ui/widgets/notifications.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/ui/widgets/tagger.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/cloud.core.callbacks.js?t=<%=now%>"></script> <script type="text/javascript" src="scripts/cloud.core.callbacks.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/sharedFunctions.js?t=<%=now%>"></script> <script type="text/javascript" src="scripts/sharedFunctions.js?t=<%=now%>"></script>

View File

@ -617,5 +617,83 @@ cloudStack.api = {
} }
} }
} }
},
tags: function(args) {
var resourceType = args.resourceType;
var contextId = args.contextId;
return {
actions: {
add: function(args) {
var data = args.data;
var resourceId = args.context[contextId][0].id;
$.ajax({
url: createURL(
'createTags&tags[0].key=' + data.key + '&tags[0].value=' + data.value
),
data: {
resourceIds: resourceId,
resourceType: resourceType
},
success: function(json) {
args.response.success({
_custom: { jobId: json.createtagsresponse.jobid },
notification: {
desc: 'Add tag for instance',
poll: pollAsyncJobResult
}
});
}
});
},
remove: function(args) {
var data = args.context.tagItems[0];
var resourceId = args.context[contextId][0].id;
$.ajax({
url: createURL(
'deleteTags&tags[0].key=' + data.key + '&tags[0].value=' + data.value
),
data: {
resourceIds: resourceId,
resourceType: resourceType
},
success: function(json) {
args.response.success({
_custom: { jobId: json.deletetagsresponse.jobid },
notification: {
desc: 'Remove tag for instance',
poll: pollAsyncJobResult
}
});
}
});
}
},
dataProvider: function(args) {
var resourceId = args.context[contextId][0].id;
$.ajax({
url: createURL('listTags'),
data: {
listAll: true,
resourceId: resourceId,
resourceType: resourceType
},
success: function(json) {
args.response.success({
data: json.listtagsresponse ?
json.listtagsresponse.tag : []
});
},
error: function(json) {
args.response.error(parseXMLHttpResponse(json));
}
});
}
};
} }
}; };

View File

@ -287,10 +287,14 @@
* @param callback * @param callback
*/ */
edit: function($detailView, args) { edit: function($detailView, args) {
$detailView.addClass('edit-mode');
if ($detailView.find('.button.done').size()) return false; if ($detailView.find('.button.done').size()) return false;
// Convert value TDs // Convert value TDs
var $inputs = $detailView.find('input, select'); var $inputs = $detailView.find('input, select').filter(function() {
return !$(this).closest('.tagger').size() && !$(this).attr('type') == 'submit';
});
var action = args.actions[args.actionName]; var action = args.actions[args.actionName];
var id = $detailView.data('view-args').id; var id = $detailView.data('view-args').id;
var $editButton = $('<div>').addClass('button done').html(_l('label.apply')).hide(); var $editButton = $('<div>').addClass('button done').html(_l('label.apply')).hide();
@ -302,9 +306,14 @@
$detailView.find('.ui-tabs-panel .detail-group.actions') $detailView.find('.ui-tabs-panel .detail-group.actions')
).fadeIn(); ).fadeIn();
$detailView.find('.tagger').removeClass('readonly');
$detailView.find('.tagger').find('input[type=text]').val('');
var convertInputs = function($inputs) { var convertInputs = function($inputs) {
// Save and turn back into labels // Save and turn back into labels
$inputs.each(function() { $inputs.each(function() {
if ($(this).closest('.tagger').size()) return true;
var $input = $(this); var $input = $(this);
var $value = $input.closest('td.value span'); var $value = $input.closest('td.value span');
@ -328,8 +337,12 @@
}; };
var removeEditForm = function() { var removeEditForm = function() {
$detailView.removeClass('edit-mode');
// Remove Edit form // Remove Edit form
var $form = $detailView.find('form'); var $form = $detailView.find('form').filter(function() {
return !$(this).closest('.tagger').size();
});
if ($form.size()) { if ($form.size()) {
var $mainGroups = $form.find('div.main-groups').detach(); var $mainGroups = $form.find('div.main-groups').detach();
$form.parent('div').append($mainGroups); $form.parent('div').append($mainGroups);
@ -337,11 +350,15 @@
} }
//Remove required labels //Remove required labels
$detailView.find('span.field-required').remove(); $detailView.find('span.field-required').remove();
} $detailView.find('.tagger').addClass('readonly');
};
// Put in original values // Put in original values
var cancelEdits = function($inputs, $editButton) { var cancelEdits = function($inputs, $editButton) {
$inputs.each(function() { $inputs.each(function() {
if ($(this).closest('.tagger').size()) return true;
var $input = $(this); var $input = $(this);
var $value = $input.closest('td.value span'); var $value = $input.closest('td.value span');
var originalValue = $input.data('original-value'); var originalValue = $input.data('original-value');
@ -424,8 +441,12 @@
}; };
$editButton.click(function() { $editButton.click(function() {
var $inputs = $detailView.find('input, select'), var $inputs = $detailView.find('input, select').filter(function() {
$form = $detailView.find('form'); return !$(this).closest('.tagger').size();
});
var $form = $detailView.find('form').filter(function() {
return !$(this).closest('.tagger').size();
});
if ($(this).hasClass('done')) { if ($(this).hasClass('done')) {
if (!$form.valid()) { if (!$form.valid()) {
@ -438,6 +459,8 @@
} else { // Cancel } else { // Cancel
cancelEdits($inputs, $editButton); cancelEdits($inputs, $editButton);
} }
return true;
}); });
$detailView.find('td.value span').each(function() { $detailView.find('td.value span').each(function() {
@ -511,8 +534,11 @@
} }
// Setup form validation // Setup form validation
$detailView.find('form').validate(); var $form = $detailView.find('form').filter(function() {
$detailView.find('form').find('input, select').each(function() { return !$(this).closest('.tagger').size();
});
$form.validate();
$form.find('input, select').each(function() {
var data = $(this).parent('span').data('validation-rules'); var data = $(this).parent('span').data('validation-rules');
if (data) { if (data) {
$(this).rules('add', data); $(this).rules('add', data);
@ -934,6 +960,14 @@
actionFilter: actionFilter actionFilter: actionFilter
}).appendTo($tabContent); }).appendTo($tabContent);
if (tabs.tags) {
$('<div>').tagger(
$.extend(true, {}, tabs.tags, {
context: $detailView.data('view-args').context
})
).appendTo($detailView.find('.main-groups')).addClass('readonly');
}
return true; return true;
}, },
error: function() { error: function() {

View File

@ -332,10 +332,16 @@
after: function(args) { after: function(args) {
var $loading = $('<div>').addClass('loading-overlay').prependTo($dataItem); var $loading = $('<div>').addClass('loading-overlay').prependTo($dataItem);
performAction({ data: args.data, complete: function() { performAction({ data: args.data, complete: function() {
$multi.multiEdit('refresh'); $multi.trigger('refresh');
} }); } });
} }
}); });
if (options.tags) {
$(':ui-dialog').append(
$('<div>').addClass('multi-edit-tags').tagger(options.tags)
);
}
} }
}) })
); );
@ -652,6 +658,7 @@
$.fn.multiEdit = function(args) { $.fn.multiEdit = function(args) {
var dataProvider = args.dataProvider; var dataProvider = args.dataProvider;
var multipleAdd = args.multipleAdd; var multipleAdd = args.multipleAdd;
var tags = args.tags;
var $multi = $('<div>').addClass('multi-edit').appendTo(this); var $multi = $('<div>').addClass('multi-edit').appendTo(this);
var $multiForm = $('<form>').appendTo($multi); var $multiForm = $('<form>').appendTo($multi);
var $inputTable = $('<table>').addClass('multi-edit').appendTo($multiForm); var $inputTable = $('<table>').addClass('multi-edit').appendTo($multiForm);
@ -918,7 +925,8 @@
context: $.extend(true, {}, context, this._context), context: $.extend(true, {}, context, this._context),
ignoreEmptyFields: ignoreEmptyFields, ignoreEmptyFields: ignoreEmptyFields,
preFilter: actionPreFilter, preFilter: actionPreFilter,
listView: listView listView: listView,
tags: tags
} }
).appendTo($dataBody); ).appendTo($dataBody);
}); });

View File

@ -0,0 +1,201 @@
(function($, cloudStack) {
var elems = {
inputArea: function(args) {
var $form = $('<form>').addClass('tag-input');
var $keyField = $('<div>').addClass('field key');
var $keyLabel = $('<label>').attr('for', 'key').html('Key:');
var $key = $('<input>').addClass('key required').attr('name', 'key');
var $valueField = $('<div>').addClass('field value');
var $valueLabel = $('<label>').attr('for', 'value').html('Value:');
var $value = $('<input>').addClass('value required').attr('name', 'value');
var $submit = $('<input>').attr('type', 'submit').val('Add');
$keyField.append($keyLabel, $key);
$valueField.append($valueLabel, $value);
$form.append(
$keyField, $valueField,
$submit
);
$form.validate({ onfocusout: false });
$form.submit(
args.onSubmit ?
function() {
if (!$form.valid()) return false;
args.onSubmit({
data: cloudStack.serializeForm($form),
response: {
success: function() {
// Restore editing of input
$key.attr('disabled', false);
$value.attr('disabled', false);
// Clear out old data
$key.val(''); $value.val('');
$key.focus();
},
error: function() {
// Restore editing of input
$key.attr('disabled', false);
$value.attr('disabled', false);
$key.focus();
}
}
});
// Prevent input during submission
$key.attr('disabled', 'disabled');
$value.attr('disabled', 'disabled');
return false;
} :
function() { return false; }
);
return $form;
},
tagItem: function(title, onRemove, data) {
var $li = $('<li>');
var $label = $('<span>').addClass('label').html(title);
var $remove = $('<span>').addClass('remove').html('X');
$remove.click(function() {
if (onRemove) onRemove($li, data);
});
$li.append($remove, $label);
return $li;
},
info: function(text) {
var $info = $('<div>').addClass('tag-info');
var $text = $('<span>').html(text);
$text.appendTo($info);
return $info;
}
};
$.widget('cloudStack.tagger', {
_init: function(args) {
var context = this.options.context;
var dataProvider = this.options.dataProvider;
var actions = this.options.actions;
var $container = this.element.addClass('tagger');
var $tagArea = $('<ul>').addClass('tags');
var $title = elems.info('Tags').addClass('title');
var $loading = $('<div>').addClass('loading-overlay');
var onRemoveItem = function($item, data) {
$loading.appendTo($container);
actions.remove({
context: $.extend(true, {}, context, {
tagItems: [data]
}),
response: {
success: function(args) {
var notification = $.extend(true, {} , args.notification, {
interval: 500,
_custom: args._custom
});
cloudStack.ui.notifications.add(
notification,
// Success
function() {
$loading.remove();
$item.remove();
}, {},
// Error
function() {
$loading.remove();
}, {}
);
},
error: function(message) {
$loading.remove();
cloudStack.dialog.notice({ message: message });
}
}
});
};
var $inputArea = elems.inputArea({
onSubmit: function(args) {
var data = args.data;
var success = args.response.success;
var error = args.response.error;
var title = data.key + ' = ' + data.value;
$loading.appendTo($container);
actions.add({
data: data,
context: context,
response: {
success: function(args) {
var notification = $.extend(true, {} , args.notification, {
interval: 500,
_custom: args._custom
});
cloudStack.ui.notifications.add(
notification,
// Success
function() {
$loading.remove();
elems.tagItem(title, onRemoveItem, data).appendTo($tagArea);
success();
}, {},
// Error
function() {
$loading.remove();
error();
}, {}
);
},
error: function(message) {
$loading.remove();
error();
cloudStack.dialog.notice({ message: message });
}
}
});
}
});
$container.append($title, $inputArea, $tagArea);
// Get data
$loading.appendTo($container);
dataProvider({
context: context,
response: {
success: function(args) {
var data = args.data;
$loading.remove();
$(data).map(function(index, item) {
var key = item.key;
var value = item.value;
var data = { key: key, value: value };
elems.tagItem(key + ' = ' + value, onRemoveItem, data).appendTo($tagArea);
});
},
error: function(message) {
$loading.remove();
$container.find('ul').html(message);
}
}
});
}
});
}(jQuery, cloudStack));