From 5e94b0d12e50c6ba3a7defd00aeb04c79286f14f Mon Sep 17 00:00:00 2001 From: bfederle Date: Mon, 23 Jul 2012 13:26:52 -0700 Subject: [PATCH 1/5] Implement tag UI widget Create UI for handling new tag API. This currently supports the detail view and multi-edit To enable tags UI, add a 'tags' object to each detailView/multiEdit configuration: tabs: { ... details: { ... tags: { actions: { add: function(args) { setTimeout(function() { args.response.success({ notification: { desc: 'Add tags for instance', poll: testData.notifications.testPoll } }); }, 500); }, remove: function(args) { args.response.success({ notification: { desc: 'Remove tags for instance', poll: testData.notifications.testPoll } }); } }, dataProvider: function(args) { args.response.success({ data: [ { id: '1', key: 'user', value: 'brian' }, { id: '2', key: 'region', value: 'usa' } ] }); } } ... Conflicts: ui/css/cloudstack3.css ui/scripts/ui/widgets/tagger.js --- ui/css/cloudstack3.css | 198 ++++++++++++++++++++++++++++ ui/scripts/ui/widgets/detailView.js | 48 ++++++- ui/scripts/ui/widgets/multiEdit.js | 12 +- ui/scripts/ui/widgets/tagger.js | 197 +++++++++++++++++++++++++++ 4 files changed, 446 insertions(+), 9 deletions(-) create mode 100644 ui/scripts/ui/widgets/tagger.js diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index ef81697e464..e405fbf4fcb 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -8952,6 +8952,204 @@ div.panel.ui-dialog div.list-view div.fixed-header { 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-chart { width: 100%; diff --git a/ui/scripts/ui/widgets/detailView.js b/ui/scripts/ui/widgets/detailView.js index b1e9a68c8a9..086f66d3e23 100644 --- a/ui/scripts/ui/widgets/detailView.js +++ b/ui/scripts/ui/widgets/detailView.js @@ -287,10 +287,14 @@ * @param callback */ edit: function($detailView, args) { + $detailView.addClass('edit-mode'); + if ($detailView.find('.button.done').size()) return false; // 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 id = $detailView.data('view-args').id; var $editButton = $('
').addClass('button done').html(_l('label.apply')).hide(); @@ -302,9 +306,14 @@ $detailView.find('.ui-tabs-panel .detail-group.actions') ).fadeIn(); + $detailView.find('.tagger').removeClass('readonly'); + $detailView.find('.tagger').find('input[type=text]').val(''); + var convertInputs = function($inputs) { // Save and turn back into labels $inputs.each(function() { + if ($(this).closest('.tagger').size()) return true; + var $input = $(this); var $value = $input.closest('td.value span'); @@ -328,8 +337,12 @@ }; var removeEditForm = function() { + $detailView.removeClass('edit-mode'); + // Remove Edit form - var $form = $detailView.find('form'); + var $form = $detailView.find('form').filter(function() { + return !$(this).closest('.tagger').size(); + }); if ($form.size()) { var $mainGroups = $form.find('div.main-groups').detach(); $form.parent('div').append($mainGroups); @@ -337,11 +350,15 @@ } //Remove required labels $detailView.find('span.field-required').remove(); - } + $detailView.find('.tagger').addClass('readonly'); + + }; // Put in original values var cancelEdits = function($inputs, $editButton) { $inputs.each(function() { + if ($(this).closest('.tagger').size()) return true; + var $input = $(this); var $value = $input.closest('td.value span'); var originalValue = $input.data('original-value'); @@ -424,8 +441,12 @@ }; $editButton.click(function() { - var $inputs = $detailView.find('input, select'), - $form = $detailView.find('form'); + var $inputs = $detailView.find('input, select').filter(function() { + return !$(this).closest('.tagger').size(); + }); + var $form = $detailView.find('form').filter(function() { + return !$(this).closest('.tagger').size(); + }); if ($(this).hasClass('done')) { if (!$form.valid()) { @@ -438,6 +459,8 @@ } else { // Cancel cancelEdits($inputs, $editButton); } + + return true; }); $detailView.find('td.value span').each(function() { @@ -511,8 +534,11 @@ } // Setup form validation - $detailView.find('form').validate(); - $detailView.find('form').find('input, select').each(function() { + var $form = $detailView.find('form').filter(function() { + return !$(this).closest('.tagger').size(); + }); + $form.validate(); + $form.find('input, select').each(function() { var data = $(this).parent('span').data('validation-rules'); if (data) { $(this).rules('add', data); @@ -934,6 +960,14 @@ actionFilter: actionFilter }).appendTo($tabContent); + if (tabs.tags) { + $('
').tagger( + $.extend(true, {}, tabs.tags, { + context: $detailView.data('view-args').context + }) + ).appendTo($tabContent).addClass('readonly'); + } + return true; }, error: function() { diff --git a/ui/scripts/ui/widgets/multiEdit.js b/ui/scripts/ui/widgets/multiEdit.js index 64d94f6dd90..89d260300eb 100644 --- a/ui/scripts/ui/widgets/multiEdit.js +++ b/ui/scripts/ui/widgets/multiEdit.js @@ -332,10 +332,16 @@ after: function(args) { var $loading = $('
').addClass('loading-overlay').prependTo($dataItem); performAction({ data: args.data, complete: function() { - $multi.multiEdit('refresh'); + $multi.trigger('refresh'); } }); } }); + + if (options.tags) { + $(':ui-dialog').append( + $('
').addClass('multi-edit-tags').tagger(options.tags) + ); + } } }) ); @@ -652,6 +658,7 @@ $.fn.multiEdit = function(args) { var dataProvider = args.dataProvider; var multipleAdd = args.multipleAdd; + var tags = args.tags; var $multi = $('
').addClass('multi-edit').appendTo(this); var $multiForm = $('
').appendTo($multi); var $inputTable = $('').addClass('multi-edit').appendTo($multiForm); @@ -918,7 +925,8 @@ context: $.extend(true, {}, context, this._context), ignoreEmptyFields: ignoreEmptyFields, preFilter: actionPreFilter, - listView: listView + listView: listView, + tags: tags } ).appendTo($dataBody); }); diff --git a/ui/scripts/ui/widgets/tagger.js b/ui/scripts/ui/widgets/tagger.js new file mode 100644 index 00000000000..b6d2f0a0dea --- /dev/null +++ b/ui/scripts/ui/widgets/tagger.js @@ -0,0 +1,197 @@ +(function($, cloudStack) { + var elems = { + inputArea: function(args) { + var $form = $('').addClass('tag-input'); + var $keyField = $('
').addClass('field key'); + var $keyLabel = $('