From bac22205a8775f44b628520b32ee28939e1873e1 Mon Sep 17 00:00:00 2001 From: Chris Houseknecht Date: Mon, 4 Nov 2013 04:03:55 +0000 Subject: [PATCH] Fixed form-generator and awRequiredWhen directive to not overlap when setting * on required field labels. Fixed job submission to work with new cloud credential implementation. --- awx/ui/static/js/controllers/Credentials.js | 115 ++++++++++++++++--- awx/ui/static/js/controllers/JobTemplates.js | 33 ++++-- awx/ui/static/js/forms/Credentials.js | 36 ++++-- awx/ui/static/js/forms/JobTemplates.js | 2 +- awx/ui/static/js/helpers/Credentials.js | 13 +-- awx/ui/static/js/helpers/JobSubmission.js | 14 +-- awx/ui/static/js/lists/CloudCredentials.js | 75 ++++++++++++ awx/ui/static/js/lists/Credentials.js | 17 ++- awx/ui/static/js/lists/Projects.js | 3 +- awx/ui/static/lib/ansible/Utilities.js | 6 +- awx/ui/static/lib/ansible/directives.js | 12 +- awx/ui/static/lib/ansible/form-generator.js | 38 +++--- 12 files changed, 280 insertions(+), 84 deletions(-) create mode 100644 awx/ui/static/js/lists/CloudCredentials.js diff --git a/awx/ui/static/js/controllers/Credentials.js b/awx/ui/static/js/controllers/Credentials.js index 5dc5d3f5f7..ae05097723 100644 --- a/awx/ui/static/js/controllers/Credentials.js +++ b/awx/ui/static/js/controllers/Credentials.js @@ -12,7 +12,7 @@ function CredentialsList ($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, CredentialList, GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller, - ClearScope, ProcessErrors, GetBasePath, SelectionInit) + ClearScope, ProcessErrors, GetBasePath, SelectionInit, GetChoices) { ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior //scope. @@ -33,20 +33,45 @@ function CredentialsList ($scope, $rootScope, $location, $log, $routeParams, Res scope.removePostRefresh(); } scope.removePostRefresh = scope.$on('PostRefresh', function() { - // After a refresh, populate the organization name on each row + list.fields.kind.searchOptions = scope.credential_kind_options; + + // Translate the kind value for(var i=0; i < scope.credentials.length; i++) { + /* if (scope.credentials[i].summary_fields.user) { scope.credentials[i].user_username = scope.credentials[i].summary_fields.user.username; } if (scope.credentials[i].summary_fields.team) { scope.credentials[i].team_name = scope.credentials[i].summary_fields.team.name; } + */ + for (var j=0; j < scope.credential_kind_options.length; j++) { + if (scope.credential_kind_options[j].value == scope.credentials[i].kind) { + scope.credentials[i].kind = scope.credential_kind_options[j].label + break; + } + } } }); - SearchInit({ scope: scope, set: 'credentials', list: list, url: defaultUrl }); - PaginateInit({ scope: scope, list: list, url: defaultUrl }); - scope.search(list.iterator); + if (scope.removeChoicesReady) { + scope.removeChoicesReady(); + } + scope.removeChoicesReady = scope.$on('choicesReady', function() { + SearchInit({ scope: scope, set: 'credentials', list: list, url: defaultUrl }); + PaginateInit({ scope: scope, list: list, url: defaultUrl }); + scope.search(list.iterator); + }); + + // Load the list of options for Kind + GetChoices({ + scope: scope, + url: defaultUrl, + field: 'kind', + variable: 'credential_kind_options', + callback: 'choicesReady' + }); + LoadBreadCrumbs(); @@ -84,7 +109,7 @@ function CredentialsList ($scope, $rootScope, $location, $log, $routeParams, Res CredentialsList.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'CredentialList', 'GenerateList', 'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope', 'ProcessErrors', - 'GetBasePath', 'SelectionInit']; + 'GetBasePath', 'SelectionInit', 'GetChoices']; function CredentialsAdd ($scope, $rootScope, $compile, $location, $log, $routeParams, CredentialForm, @@ -171,23 +196,39 @@ function CredentialsAdd ($scope, $rootScope, $compile, $location, $log, $routePa var data = {} for (var fld in form.fields) { - if (scope[fld] === null) { - data[fld] = ""; - } - else { - data[fld] = scope[fld]; + if (fld !== 'access_key' && fld !== 'secret_key' && fld !== 'ssh_username' && + fld !== 'ssh_password') { + if (scope[fld] === null) { + data[fld] = ""; + } + else { + data[fld] = scope[fld]; + } } } if (!Empty(scope.team)) { data.team = scope.team; + data.user = ""; } else { data.user = scope.user; + data.team = ""; } data['kind'] = scope['kind'].value; + switch (data['kind']) { + case 'ssh': + data['username'] = scope['ssh_username']; + data['password'] = scope['ssh_password']; + break; + case 'aws': + data['username'] = scope['access_key']; + data['password'] = scope['secret_key']; + break; + } + if (Empty(data.team) && Empty(data.user)) { Alert('Missing User or Team', 'You must provide either a User or a Team. If this credential will only be accessed by a specific ' + 'user, select a User. To allow a team of users to access this credential, select a Team.', 'alert-danger'); @@ -353,6 +394,29 @@ function CredentialsEdit ($scope, $rootScope, $compile, $location, $log, $routeP scope['owner'] = 'team'; } master['owner'] = scope['owner']; + + for (var i=0; i < scope.credential_kind_options.length; i++) { + if (scope.credential_kind_options[i].value == data.kind) { + scope.kind = scope.credential_kind_options[i]; + break; + } + } + master['kind'] = scope['kind']; + + switch (data.kind) { + case 'aws': + scope['access_key'] = data.username; + scope['secret_key'] = data.password; + master['access_key'] = scope['access_key']; + master['secret_key'] = scope['secret_key']; + break; + case 'ssh': + scope['ssh_username'] = data.username; + scope['ssh_password'] = data.password; + master['ssh_username'] = scope['ssh_username']; + master['ssh_password'] = scope['ssh_password']; + break; + } scope.$emit('credentialLoaded'); }) @@ -373,26 +437,43 @@ function CredentialsEdit ($scope, $rootScope, $compile, $location, $log, $routeP // Save changes to the parent scope.formSave = function() { generator.clearApiErrors(); - + var data = {} for (var fld in form.fields) { - if (scope[fld] === null) { - data[fld] = ""; - } - else { - data[fld] = scope[fld]; + if (fld !== 'access_key' && fld !== 'secret_key' && fld !== 'ssh_username' && + fld !== 'ssh_password') { + if (scope[fld] === null) { + data[fld] = ""; + } + else { + data[fld] = scope[fld]; + } } } + if (!Empty(scope.team)) { data.team = scope.team; + data.user = ""; } else { data.user = scope.user; + data.team = ""; } data['kind'] = scope['kind'].value; + switch (data['kind']) { + case 'ssh': + data['username'] = scope['ssh_username']; + data['password'] = scope['ssh_password']; + break; + case 'aws': + data['username'] = scope['access_key']; + data['password'] = scope['secret_key']; + break; + } + if (Empty(data.team) && Empty(data.user)) { Alert('Missing User or Team', 'You must provide either a User or a Team. If this credential will only be accessed by a specific ' + 'user, select a User. To allow a team of users to access this credential, select a Team.', 'alert-danger'); diff --git a/awx/ui/static/js/controllers/JobTemplates.js b/awx/ui/static/js/controllers/JobTemplates.js index 98d8392202..4d0bbb54a7 100644 --- a/awx/ui/static/js/controllers/JobTemplates.js +++ b/awx/ui/static/js/controllers/JobTemplates.js @@ -82,7 +82,8 @@ JobTemplatesList.$inject = [ '$scope', '$rootScope', '$location', '$log', '$rout function JobTemplatesAdd ($scope, $rootScope, $compile, $location, $log, $routeParams, JobTemplateForm, GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope, - GetBasePath, InventoryList, CredentialList, ProjectList, LookUpInit, md5Setup, ParseTypeChange) + GetBasePath, InventoryList, CredentialList, ProjectList, LookUpInit, + md5Setup, ParseTypeChange) { ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior //scope. @@ -123,23 +124,30 @@ function JobTemplatesAdd ($scope, $rootScope, $compile, $location, $log, $routeP field: 'inventory' }); - LookUpInit({ - url: GetBasePath('credentials') + '?cloud=false', - scope: scope, - form: form, - current_item: null, - list: CredentialList, - field: 'credential' - }); - + // Clone the CredentialList object for use with cloud_credential. Cloning + // and changing properties to avoid collision. + var CloudCredentialList = {}; + jQuery.extend(true, CloudCredentialList, CredentialList); + CloudCredentialList.name = 'cloudcredentials', + CloudCredentialList.iterator = 'cloudcredential', + LookUpInit({ url: GetBasePath('credentials') + '?cloud=true', scope: scope, form: form, current_item: null, - list: CredentialList, + list: CloudCredentialList, field: 'cloud_credential' }); + + LookUpInit({ + url: GetBasePath('credentials') + '?kind=ssh', + scope: scope, + form: form, + current_item: null, + list: CredentialList, + field: 'credential' + }); // Update playbook select whenever project value changes var selectPlaybook = function(oldValue, newValue) { @@ -277,7 +285,8 @@ function JobTemplatesAdd ($scope, $rootScope, $compile, $location, $log, $routeP JobTemplatesAdd.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'JobTemplateForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', 'ClearScope', - 'GetBasePath', 'InventoryList', 'CredentialList', 'ProjectList', 'LookUpInit', 'md5Setup', 'ParseTypeChange' ]; + 'GetBasePath', 'InventoryList', 'CredentialList', 'ProjectList', 'LookUpInit', + 'md5Setup', 'ParseTypeChange' ]; function JobTemplatesEdit ($scope, $rootScope, $compile, $location, $log, $routeParams, JobTemplateForm, diff --git a/awx/ui/static/js/forms/Credentials.js b/awx/ui/static/js/forms/Credentials.js index 42b93da95c..391234cf6b 100644 --- a/awx/ui/static/js/forms/Credentials.js +++ b/awx/ui/static/js/forms/Credentials.js @@ -75,15 +75,15 @@ angular.module('CredentialFormDefinition', []) label: 'Access Key', type: 'text', ngShow: "kind.value == 'aws'", - awRequiredWhen: { variable: "aws_required", init: "false" }, + awRequiredWhen: { variable: "aws_required", init: false }, autocomplete: false, apiField: 'username' }, secret_key: { - label: 'Secrent Key', + label: 'Secret Key', type: 'password', ngShow: "kind.value == 'aws'", - awRequiredWhen: { variable: "aws_required", init: "false" }, + awRequiredWhen: { variable: "aws_required", init: false }, autocomplete: false, ask: false, clear: false, @@ -97,9 +97,9 @@ angular.module('CredentialFormDefinition', []) autocomplete: false }, "password": { - labelBind: 'passwordLabel', + label: 'Password', type: 'password', - ngShow: "kind.value && kind.value !== 'aws'", + ngShow: "kind.value == 'rax' || kind.value == 'scm'", awRequiredWhen: {variable: 'rackspace_required', init: false }, ngChange: "clearPWConfirm('password_confirm')", ask: false, @@ -108,15 +108,37 @@ angular.module('CredentialFormDefinition', []) autocomplete: false }, "password_confirm": { - labelBind: 'passwordConfirmLabel', + label: 'Confirm Password', type: 'password', - ngShow: "kind.value && kind.value !== 'aws'", + ngShow: "kind.value == 'rax' || kind.value == 'scm'", addRequired: false, editRequired: false, awPassMatch: true, associated: 'password', autocomplete: false }, + "ssh_password": { + label: 'SSH Password', + type: 'password', + ngShow: "kind.value == 'ssh'", + ngChange: "clearPWConfirm('password_confirm')", + addRequired: false, + editRequired: false, + ask: true, + clear: true, + associated: 'ssh_password_confirm', + autocomplete: false + }, + "ssh_password_confirm": { + label: 'Confirm SSH Password', + type: 'password', + ngShow: "kind.value == 'ssh'", + addRequired: false, + editRequired: false, + awPassMatch: true, + associated: 'ssh_password', + autocomplete: false + }, "ssh_key_data": { labelBind: 'sshKeyDataLabel', type: 'textarea', diff --git a/awx/ui/static/js/forms/JobTemplates.js b/awx/ui/static/js/forms/JobTemplates.js index a7bc3eaeb6..329ebb969e 100644 --- a/awx/ui/static/js/forms/JobTemplates.js +++ b/awx/ui/static/js/forms/JobTemplates.js @@ -87,7 +87,7 @@ angular.module('JobTemplateFormDefinition', []) type: 'lookup', sourceModel: 'cloud_credential', sourceField: 'name', - ngClick: 'lookUpCredential()', + ngClick: 'lookUpCloudcredential()', addRequired: false, editRequired: false, column: 1 diff --git a/awx/ui/static/js/helpers/Credentials.js b/awx/ui/static/js/helpers/Credentials.js index 2d3fd0708f..a1ffc003d3 100644 --- a/awx/ui/static/js/helpers/Credentials.js +++ b/awx/ui/static/js/helpers/Credentials.js @@ -18,27 +18,20 @@ angular.module('CredentialsHelper', ['Utilities']) // Put things in a default state scope['usernameLabel'] = 'Username'; - scope['passwordLabel'] = 'Password'; - scope['passwordConfirmLabel'] = 'Confirm Password'; scope['aws_required'] = false; scope['rackspace_required'] = false; scope['sshKeyDataLabel'] = 'SSH Private Key'; - form.fields['password'].clear = true; - form.fields['password'].ask = true; - + // Apply kind specific settings switch(scope['kind'].value) { case 'aws': scope['aws_required'] = true; break; case 'rax': - scope['rackspace_required'] = true; - form.fields['password'].ask = false; + scope['rackspace_required'] = true; break; - case 'ssh': + case 'ssh': scope['usernameLabel'] = 'SSH Username'; - scope['passwordLabel'] = 'SSH Password'; - scope['passwordConfirmLabel'] = 'Confirm SSH Password'; break; case 'scm': scope['sshKeyDataLabel'] = 'SCM Private Key'; diff --git a/awx/ui/static/js/helpers/JobSubmission.js b/awx/ui/static/js/helpers/JobSubmission.js index 4fcc8e3fc0..94ef5d9926 100644 --- a/awx/ui/static/js/helpers/JobSubmission.js +++ b/awx/ui/static/js/helpers/JobSubmission.js @@ -8,8 +8,8 @@ angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'Credential 'LookUpHelper', 'ProjectFormDefinition', 'JobSubmissionHelper', 'GroupFormDefinition', 'GroupsHelper' ]) .factory('PromptPasswords', ['CredentialForm', 'JobTemplateForm', 'GroupForm', 'ProjectsForm', '$compile', 'Rest', '$location', 'ProcessErrors', - 'GetBasePath', 'Alert', - function(CredentialForm, JobTemplateForm, ProjectsForm, GroupForm, $compile, Rest, $location, ProcessErrors, GetBasePath, Alert) { + 'GetBasePath', 'Alert', 'Empty', + function(CredentialForm, JobTemplateForm, ProjectsForm, GroupForm, $compile, Rest, $location, ProcessErrors, GetBasePath, Alert, Empty) { return function(params) { var scope = params.scope; @@ -73,7 +73,7 @@ angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'Credential value_supplied = true; } }); - if (passwords.length == 0 || value_supplied) { + if (Empty(passwords) || passwords.length == 0 || value_supplied) { Rest.setUrl(start_url); Rest.post(pswd) .success( function(data, status, headers, config) { @@ -97,7 +97,7 @@ angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'Credential } } - if (passwords.length > 0) { + if (passwords && passwords.length > 0) { // Prompt for passwords html += "
\n"; html += (extra_html) ? extra_html : ""; @@ -441,9 +441,9 @@ angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'Credential Rest.get() .success( function(data, status, headers, config) { if (data.can_update) { - var extra_html = "
Starting inventory update for " + group_name + - ". Please provide the " + group_source + " credentials:
\n"; - scope.$emit('InventorySubmit', data.passwords_needed_to_update, extra_html); + //var extra_html = "
Starting inventory update for " + group_name + + // ". Please provide the " + group_source + " credentials:
\n"; + scope.$emit('InventorySubmit', data.passwords_needed_to_update); } else { Alert('Permission Denied', 'You do not have access to run the update. Please contact your system administrator.', diff --git a/awx/ui/static/js/lists/CloudCredentials.js b/awx/ui/static/js/lists/CloudCredentials.js new file mode 100644 index 0000000000..1a129dfe5c --- /dev/null +++ b/awx/ui/static/js/lists/CloudCredentials.js @@ -0,0 +1,75 @@ +/********************************************* + * Copyright (c) 2013 AnsibleWorks, Inc. + * + * CloudCredentials.js + * List view object for Credential data model. + * + * @dict + */ +angular.module('CloudCredentialsListDefinition', []) + .value( + 'CloudCredentialList', { + + name: 'cloudcredentials', + iterator: 'cloudcredential', + selectTitle: 'Add Cloud Credentials', + editTitle: 'Cloud Credentials', + selectInstructions: '

Select existing credentials by clicking each credential or checking the related checkbox. When finished, click the blue ' + + 'Select button, located bottom right.

Create a brand new credential by clicking the green Create New button.

', + index: true, + hover: true, + + fields: { + name: { + key: true, + label: 'Name' + }, + description: { + label: 'Description', + excludeModal: false + }, + team: { + label: 'Team', + ngBind: 'credential.team_name', + sourceModel: 'team', + sourceField: 'name', + excludeModal: true + }, + user: { + label: 'User', + ngBind: 'credential.user_username', + sourceModel: 'user', + sourceField: 'username', + excludeModal: true + } + }, + + actions: { + add: { + icon: 'icon-plus', + label: 'Create New', + mode: 'all', // One of: edit, select, all + ngClick: 'addCredential()', + "class": 'btn-success btn-xs', + awToolTip: 'Create a new credential' + } + }, + + fieldActions: { + edit: { + ngClick: "editCredential(\{\{ credential.id \}\})", + icon: 'icon-edit', + label: 'Edit', + "class": 'btn-xs btn-default', + awToolTip: 'View/Edit credential' + }, + + "delete": { + ngClick: "deleteCredential(\{\{ credential.id \}\},'\{\{ credential.name \}\}')", + icon: 'icon-trash', + label: 'Delete', + "class": 'btn-xs btn-danger', + awToolTip: 'Delete credential' + } + } + }); diff --git a/awx/ui/static/js/lists/Credentials.js b/awx/ui/static/js/lists/Credentials.js index 385ce23fdd..004b2be5b5 100644 --- a/awx/ui/static/js/lists/Credentials.js +++ b/awx/ui/static/js/lists/Credentials.js @@ -26,20 +26,31 @@ angular.module('CredentialsListDefinition', []) }, description: { label: 'Description', - excludeModal: true + excludeModal: false }, + kind: { + label: 'Type', + searchType: 'select', + searchOptions: [], // will be set by Options call to credentials resource + excludeModal: true, + nosort: true + } + /* team: { label: 'Team', ngBind: 'credential.team_name', sourceModel: 'team', - sourceField: 'name' + sourceField: 'name', + excludeModal: true }, user: { label: 'User', ngBind: 'credential.user_username', sourceModel: 'user', - sourceField: 'username' + sourceField: 'username', + excludeModal: true } + */ }, actions: { diff --git a/awx/ui/static/js/lists/Projects.js b/awx/ui/static/js/lists/Projects.js index 7cd30f6bdd..517e4936eb 100644 --- a/awx/ui/static/js/lists/Projects.js +++ b/awx/ui/static/js/lists/Projects.js @@ -41,7 +41,8 @@ angular.module('ProjectsListDefinition', []) last_updated: { label: 'Last Updated', type: 'date', - excludeModal: true + excludeModal: true, + searchable: false } }, diff --git a/awx/ui/static/lib/ansible/Utilities.js b/awx/ui/static/lib/ansible/Utilities.js index b626bc529a..1b5585945d 100644 --- a/awx/ui/static/lib/ansible/Utilities.js +++ b/awx/ui/static/lib/ansible/Utilities.js @@ -448,8 +448,9 @@ angular.module('Utilities',['RestServices', 'Utilities']) Rest.options() .success( function(data, status, headers, config) { var choices = data.actions.GET[field].choices + // including 'name' property so list can be used by search for (var i=0; i < choices.length; i++) { - scope[variable].push({ label: choices[i][1], value: choices[i][0] }); + scope[variable].push({ label: choices[i][1], value: choices[i][0], name: choices[i][1]}); } if (callback) { scope.$emit(callback); @@ -490,7 +491,8 @@ angular.module('Utilities',['RestServices', 'Utilities']) /* Empty() * - * Test if a value is 'empty'. Returns true if val is null | '' | undefined + * Test if a value is 'empty'. Returns true if val is null | '' | undefined. + * Only works on non-Ojbect types. * */ .factory('Empty', [ function() { diff --git a/awx/ui/static/lib/ansible/directives.js b/awx/ui/static/lib/ansible/directives.js index ba92facb45..5dfb7136e3 100644 --- a/awx/ui/static/lib/ansible/directives.js +++ b/awx/ui/static/lib/ansible/directives.js @@ -107,26 +107,26 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Hos function checkIt () { var viewValue = elm.val(); - var txt, label; + var txt, label, p, l, s; validity = true; if ( scope[attrs.awRequiredWhen] && (elm.attr('required') == null || elm.attr('required') == undefined) ) { $(elm).attr('required','required'); if ($(elm).hasClass('lookup')) { - $(elm).parent().parent().parent().find('label').addClass('prepend-asterisk'); + $(elm).parent().parent().parent().find('label').first().addClass('prepend-asterisk'); } else { - $(elm).parent().parent().find('label').addClass('prepend-asterisk'); + $(elm).parent().parent().find('label').first().addClass('prepend-asterisk'); } } else if (!scope[attrs.awRequiredWhen]) { elm.removeAttr('required'); if ($(elm).hasClass('lookup')) { - label = $(elm).parent().parent().parent().find('label'); + label = $(elm).parent().parent().parent().find('label').first(); + label.removeClass('prepend-asterisk'); } else { - label = $(elm).parent().parent().find('label'); + $(elm).parent().parent().find('label').first().removeClass('prepend-asterisk'); } - label.removeClass('prepend-asterisk'); } if (scope[attrs.awRequiredWhen] && (viewValue == undefined || viewValue == null || viewValue == '')) { validity = false; diff --git a/awx/ui/static/lib/ansible/form-generator.js b/awx/ui/static/lib/ansible/form-generator.js index e93dd1185f..c955a061bf 100644 --- a/awx/ui/static/lib/ansible/form-generator.js +++ b/awx/ui/static/lib/ansible/form-generator.js @@ -8,11 +8,11 @@ * */ -angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies']) +angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies', 'Utilities']) .factory('GenerateForm', [ '$location', '$cookieStore', '$compile', 'SearchWidget', 'PaginateWidget', 'Attr', 'Icon', 'Column', - 'NavigationLink', 'HelpCollapse', 'Button', 'DropDown', + 'NavigationLink', 'HelpCollapse', 'Button', 'DropDown', 'Empty', function($location, $cookieStore, $compile, SearchWidget, PaginateWidget, Attr, Icon, Column, NavigationLink, HelpCollapse, Button, - DropDown) { + DropDown, Empty) { return { setForm: function(form) { @@ -102,18 +102,20 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies']) // Prepend an asterisk to required field label $('.form-control[required], input[type="radio"][required]').each(function() { - var label = $(this).parent().parent().find('label'); - if ($(this).attr('type') == 'radio') { - label = $(this).parent().parent().parent().find('label').first(); - } - if (label) { - var span = label.find('span'); - if (span && !span.hasClass('prepend-asterisk')) { - span.addClass('prepend-asterisk'); - } - else if (!label.hasClass('prepend-asterisk') && !label.find('.prepend-asterisk')) { - label.addClass('prepend-asterisk'); - } + if ( Empty($(this).attr('aw-required-when')) ) { + var label = $(this).parent().parent().find('label').first(); + if ($(this).attr('type') == 'radio') { + label = $(this).parent().parent().parent().find('label').first(); + } + if (label) { + var span = label.find('span').first(); + if (span && !span.hasClass('prepend-asterisk')) { + span.addClass('prepend-asterisk'); + } + else if (!label.hasClass('prepend-asterisk') && !label.find('.prepend-asterisk')) { + label.addClass('prepend-asterisk'); + } + } } }); @@ -463,7 +465,7 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies']) html += (field.labelBind) ? "ng-bind=\"" + field.labelBind + "\" " : ""; html += "for=\"" + fld + '">'; html += (field.icon) ? this.icon(field.icon) : ""; - html += "" + field.label + '' + "\n"; + html += "" + field.label + '' + "\n"; html += (field.awPopOver && field.awPopOverRight) ? this.attr(field, 'awPopOver', fld) : ""; html += "\n"; html += "
'; html += (field.icon) ? this.icon(field.icon) : ""; - html += '' + field.label + '' + "\n"; + html += '' + field.label + '' + "\n"; html += (field.awPopOver && field.awPopOverRight) ? this.attr(field, 'awPopOver', fld) : ""; html += "
\n"; html += "
'; html += (field.awPopOver) ? this.attr(field, 'awPopOver', fld) : ""; - html += '' + field.label + '' + "\n"; + html += '' + field.label + '' + "\n"; html += "