From a764c9a09dbb59554c698a418500413f8d13f048 Mon Sep 17 00:00:00 2001 From: bfederle Date: Tue, 26 Jun 2012 13:30:36 -0700 Subject: [PATCH] CS-15287 Support validation on edit detail view Original patch by: olga.smola reviewed-by: brian --- ui/css/cloudstack3.css | 6 ++ ui/scripts/accounts.js | 33 ++++++----- ui/scripts/configuration.js | 24 +++++--- ui/scripts/templates.js | 12 ++-- ui/scripts/ui/widgets/detailView.js | 90 ++++++++++++++++++++++------- 5 files changed, 119 insertions(+), 46 deletions(-) diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index 21d1c6af373..c061c439429 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -1641,6 +1641,12 @@ div.details div.detail-group td.value input[type=text] { width: 93%; } +div.details .main-groups label.error { + position: absolute; + right: 10%; + top: 6px; +} + /*** Actions*/ div.detail-group.actions { padding: 0; diff --git a/ui/scripts/accounts.js b/ui/scripts/accounts.js index 6d67d7a332c..9b565c62d90 100644 --- a/ui/scripts/accounts.js +++ b/ui/scripts/accounts.js @@ -510,7 +510,8 @@ { name: { label: 'label.name', - isEditable: true + isEditable: true, + validation: { required: true } } }, { @@ -812,16 +813,16 @@ label: 'label.new.password', isPassword: true, validation: { required: true }, - id: 'newPassword' + id: 'newPassword' }, - 'password-confirm': { - label: 'label.confirm.password', - validation: { - required: true, - equalTo: '#newPassword' - }, - isPassword: true - } + 'password-confirm': { + label: 'label.confirm.password', + validation: { + required: true, + equalTo: '#newPassword' + }, + isPassword: true + } } }, action: function(args) { @@ -975,7 +976,8 @@ { username: { label: 'label.name', - isEditable: true + isEditable: true, + validation: { required: true } } }, { @@ -993,15 +995,18 @@ domain: { label: 'label.domain' }, email: { label: 'label.email', - isEditable: true + isEditable: true, + validation: { required: true, email: true } }, firstname: { label: 'label.first.name', - isEditable: true + isEditable: true, + validation: { required: true } }, lastname: { label: 'label.last.name', - isEditable: true + isEditable: true, + validation: { required: true } }, timezone: { label: 'label.timezone', diff --git a/ui/scripts/configuration.js b/ui/scripts/configuration.js index fc1b3a4c3cd..7cc12ac447d 100644 --- a/ui/scripts/configuration.js +++ b/ui/scripts/configuration.js @@ -281,14 +281,16 @@ { name: { label: 'label.name', - isEditable: true + isEditable: true, + validation: { required: true } } }, { id: { label: 'label.id' }, displaytext: { label: 'label.description', - isEditable: true + isEditable: true, + validation: { required: true } }, storagetype: { label: 'label.storage.type' }, cpunumber: { label: 'label.num.cpu.cores' }, @@ -611,14 +613,16 @@ { name: { label: 'label.name', - isEditable: true + isEditable: true, + validation: { required: true } } }, { id: { label: 'label.id' }, displaytext: { label: 'label.description', - isEditable: true + isEditable: true, + validation: { required: true } }, systemvmtype: { label: 'label.system.vm.type', @@ -907,14 +911,16 @@ { name: { label: 'label.name', - isEditable: true + isEditable: true, + validation: { required: true } } }, { id: { label: 'label.id' }, displaytext: { label: 'label.description', - isEditable: true + isEditable: true, + validation: { required: true } }, iscustomized: { label: 'label.custom.disk.size', @@ -1697,14 +1703,16 @@ { name: { label: 'label.name', - isEditable: true + isEditable: true, + validation: { required: true } } }, { id: { label: 'label.id' }, displaytext: { label: 'label.description', - isEditable: true + isEditable: true, + validation: { required: true } }, state: { label: 'label.state' }, guestiptype: { diff --git a/ui/scripts/templates.js b/ui/scripts/templates.js index e49b94ff52c..5a13af9fc6f 100644 --- a/ui/scripts/templates.js +++ b/ui/scripts/templates.js @@ -575,7 +575,8 @@ { name: { label: 'label.name', - isEditable: true + isEditable: true, + validation: { required: true } } }, { @@ -584,7 +585,8 @@ zoneid: { label: 'label.zone.id' }, displaytext: { label: 'label.description', - isEditable: true + isEditable: true, + validation: { required: true } }, hypervisor: { label: 'label.hypervisor' }, templatetype: { label: 'label.type' }, @@ -1110,7 +1112,8 @@ { name: { label: 'label.name', - isEditable: true + isEditable: true, + validation: { required: true } } }, { @@ -1119,7 +1122,8 @@ zoneid: { label: 'label.zone.id' }, displaytext: { label: 'label.description', - isEditable: true + isEditable: true, + validation: { required: true } }, isready: { label: 'state.Ready', converter:cloudStack.converters.toBooleanText }, status: { label: 'label.status' }, diff --git a/ui/scripts/ui/widgets/detailView.js b/ui/scripts/ui/widgets/detailView.js index 68520e08a23..68f09276667 100644 --- a/ui/scripts/ui/widgets/detailView.js +++ b/ui/scripts/ui/widgets/detailView.js @@ -320,6 +320,18 @@ } }); }; + + var removeEditForm = function() { + // Remove Edit form + var $form = $detailView.find('form'); + if ($form.size()) { + var $mainGroups = $form.find('div.main-groups').detach(); + $form.parent('div').append($mainGroups); + $form.remove(); + } + //Remove required labels + $detailView.find('span.field-required').remove(); + } // Put in original values var cancelEdits = function($inputs, $editButton) { @@ -334,6 +346,8 @@ $editButton.fadeOut('fast', function() { $editButton.remove(); }); + + removeEditForm(); }; var applyEdits = function($inputs, $editButton) { @@ -375,6 +389,7 @@ notificationArgs, function() {}, [] ); replaceListViewItem($detailView, data); + removeEditForm(); } else { $loading.appendTo($detailView); cloudStack.ui.notifications.add( @@ -383,6 +398,7 @@ replaceListViewItem($detailView, data); convertInputs($inputs); + removeEditForm(); $loading.remove(); }, [], function() { @@ -401,17 +417,24 @@ } }; - $editButton.click(function() { - var $inputs = $detailView.find('input, select'); + $editButton.click(function() { + var $inputs = $detailView.find('input, select'), + $form = $detailView.find('form'); if ($(this).hasClass('done')) { - applyEdits($inputs, $editButton); + if (!$form.valid()) { + // Ignore hidden field validation + if ($form.find('input.error:visible, select.error:visible').size()) { + return false; + } + } + applyEdits($inputs, $editButton); } else { // Cancel cancelEdits($inputs, $editButton); } }); - - $detailView.find('td.value span').each(function() { + + $detailView.find('td.value span').each(function() { var name = $(this).closest('tr').data('detail-view-field'); var $value = $(this); if (!$value.data('detail-view-is-editable')) return true; @@ -420,6 +443,7 @@ var selectData = $value.data('detail-view-editable-select'); var isBoolean = $value.data('detail-view-editable-boolean'); var data = !isBoolean ? cloudStack.sanitizeReverse($value.html()) : $value.data('detail-view-boolean-value'); + var rules = $value.data('validation-rules') ? $value.data('validation-rules') : {}; $value.html(''); @@ -461,13 +485,36 @@ name: name, type: 'text', value: data - }).data('original-value', data) + }).data('original-value', data) ); } + + if (rules && rules.required) { + var $required = $('').addClass('field-required').text(' *'); + $value.parent('td.value').prev('td.name').append($required); + } return true; }); + if ($detailView.find('td.value span:data(detail-view-is-editable)').size()) { + var $detailsEdit = $detailView.find('div.main-groups').detach(), + $detailsEditForm = $('
').append($detailsEdit); + + $detailView.find('div.details').append($detailsEditForm); + } + + // Setup form validation + $detailView.find('form').validate(); + $detailView.find('form').find('input, select').each(function() { + var data = $(this).parent('span').data('validation-rules'); + if (data) { + $(this).rules('add', data); + } else { + $(this).rules('add', {}); + } + }); + return $detailView; } }; @@ -683,23 +730,26 @@ //??? /* - if("pollAgainIfValueIsIn" in value) { - if ((content in value.pollAgainIfValueIsIn) && (value.pollAgainFn != null)) { - //poll again - var intervalKey = setInterval(function() { - var toClearInterval = value.pollAgainFn(context); - if(toClearInterval == true) { - clearInterval(intervalKey); - $('.detail-view .toolbar .button.refresh').click(); //click Refresh button to refresh detailView - } - }, 2000); - } - } - */ - + if("pollAgainIfValueIsIn" in value) { + if ((content in value.pollAgainIfValueIsIn) && (value.pollAgainFn != null)) { + //poll again + var intervalKey = setInterval(function() { + var toClearInterval = value.pollAgainFn(context); + if(toClearInterval == true) { + clearInterval(intervalKey); + $('.detail-view .toolbar .button.refresh').click(); //click Refresh button to refresh detailView + } + }, 2000); + } + } + */ + $name.html(_l(value.label)); $value.html(_s(content)); + // Set up validation metadata + $value.data('validation-rules', value.validation); + // Set up editable metadata if(typeof(value.isEditable) == 'function') $value.data('detail-view-is-editable', value.isEditable());