From edc2df1d733a3b59822180335884b6809f89d92a Mon Sep 17 00:00:00 2001 From: Brian Federle Date: Wed, 16 Nov 2011 16:19:17 -0800 Subject: [PATCH] -Correctly refresh properties on detail view action -Support async edit action -Make action notification section optional -Add save button to apply detail view edit -Fix indentation, button spacing for multi-edit items --- ui/css/cloudstack3.css | 57 ++++++-- ui/images/bg-gradients.png | Bin 5615 -> 5662 bytes ui/index-test.html | 2 +- ui/index.jsp | 2 +- ui/scripts-test/domains.js | 6 +- ui/scripts-test/storage.js | 7 +- ui/scripts/ui-custom/enableStaticNAT.js | 2 +- ui/scripts/ui/multiEdit.js | 2 +- ui/scripts/ui/widgets/detailView.js | 165 +++++++++++++++--------- 9 files changed, 158 insertions(+), 85 deletions(-) diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index 5f104eb5970..6b981c74170 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -122,6 +122,14 @@ table tbody td.actions { vertical-align: middle; } +table tbody td.actions input { + /*+placement:shift 10px -6px;*/ + position: relative; + left: 10px; + top: -6px; + margin: 11px 0 0px; +} + table tbody tr { border-left: 1px solid #C4C5C5; border-right: 1px solid #C4C5C5; @@ -796,7 +804,8 @@ div.notification-box .button.close:hover { /*** Corner alert*/ div.notification.corner-alert { background: #EBE8E8; - width: 260px; + display: inline-block; + min-width: 260px; height: 70px; position: absolute; text-indent: 10px; @@ -1013,14 +1022,6 @@ div.list-view td.state.off { top: 2px; } -.project-view .ui-tabs ul { - /*+placement:shift 0px 0px;*/ - position: relative; - left: 0px; - top: 0px; - height: 39px; -} - .ui-tabs .info { background: #EFEFEF; width: 91%; @@ -1209,6 +1210,41 @@ div.list-view td.state.off { padding: 20px 0px 17px; } +.detail-view .button.done { + display: inline-block; + color: #FFFFFF; + font-size: 12px; + font-weight: bold; + /*+border-radius:10px;*/ + -moz-border-radius: 10px; + -webkit-border-radius: 10px; + -khtml-border-radius: 10px; + border-radius: 10px 10px 10px 10px; + /*+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; + /*+box-shadow:0px 1px 4px #ADADAD;*/ + -moz-box-shadow: 0px 1px 4px #ADADAD; + -webkit-box-shadow: 0px 1px 4px #ADADAD; + -o-box-shadow: 0px 1px 4px #ADADAD; + box-shadow: 0px 1px 4px #ADADAD; + cursor: pointer; + margin: 0 0 0 12px; + padding: 9px 20px; + background: url(../images/bg-gradients.png) 0px -221px; +} + +.detail-view .button.done:hover { + background-position: 0px -950px; + /*+box-shadow:inset 0px 1px 3px #000000;*/ + -moz-box-shadow: inset 0px 1px 3px #000000; + -webkit-box-shadow: inset 0px 1px 3px #000000; + -o-box-shadow: inset 0px 1px 3px #000000; + box-shadow: inset 0px 1px 3px #000000; +} + div.group-multiple div.detail-group table { margin-top: -12px; } @@ -1778,7 +1814,7 @@ div.detail-group.actions td { } .project-view .ui-tabs div.ui-tabs-panel { - background: #DBDDDF; + background: #C7C7C7 0px 9px; } #browser div.panel .shadow { @@ -5109,6 +5145,7 @@ div.panel.ui-dialog div.list-view div.fixed-header { border: none; width: 100%; margin: 0; + text-indent: 37px; } .multi-edit .data .data-body .data-item .expandable-listing tr.odd td { diff --git a/ui/images/bg-gradients.png b/ui/images/bg-gradients.png index 23e8a81ad9837e4321a23b3977e829ec97bc4e04..977bced185c014a3fab6882fc46ab47e2ce62884 100644 GIT binary patch delta 2940 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 F{|#TmJ+lA+ diff --git a/ui/index-test.html b/ui/index-test.html index bb2c84c61b2..c90975d02ba 100644 --- a/ui/index-test.html +++ b/ui/index-test.html @@ -374,7 +374,7 @@
    -
  • 1Zone Type
  • +
  • 1Select Type
  • 2Setup Zone
diff --git a/ui/index.jsp b/ui/index.jsp index 8f682175d2c..e2fb02d51bb 100644 --- a/ui/index.jsp +++ b/ui/index.jsp @@ -374,7 +374,7 @@
    -
  • 1Zone Type
  • +
  • 1Select Type
  • 2Setup Zone
diff --git a/ui/scripts-test/domains.js b/ui/scripts-test/domains.js index fc0cdc257de..722efc57b83 100644 --- a/ui/scripts-test/domains.js +++ b/ui/scripts-test/domains.js @@ -61,7 +61,7 @@ messages: { notification: function(args) { - return 'Created domain' + return 'Created domain'; } }, @@ -78,10 +78,6 @@ validation: { required: true } } } - }, - - notification: { - poll: testData.notifications.testPoll } } }, diff --git a/ui/scripts-test/storage.js b/ui/scripts-test/storage.js index 4ffb07bf8ef..d3fc8691109 100644 --- a/ui/scripts-test/storage.js +++ b/ui/scripts-test/storage.js @@ -403,10 +403,9 @@ edit: { label: 'Edit volume details', action: function(args) { - args.response.success(); - }, - notification: { - poll: testData.notifications.testPoll + setTimeout(function() { + args.response.success(); + }, 500); } }, snapshot: { diff --git a/ui/scripts/ui-custom/enableStaticNAT.js b/ui/scripts/ui-custom/enableStaticNAT.js index 4b52d4d5d20..03e060743b7 100644 --- a/ui/scripts/ui-custom/enableStaticNAT.js +++ b/ui/scripts/ui-custom/enableStaticNAT.js @@ -53,7 +53,7 @@ title: 'Select VM for Static NAT', buttons: [ { - text: 'Done', + text: 'Apply', 'class': 'ok', click: function() { var complete = args.complete; diff --git a/ui/scripts/ui/multiEdit.js b/ui/scripts/ui/multiEdit.js index 5af4e9cd8e7..005325f4db9 100644 --- a/ui/scripts/ui/multiEdit.js +++ b/ui/scripts/ui/multiEdit.js @@ -535,7 +535,7 @@ title: args.add.label, buttons: [ { - text: 'Done', + text: 'Apply', 'class': 'ok', click: function() { $dataList.fadeOut(function() { diff --git a/ui/scripts/ui/widgets/detailView.js b/ui/scripts/ui/widgets/detailView.js index c7737858ee8..a95fdec34c1 100644 --- a/ui/scripts/ui/widgets/detailView.js +++ b/ui/scripts/ui/widgets/detailView.js @@ -60,7 +60,8 @@ */ standard: function($detailView, args, additional) { var action = args.actions[args.actionName]; - var notification = action.notification; + var notification = action.notification ? + action.notification : {}; var messages = action.messages; var messageArgs = { name: $detailView.find('tr.name td.value').html() }; var id = args.id; @@ -98,6 +99,10 @@ var $form = options.$form; + // Set loading appearance + var $loading = $('
').addClass('loading-overlay'); + $detailView.prepend($loading); + action.action({ data: data, _custom: _custom, @@ -109,11 +114,6 @@ args = args ? args : {}; notification._custom = args._custom; - // Set loading appearance - $detailView.prepend( - $('
').addClass('loading-overlay') - ); - if (additional && additional.success) additional.success(args); // Setup notification @@ -121,12 +121,15 @@ notification, function(args) { if ($detailView.is(':visible')) { - $detailView.find('.loading-overlay').remove(); + $loading.remove(); // Refresh actions loadTabContent( $detailView.find('.detail-group:visible'), - $detailView.data('view-args') + $detailView.data('view-args'), + { + newData: args.data + } ); } @@ -203,70 +206,102 @@ * @param callback */ edit: function($detailView, args) { + if ($detailView.find('.button.done').size()) return false; + // Convert value TDs var $inputs = $detailView.find('input[type=text], select'); + var action = args.actions[args.actionName]; + var id = $detailView.data('view-args').id; + var $editButton = $('
').addClass('button done').html('Apply') + .hide() + .appendTo( + $detailView.find('.ui-tabs-panel:visible') + ) + .fadeIn('fast'); - if ($inputs.size()) { - $inputs.animate({ opacity: 0.5 }, 500); - - var data = {}; + var convertInputs = function($inputs) { + // Save and turn back into labels $inputs.each(function() { - data[$(this).attr('name')] = $(this).val(); - }); + var $input = $(this); + var $value = $input.closest('td.value'); - args.actions[args.actionName].action({ - data: data, - _custom: $detailView.data('_custom'), - context: $detailView.data('view-args').context, - response: { + if ($input.is('input[type=text]')) + $value.html( + $input.attr('value') + ); + else if ($input.is('select')) { + $value.html( + $input.find('option:selected').html() + ); + $value.data('detail-view-selected-option', $input.find('option:selected').val()); + } + }); + }; + + var applyEdits = function($inputs, $editButton) { + if ($inputs.size()) { + $inputs.animate({ opacity: 0.5 }, 500); + + var data = {}; + $inputs.each(function() { + data[$(this).attr('name')] = $(this).val(); + }); + + $editButton.fadeOut('fast', function() { + $editButton.remove(); + }); + + var $loading = $('
').addClass('loading-overlay'); + + action.action({ data: data, - success: function(data) { - // Save and turn back into labels - $inputs.each(function() { - var $input = $(this); - var $value = $input.closest('td.value'); - - if ($input.is('input[type=text]')) - $value.html( - $input.attr('value') - ); - else if ($input.is('select')) { - $value.html( - $input.find('option:selected').html() - ); - $value.data('detail-view-selected-option', $input.find('option:selected').val()); - } - }); - - var id = $detailView.data('view-args').id - - addNotification( - { + _custom: $detailView.data('_custom'), + context: $detailView.data('view-args').context, + response: { + data: data, + success: function(data) { + var notificationArgs = { section: id, desc: 'Changed item properties' - }, - function(data) { - }, - [] - ); - }, - error: function(args) { - // Put in original values on error - $inputs.each(function() { - var $input = $(this); - var $value = $input.closest('td.value'); - var originalValue = $input.data('original-value'); + }; - $value.html(originalValue); - }); + if (!action.notification) { + convertInputs($inputs); + addNotification( + notificationArgs, function(data) {}, [] + ); + } else { + $loading.appendTo($detailView); + addNotification( + $.extend(true, {}, action.notification, notificationArgs), + function(args) { + convertInputs($inputs); + $loading.remove(); + }, [] + ); + } + }, + error: function(args) { + // Put in original values on error + $inputs.each(function() { + var $input = $(this); + var $value = $input.closest('td.value'); + var originalValue = $input.data('original-value'); - if (args.message) cloudStack.dialog.notice({ message: args.message }); + $value.html(originalValue); + }); + + if (args.message) cloudStack.dialog.notice({ message: args.message }); + } } - } - }); + }); + } + }; - return $detailView; - } + $editButton.click(function() { + var $inputs = $detailView.find('input[type=text], select'); + applyEdits($inputs, $editButton); + }); $detailView.find('td.value').each(function() { var name = $(this).closest('tr').data('detail-view-field'); @@ -587,8 +622,10 @@ * * @param $tabContent {jQuery} tab div to load content into * @param args {object} Detail view data + * @param options {object} Additional options */ - var loadTabContent = function($tabContent, args) { + var loadTabContent = function($tabContent, args, options) { + if (!options) options = {}; $tabContent.html(''); var targetTabID = $tabContent.data('detail-view-tab-id'); @@ -622,10 +659,14 @@ return dataProvider({ tab: targetTabID, id: args.id, - jsonObj: args.jsonObj, + jsonObj: options.newData ? $.extend(true, {}, args.jsonObj, options.newData) : args.jsonObj, context: args.context, response: { success: function(args) { + if (options.newData) { + $.extend(args.data, options.newData); + } + if (args._custom) { $detailView.data('_custom', args._custom); }