On 05/14/2014 04:44 AM, Crístian Viana wrote:
Most forms contain fields that must be filled before they are
submitted.
Some of them submit the missing data and display an error message when
something goes wrong, and some of them do not allow the user to submit
them if some data is missing.
Make the forms behavior consistent by enabling their buttons only
when the required data is entered.
Internally, the page tags all required fields with the class "required"
and whenever any of their values change, they are checke. If any
required field is empty, the submit button becomses disabled; otherwise,
it becomes enabled.
Fix GitHub issue #317 ("Inconsistent button status when adding or
creating new resources").
Signed-off-by: Crístian Viana <vianac(a)linux.vnet.ibm.com>
---
ui/css/theme-default/login-window.css | 4 --
ui/js/src/kimchi.guest_edit_main.js | 15 +++++++
ui/js/src/kimchi.login_window.js | 36 +++++++--------
ui/js/src/kimchi.storagepool_add_main.js | 75 +++++++++++++++++++++++---------
ui/js/src/kimchi.template_edit_main.js | 20 +++++++++
ui/pages/guest-edit.html.tmpl | 6 +--
ui/pages/i18n.html.tmpl | 6 ---
ui/pages/login-window.html.tmpl | 8 ++--
ui/pages/storagepool-add.html.tmpl | 6 +--
ui/pages/template-edit.html.tmpl | 8 ++--
10 files changed, 117 insertions(+), 67 deletions(-)
diff --git a/ui/css/theme-default/login-window.css
b/ui/css/theme-default/login-window.css
index 8a21090..d021be6 100644
--- a/ui/css/theme-default/login-window.css
+++ b/ui/css/theme-default/login-window.css
@@ -62,10 +62,6 @@
width: 290px;
}
-#login-window .login-panel .msg-required {
- color: red;
-}
-
#login-window .login-panel button {
font-size: 18px;
height: 40px;
diff --git a/ui/js/src/kimchi.guest_edit_main.js b/ui/js/src/kimchi.guest_edit_main.js
index 0236e2d..bb4ee51 100644
--- a/ui/js/src/kimchi.guest_edit_main.js
+++ b/ui/js/src/kimchi.guest_edit_main.js
@@ -202,6 +202,21 @@ kimchi.guest_edit_main = function() {
kimchi.retrieveVM(kimchi.selectedGuest, initContent);
+ var updateSubmitButtonStatus = function() {
+ var valid = true;
+ guestEditForm.find('input.required').each(function(index, field) {
+ if (field.value === '') {
+ valid = false;
+ return;
+ }
+ });
+
+ saveButton.prop('disabled', !valid);
+ };
+
+ guestEditForm.find('input.required').on('input propertychange',
+ updateSubmitButtonStatus);
+
var submitForm = function(event) {
$(saveButton).prop('disabled', true);
var data=$('#form-guest-edit-general').serializeObject();
diff --git a/ui/js/src/kimchi.login_window.js b/ui/js/src/kimchi.login_window.js
index 9c06a50..52394a5 100644
--- a/ui/js/src/kimchi.login_window.js
+++ b/ui/js/src/kimchi.login_window.js
@@ -30,26 +30,25 @@ kimchi.login_main = function() {
$(opt).prop('selected', selectedLanguage === k);
}
+ var updateSubmitButtonStatus = function() {
+ var valid = true;
+ $('#form-login').find('input.required').each(function(index,
field) {
+ if (field.value === '') {
+ valid = false;
+ return;
+ }
+ });
+
+ $('#btn-login').prop('disabled', !valid);
+ }
+
+ $('#form-login').find('input.required').on('input
propertychange',
+ updateSubmitButtonStatus);
+
There's some problem with this new function. And there is no need to
replace the current validateNonEmpty() function.
In the current validateNonEmpty() function, several checks are processed:
1)
If user name field is empty, then
put cursor in user name box
Else if password field is empty, then
put cursor in password box
Else
put cursor on log in button
2)
If some field is empty, a message will show to tell user the field is
required.
$('#language').on('change', function() {
kimchi.topic('languageChanged').publish($(this).val());
});
- var validateNonEmpty = function(idsArray) {
- for(var i = 0; i < idsArray.length; i++) {
- var id = idsArray[i];
- if (!$('#' + id).val()) {
- $('#' + id +
'-msg').text(i18n['KCHAUTH6002E']);
- placeCursor(id);
- return false;
- }
- else {
- $('#' + id + '-msg').empty();
- }
- }
-
- return true;
- };
-
var placeCursor = function(id) {
if (id && $('#' + id).size() > 0) {
$('#' + id).focus();
@@ -66,11 +65,6 @@ kimchi.login_main = function() {
};
var login = function(event) {
-
- if (!validateNonEmpty(['username', 'password'])) {
- return false;
- }
-
$('#btn-login').text(i18n['KCHAUTH6002M']).prop('disabled',
true);
var userName = $('#username').val();
diff --git a/ui/js/src/kimchi.storagepool_add_main.js
b/ui/js/src/kimchi.storagepool_add_main.js
index 86dbe7f..5356985 100644
--- a/ui/js/src/kimchi.storagepool_add_main.js
+++ b/ui/js/src/kimchi.storagepool_add_main.js
@@ -122,6 +122,18 @@ kimchi.initStorageAddPage = function() {
});
});
+ var updateSubmitButtonStatus = function() {
+ var valid = true;
+ $('#form-pool-add').find('input.required').each(function(index,
field) {
+ if (field.value === '') {
+ valid = false;
+ return;
+ }
+ });
+
+ $('#pool-doAdd').prop('disabled', !valid);
+ };
+
Adam is working on the global form validation item, so you can leave
this function alone and work on other feature currently.
$('#poolTypeInputId').change(function() {
var poolObject = {'dir': ".path-section", 'netfs':
'.nfs-section',
'iscsi': '.iscsi-section', 'scsi':
'.scsi-section',
@@ -134,7 +146,49 @@ kimchi.initStorageAddPage = function() {
$(value).addClass('tmpl-html');
}
});
+
+ switch (selectType) {
+ case 'dir':
+ $('#pathId').addClass('required');
+
+ $('#nfsserverId').removeClass('required');
+ $('#nfspathId').removeClass('required');
+ $('#iscsiserverId').removeClass('required');
+ break;
+ case 'netfs':
+ $('#nfsserverId').addClass('required');
+ $('#nfspathId').addClass('required');
+
+ $('#pathId').removeClass('required');
+ $('#iscsiserverId').removeClass('required');
+ break;
+ case 'iscsi':
+ $('#iscsiserverId').addClass('required');
+
+ $('#pathId').removeClass('required');
+ $('#nfsserverId').removeClass('required');
+ $('#nfspathId').removeClass('required');
+ break;
+ case 'scsi':
+ $('#pathId').removeClass('required');
+ $('#nfsserverId').removeClass('required');
+ $('#nfspathId').removeClass('required');
+ $('#iscsiserverId').removeClass('required');
+ break;
+ case 'logical':
+ $('#pathId').removeClass('required');
+ $('#nfsserverId').removeClass('required');
+ $('#nfspathId').removeClass('required');
+ $('#iscsiserverId').removeClass('required');
+ break;
+ }
+
+ updateSubmitButtonStatus();
});
+
+ $('#form-pool-add').find('input').on('input
propertychange',
+ updateSubmitButtonStatus);
+
$('#authId').click(function() {
if ($(this).prop("checked")) {
$('.authenticationfield').removeClass('tmpl-html');
@@ -150,10 +204,6 @@ kimchi.initStorageAddPage = function() {
kimchi.validateForm = function() {
var name = $('#poolId').val();
var poolType = $("#poolTypeInputId").val();
- if ('' === name) {
- kimchi.message.error.code('KCHPOOL6001E');
- return false;
- }
if (name.indexOf("/")!=-1) {
kimchi.message.error.code('KCHPOOL6004E');
return false;
@@ -173,10 +223,6 @@ kimchi.validateForm = function() {
kimchi.validateDirForm = function () {
var path = $('#pathId').val();
- if ('' === path) {
- kimchi.message.error.code('KCHPOOL6002E');
- return false;
- }
if (!/(^\/.*)$/.test(path)) {
kimchi.message.error.code('KCHAPI6003E');
return false;
@@ -190,10 +236,6 @@ kimchi.validateNfsForm = function () {
if (!kimchi.validateServer(nfsserver)) {
return false;
}
- if ('' === nfspath) {
- kimchi.message.error.code('KCHPOOL6003E');
- return false;
- }
if (!/((\/([0-9a-zA-Z-_\.]+)))$/.test(nfspath)) {
kimchi.message.error.code('KCHPOOL6005E');
return false;
@@ -203,22 +245,13 @@ kimchi.validateNfsForm = function () {
kimchi.validateIscsiForm = function() {
var iscsiServer = $('#iscsiserverId').val();
- var iscsiTarget = $('#iscsiTargetId').val();
if (!kimchi.validateServer(iscsiServer)) {
return false;
}
- if ('' === iscsiTarget) {
- kimchi.message.error.code('KCHPOOL6007E');
- return false;
- }
return true;
};
kimchi.validateServer = function(serverField) {
- if ('' === serverField) {
- kimchi.message.error.code('KCHPOOL6008E');
- return false;
- }
if(!kimchi.isServer(serverField)) {
kimchi.message.error.code('KCHPOOL6009E');
return false;
diff --git a/ui/js/src/kimchi.template_edit_main.js
b/ui/js/src/kimchi.template_edit_main.js
index f0f4718..e552bf9 100644
--- a/ui/js/src/kimchi.template_edit_main.js
+++ b/ui/js/src/kimchi.template_edit_main.js
@@ -104,6 +104,26 @@ kimchi.template_edit_main = function() {
});
});
+ var updateSubmitButtonStatus = function() {
+ var valid = true;
+ templateEditForm.find('input.required').each(function(index, field) {
+ if (field.value === '') {
+ valid = false;
+ return;
+ }
+ });
+
+ if (valid) {
+ $('#tmpl-edit-button-save').removeAttr('disabled');
+ }
+ else {
+ $('#tmpl-edit-button-save').attr('disabled',
'disabled');
+ }
+ };
+
+ templateEditForm.find('input.required').on('input propertychange',
+ updateSubmitButtonStatus);
+
$('#tmpl-edit-button-cancel').on('click', function() {
kimchi.window.close();
});
diff --git a/ui/pages/guest-edit.html.tmpl b/ui/pages/guest-edit.html.tmpl
index 96d907e..d35ad7a 100644
--- a/ui/pages/guest-edit.html.tmpl
+++ b/ui/pages/guest-edit.html.tmpl
@@ -49,7 +49,7 @@
</div>
<div class="guest-edit-wrapper-controls">
<input id="guest-edit-id-textbox"
- name="name" type="text" />
+ name="name" type="text"
class="required" />
</div>
</div>
<div>
@@ -62,7 +62,7 @@
<input
id="guest-edit-cores-textbox"
name="cpus"
- type="text" />
+ type="text" class="required" />
</div>
</div>
<div>
@@ -74,7 +74,7 @@
<div class="guest-edit-wrapper-controls">
<input id="guest-edit-memory-textbox"
name="memory"
- type="text" />
+ type="text" class="required" />
</div>
</div>
<div>
diff --git a/ui/pages/i18n.html.tmpl b/ui/pages/i18n.html.tmpl
index 98da828..814825f 100644
--- a/ui/pages/i18n.html.tmpl
+++ b/ui/pages/i18n.html.tmpl
@@ -33,7 +33,6 @@
<script>
var i18n = {
'KCHAUTH6001E': "$_("The username or password you entered is
incorrect. Please try again.")",
- 'KCHAUTH6002E': "$_("This field is required.")",
'KCHAUTH6001M': "$_("Log in")",
'KCHAUTH6002M': "$_("Logging in...")",
@@ -158,14 +157,9 @@ var i18n = {
'KCHPOOL6004M': "$_("SCSI Fibre Channel")",
'KCHPOOL6005M': "$_("No SCSI adapters found.")",
- 'KCHPOOL6001E': "$_("The storage pool name can not be
blank.")",
- 'KCHPOOL6002E': "$_("The storage pool path can not be
blank.")",
- 'KCHPOOL6003E': "$_("NFS server mount path can not be
blank.")",
'KCHPOOL6004E': "$_("Invalid storage pool name. It should not
contain '/'.")",
'KCHPOOL6005E': "$_("Invalid NFS mount path.")",
'KCHPOOL6006E': "$_("No logical device selected.")",
- 'KCHPOOL6007E': "$_("The iSCSI target can not be
blank.")",
- 'KCHPOOL6008E': "$_("Server name can not be blank.")",
'KCHPOOL6009E': "$_("This is not a valid Server Name or IP.
please, modify it.")",
'KCHPOOL6010M': "$_("Looking for available partitions
...")",
'KCHPOOL6011M': "$_("No available partitions
found.")",
diff --git a/ui/pages/login-window.html.tmpl b/ui/pages/login-window.html.tmpl
index 3e451c4..1cd9e83 100644
--- a/ui/pages/login-window.html.tmpl
+++ b/ui/pages/login-window.html.tmpl
@@ -34,15 +34,13 @@
<div class="content login-panel">
<form id="form-login" action="/login"
method="POST">
<div class="row">
- <input type="text" id="username"
name="username" required="required" placeholder="$_("User
Name")" />
- <div id="username-msg"
class="msg-required"></div>
+ <input type="text" id="username"
name="username" class="required" placeholder="$_("User
Name")" />
</div>
<div class="row">
- <input type="password" id="password"
name="password" required="required"
placeholder="$_("Password")" />
- <div id="password-msg"
class="msg-required"></div>
+ <input type="password" id="password"
name="password" class="required"
placeholder="$_("Password")" />
</div>
<div class="row">
- <button id="btn-login" class="btn-normal">$_("Log
in")</button>
+ <button id="btn-login" class="btn-normal"
disabled="true">$_("Log in")</button>
Suggest not
change this as mentioned above.
</div>
</form>
</div>
diff --git a/ui/pages/storagepool-add.html.tmpl b/ui/pages/storagepool-add.html.tmpl
index 977db66..6ce1343 100644
--- a/ui/pages/storagepool-add.html.tmpl
+++ b/ui/pages/storagepool-add.html.tmpl
@@ -36,7 +36,7 @@
<p class="text-help">
$_("The name used to identify the storage pools, and
it should not be empty.")
</p>
- <input id="poolId" required="required"
type="text" class="text storage-base-input-width"
name="name">
+ <input id="poolId" type="text"
class="text storage-base-input-width required" name="name">
</div>
</section>
<section class="form-section">
@@ -60,7 +60,7 @@
$_("The path of the Storage Pool. Each Storage
Pool must have a unique path.")</p>
<p class="text-help">
$_("Kimchi will try to create the directory when
it does not already exist in your system.")</p>
- <input id="pathId" type="text"
class="text storage-base-input-width">
+ <input id="pathId" type="text"
class="text storage-base-input-width required">
</div>
<div class="clear"></div>
</section>
@@ -152,7 +152,7 @@
</div>
<footer>
<div class="btn-group">
- <button id="pool-doAdd" class="btn-normal">
+ <button id="pool-doAdd" class="btn-normal"
disabled="disabled">
<span
class="text">$_("Create")</span>
</button>
</div>
diff --git a/ui/pages/template-edit.html.tmpl b/ui/pages/template-edit.html.tmpl
index 434d938..46b7058 100644
--- a/ui/pages/template-edit.html.tmpl
+++ b/ui/pages/template-edit.html.tmpl
@@ -36,7 +36,7 @@
<label
for="template-edit-id-textbox">$_("Name")</label>
</div>
<div class="template-edit-wrapper-controls">
- <input id="template-edit-id-textbox"
name="name" type="text" />
+ <input id="template-edit-id-textbox"
name="name" type="text" class="required" />
</div>
</div>
<div>
@@ -60,7 +60,7 @@
<label
for="template-edit-cpu-textbox">$_("CPU Number")</label>
</div>
<div class="template-edit-wrapper-controls">
- <input id="template-edit-cpu-textbox"
name="cpus" type="text" />
+ <input id="template-edit-cpu-textbox"
name="cpus" type="text" class="required" />
</div>
</div>
<div>
@@ -68,7 +68,7 @@
<label
for="template-edit-memory-textbox">$_("Memory")</label>
</div>
<div class="template-edit-wrapper-controls">
- <input id="template-edit-memory-textbox"
name="memory" type="text" />
+ <input id="template-edit-memory-textbox"
name="memory" type="text" class="required" />
</div>
</div>
<div>
@@ -76,7 +76,7 @@
<label
for="template-edit-disk-textbox">$_("Disk (GB)")</label>
</div>
<div class="template-edit-wrapper-controls">
- <input id="template-edit-disk-textbox"
name="disks" type="text" />
+ <input id="template-edit-disk-textbox"
name="disks" type="text" class="required" />
</div>
</div>
</fieldset>