AC-970 no longer highlighting currently focused form field with red. Field is hightlighted in red when an error immediately on error detection. This includes Angular errors and custom errors.

This commit is contained in:
chris Houseknecht 2014-01-23 23:49:16 -05:00
parent 3d228b2955
commit c52f98e9ac
15 changed files with 83 additions and 138 deletions

View File

@ -93,17 +93,18 @@ function OrganizationsAdd ($scope, $rootScope, $compile, $location, $log, $route
//scope.
// Inject dynamic view
var form = GenerateForm;
var scope = form.inject(OrganizationForm, {mode: 'add', related: false});
var generator = GenerateForm;
var form = OrganizationForm;
var scope = generator.inject(form, {mode: 'add', related: false});
var base = $location.path().replace(/^\//,'').split('/')[0];
var defaultUrl = GetBasePath('organizations');
form.reset();
generator.reset();
LoadBreadCrumbs();
// Save
scope.formSave = function() {
form.clearApiErrors();
generator.clearApiErrors();
Wait('start');
var url = GetBasePath(base);
url += (base != 'organizations') ? $routeParams['project_id'] + '/organizations/' : '';
@ -121,9 +122,8 @@ function OrganizationsAdd ($scope, $rootScope, $compile, $location, $log, $route
}
})
.error( function(data, status, headers, config) {
Wait('stop');
ProcessErrors(scope, data, status, OrganizationForm,
{ hdr: 'Error!', msg: 'Failed to add new organization. Post returned status: ' + status });
ProcessErrors(scope, data, status, form,
{ hdr: 'Error!', msg: 'Failed to add new organization. Post returned status: ' + status });
});
};

View File

@ -1,3 +1,14 @@
/************************************
* Copyright (c) 2014 AnsibleWorks, Inc.
*
*
* Permissions.js
*
* Controller functions for Permissions model.
*
*/
'use strict';
function PermissionsList ($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, PermissionList,
GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller,

View File

@ -479,14 +479,14 @@ dd {
padding-right: 10px;
}
/* Outline required fields in Red when focused */
.form-control[required]:focus {
border-color: rgba(204, 0, 0, 0.8);
outline: 0;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 5px rgba(204, 0, 0, 0.6);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 5px rgba(204, 0, 0, 0.6);
}
/* Outline required fields in Red when there is an error */
.form-control.ng-dirty.ng-invalid, .form-control.ng-dirty.ng-invalid:focus {
border-color: rgba(204, 0, 0, 0.8);
outline: 0;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 5px rgba(204, 0, 0, 0.6);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 5px rgba(204, 0, 0, 0.6);
}
/* For some reason TB 3 RC1 does not provide an input-mini */

View File

@ -6,6 +6,8 @@
* User authentication functions
*/
'use strict';
angular.module('AuthService', ['ngCookies', 'Utilities'])
.factory('Authorization', ['$http', '$rootScope', '$location', '$cookieStore', 'GetBasePath',
function($http, $rootScope, $location, $cookieStore, GetBasePath) {

View File

@ -9,6 +9,8 @@
*
*/
'use strict';
angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'PromptDialog'])
.factory('SortNodes', [ function() {

View File

@ -4,6 +4,9 @@
* Generic accessor for Ansible Commander services
*
*/
'use strict';
angular.module('RestServices',['ngCookies','AuthService'])
.factory('Rest', ['$http','$rootScope','$cookieStore', '$q', 'Authorization',
function($http, $rootScope, $cookieStore, $q, Authorization) {

View File

@ -7,6 +7,9 @@
* duration set in config.js
*
*/
'use strict';
angular.module('TimerService', ['ngCookies', 'Utilities'])
.factory('Timer', ['$rootScope', '$cookieStore', '$location', 'GetBasePath', 'Empty',
function($rootScope, $cookieStore, $location, GetBasePath, Empty) {

View File

@ -5,6 +5,9 @@
* Utility functions
*
*/
'use strict';
angular.module('Utilities',['RestServices', 'Utilities'])
.factory('ClearScope', [ function() {
@ -137,6 +140,7 @@ angular.module('Utilities',['RestServices', 'Utilities'])
if (form.fields[field].realName) {
if (data[form.fields[field].realName]) {
scope[field + '_api_error'] = data[form.fields[field]][0];
scope[form.name + '_form'][form.fields[field].realName].$setValidity('apiError', false);
fieldErrors = true;
}
}
@ -144,12 +148,15 @@ angular.module('Utilities',['RestServices', 'Utilities'])
if (data[field]) {
scope[form.fields[field].sourceModel + '_' + form.fields[field].sourceField + '_api_error'] =
data[field][0];
scope[form.name + '_form'][form.fields[field].sourceModel + '_' + form.fields[field].sourceField].$setValidity('apiError', false);
fieldErrors = true;
}
}
else {
if (data[field]) {
console.log('setting api error: ' + form.name + '_form.' + field);
scope[field + '_api_error'] = data[field][0];
scope[form.name + '_form'][field].$setValidity('apiError', false);
fieldErrors = true;
}
}

View File

@ -7,6 +7,8 @@
*
*/
'use strict';
angular.module('ApiLoader', ['ngCookies'])
.factory('LoadBasePaths', ['$http', '$rootScope', '$cookieStore', 'ProcessErrors',
function($http, $rootScope, $cookieStore, ProcessErrors) {

View File

@ -5,8 +5,9 @@
*
*/
var INTEGER_REGEXP = /^\-?\d*$/;
'use strict';
var INTEGER_REGEXP = /^\-?\d*$/;
angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'JobsHelper'])
// awpassmatch: Add to password_confirm field. Will test if value
@ -108,7 +109,7 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job
function checkIt () {
var viewValue = elm.val();
var txt, label;
validity = true;
var validity = true;
if ( scope[attrs.awRequiredWhen] && (elm.attr('required') == null || elm.attr('required') == undefined) ) {
$(elm).attr('required','required');
if ($(elm).hasClass('lookup')) {

View File

@ -4,21 +4,22 @@
* Custom filters
*
*/
'use strict';
angular.module('AWFilters', [])
//
// capitalize -capitalize the first letter of each word
//
.filter('capitalize', function() {
.filter('capitalize', [ function() {
return function(input) {
if (input) {
var values = input.replace(/\_/g,' ').split(" ");
var result = "";
for (i = 0; i < values.length; i++){
for (var i = 0; i < values.length; i++){
result += values[i].charAt(0).toUpperCase() + values[i].substr(1) + ' ';
}
result = result.trim();
return result;
return result.trim();
}
}
});
}]);

View File

@ -8,6 +8,8 @@
*
*/
'use strict';
angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies', 'Utilities'])
.factory('GenerateForm', ['$rootScope', '$location', '$cookieStore', '$compile', 'SearchWidget', 'PaginateWidget', 'Attr',
'Icon', 'Column', 'NavigationLink', 'HelpCollapse', 'Button', 'DropDown', 'Empty', 'SelectIcon',
@ -195,7 +197,7 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies', 'Utilities'])
},
applyDefaults: function() {
for (fld in this.form.fields) {
for (var fld in this.form.fields) {
if (this.form.fields[fld]['default'] || this.form.fields[fld]['default'] == 0) {
if (this.form.fields[fld].type == 'select' && this.scope[fld + '_options']) {
this.scope[fld] = this.scope[fld + '_options'][this.form.fields[fld]['default']];
@ -223,23 +225,27 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies', 'Utilities'])
if (f.type == 'checkbox_group') {
for (var i=0; i < f.fields.length; i++) {
scope[f.name] = '';
scope[f.name + '_api_error'] = '';
scope[f.fields[i].name] = '';
scope[f.fields[i].name + '_api_error'] = '';
scope[form.name + '_form'][f.fields[i].name].$setValidity('apiError', true);
}
}
else {
scope[fld] = '';
scope[fld + '_api_error'] = '';
scope[fld + '_api_error'] = '';
}
if (f.sourceModel) {
scope[f.sourceModel + '_' + f.sourceField] = '';
scope[f.sourceModel + '_' + f.sourceField + '_api_error'] = '';
scope[form.name + '_form'][f.sourceModel + '_' + f.sourceField].$setValidity('apiError', true);
}
if (f.type == 'lookup' && scope[form.name + '_form'][f.sourceModel + '_' + f.sourceField]) {
scope[form.name + '_form'][f.sourceModel + '_' + f.sourceField].$setPristine();
scope[form.name + '_form'][f.sourceModel + '_' + f.sourceField].$setValidity('apiError', true);
}
if (scope[form.name + '_form'][fld]) {
scope[form.name + '_form'][fld].$setPristine();
scope[form.name + '_form'][fld].$setValidity('apiError', true);
}
if (f.chkPass && scope[form.name + '_form'][fld]) {
scope[form.name + '_form'][fld].$setValidity('complexity', true);
@ -528,19 +534,6 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies', 'Utilities'])
//text fields
if (field.type == 'text' || field.type == 'password' || field.type == 'email') {
//html += "<div class=\"label-text " + getLabelWidth();
//html += (field.labelClass) ? " " + field.labelClass : "";
//html += "\" ";
//html += (field.labelNGClass) ? "ng-class=\"" + field.labelNGClass + "\" " : "";
//html += ">\n";
//html += (field.awPopOver && !field.awPopOverRight) ? this.attr(field, 'awPopOver', fld) : "";
//html += "<label class=\"control-label\" ";
//html += (field.labelBind) ? "ng-bind=\"" + field.labelBind + "\" " : "";
//html += "for=\"" + fld + '">';
//html += (field.icon) ? this.icon(field.icon) : "";
//html += "<span class=\"label-text\">" + field.label + '</span></label>' + "\n";
//html += (field.awPopOver && field.awPopOverRight) ? this.attr(field, 'awPopOver', fld) : "";
//html += "</div>\n";
html += label();
@ -665,26 +658,6 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies', 'Utilities'])
//textarea fields
if (field.type == 'textarea') {
/*if (field.label !== false) {
html += "<div class=\"label-text " + getLabelWidth();
html += (field.labelClass) ? " " + field.labelClass : "";
html += "\" ";
html += (field.labelNGClass) ? "ng-class=\"" + field.labelNGClass + "\" " : "";
html += ">\n";
html += (field.awPopOver && !field.awPopOverRight) ? this.attr(field, 'awPopOver', fld) : "";
html += "<label class=\"control-label\" ";
html += (field.labelBind) ? "ng-bind=\"" + field.labelBind + "\" " : "";
html += "for=\"" + fld + "\">";
html += field.label + '</label>' + "\n";
html += (field.awPopOver && field.awPopOverRight) ? this.attr(field, 'awPopOver', fld) : "";
html += "</div>\n";
html += "<div ";
html += (field.controlNGClass) ? "ng-class=\"" + field.controlNGClass + "\" " : "";
html += "class=\"" + getFieldWidth() + "\"";
html += ">\n";
}
*/
html += label();
@ -731,21 +704,6 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies', 'Utilities'])
//select field
if (field.type == 'select') {
/*html += "<div class=\"label-text " + getLabelWidth();
html += (field.labelClass) ? " " + field.labelClass : "";
html += "\" ";
html += (field.labelNGClass) ? "ng-class=\"" + field.labelNGClass + "\" " : "";
html += ">\n";
html += (field.awPopOver) ? this.attr(field, 'awPopOver', fld) : "";
html += "<label class=\"control-label\" for=\"" + fld + '">';
html += field.label + '</label>' + "\n";
html += "</div>\n";
html += "<div ";
html += (field.controlNGClass) ? "ng-class=\"" + field.controlNGClass + "\" " : "";
html += "class=\"" + getFieldWidth() + "\"";
html += ">\n";
*/
html += label();
html += "<div ";
@ -788,17 +746,6 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies', 'Utilities'])
//number field
if (field.type == 'number') {
/*html += "<label class=\"control-label " + getLabelWidth();
html += " for=\"" + fld + '">';
html += (field.awPopOver) ? this.attr(field, 'awPopOver', fld) : "";
html += field.label + '</label>' + "\n";
html += "<div ";
html += (field.controlNGClass) ? "ng-class=\"" + field.controlNGClass + "\" " : "";
html += "class=\"" + getFieldWidth() + "\"";
html += ">\n";
// Use 'text' rather than 'number' so that our integer directive works correctly
html += (field.slider) ? "<div class=\"slider\" id=\"" + fld + "-slider\"></div>\n" : "";
*/
html += label();
@ -880,17 +827,6 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies', 'Utilities'])
//checkbox
if (field.type == 'checkbox') {
//html += "<div class=\"label-text " + getLabelWidth();
//html += (field.labelClass) ? " " + field.labelClass : "";
//html += "\" ";
//html += (field.labelNGClass) ? "ng-class=\"" + field.labelNGClass + "\" " : "";
//html += ">\n";
//html += "</div>\n";
//html += "<div ";
//html += (field.controlNGClass) ? "ng-class=\"" + field.controlNGClass + "\" " : "";
//html += "class=\"" + getFieldWidth() + "\"";
//html += ">\n";
if (horizontal) {
var fldWidth = getFieldWidth();
@ -987,22 +923,7 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies', 'Utilities'])
//lookup type fields
if (field.type == 'lookup' && (field.excludeMode == undefined || field.excludeMode != options.mode)) {
/*
html += "<div class=\"label-text " + getLabelWidth();
html += (field.labelClass) ? " " + field.labelClass : "";
html += "\" ";
html += (field.labelNGClass) ? "ng-class=\"" + field.labelNGClass + "\" " : "";
html += "id=\"" + this.form.name + "_" + fld + "_lookup\" ";
html += ">\n";
html += (field.awPopOver) ? this.attr(field, 'awPopOver', fld) : "";
html += "<label class=\"control-label\" for=\"" + fld + '">';
html += field.label + '</label>' + "\n";
html += "</div>\n";
html += "<div ";
html += (field.controlNGClass) ? "ng-class=\"" + field.controlNGClass + "\" " : "";
html += "class=\"" + getFieldWidth() + "\"";
html += ">\n";
*/
html += label();
html += "<div ";
@ -1080,8 +1001,8 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies', 'Utilities'])
getActions: function(options) {
// Use to add things like Activity Stream to a detail page
html = "<div class=\"list-actions\">\n";
for (action in this.form.actions) {
var html = "<div class=\"list-actions\">\n";
for (var action in this.form.actions) {
if (this.form.actions[action].mode == 'all' || this.form.actions[action].mode == options.mode) {
html += this.button({ btn: this.form.actions[action], action: action, toolbar: true });
}
@ -1090,24 +1011,10 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies', 'Utilities'])
return html;
},
/*
activityCrumbs: function() {
// Breadcrumbs for activity stream widget
// Make the links clickable using ng-click function so we can first remove the stream widget.
html = '';
html += "<div class=\"nav-path\">\n";
html += "<ul class=\"breadcrumb\">\n";
html += "<li ng-repeat=\"crumb in breadcrumbs\"><a href=\"\" ng-click=\"{{ crumb.ngClick }}\">{{ crumb.title | capitalize }}</a></li>\n";
html += "<li class=\"active\">";
html += this.form.editTitle;
html += "</li>\n</ul>\n</div>\n";
return html;
},
*/
breadCrumbs: function(options, navigation) {
var html = '';
var html = '';
html += "<div class=\"nav-path\">\n";
html += "<ul class=\"breadcrumb\">\n";
html += "<li ng-repeat=\"crumb in breadcrumbs\"><a href=\"{{ '#' + crumb.path }}\">{{ crumb.title | capitalize }}</a></li>\n";
@ -1190,7 +1097,7 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies', 'Utilities'])
if (this.form.statusActions) {
html += "<div class=\"list-actions\">\n";
var act;
for (action in this.form.statusActions) {
for (var action in this.form.statusActions) {
act = this.form.statusActions[action];
html += this.button({ btn: act, action: action, toolbar: true });
}
@ -1241,7 +1148,7 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies', 'Utilities'])
html += (options.mode == 'edit') ? this.form.editTitle : this.form.addTitle;
if (this.has('titleActions')) {
html += "<div class=\"title-actions pull-right\">\n";
for (btn in this.form.titleActions) {
for (var btn in this.form.titleActions) {
html += this.button({ btn: this.form.titleActions[btn], action: btn, toolbar: true });
}
html += "</div>\n";
@ -1442,7 +1349,7 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies', 'Utilities'])
}
if ((!this.modal && this.form.items)) {
for (itm in this.form.items) {
for (var itm in this.form.items) {
html += "<div class=\"well form-items\">\n";
html += SearchWidget({ iterator: this.form.items[itm].iterator, template: this.form.items[itm], mini: false, label: 'Filter Events'});
html += "<div class=\"item-count pull-right\">Viewing" + " \{\{ " + this.form.items[itm].iterator + "Page + 1 \}\} of " +
@ -1485,7 +1392,7 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies', 'Utilities'])
//
var idx = 1;
var form = this.form;
html = "<div id=\"" + this.form.name + "-collapse-" + idx + "\" class=\"jqui-accordion\">\n";
var html = "<div id=\"" + this.form.name + "-collapse-" + idx + "\" class=\"jqui-accordion\">\n";
for (var itm in form.related) {
if (form.related[itm].type == 'collection') {
html += "<h3 class=\"" + itm + "_collapse\">" + form.related[itm].title + "<h3>\n";
@ -1561,7 +1468,7 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies', 'Utilities'])
// Row level actions
html += "<td class=\"actions\">";
for (act in form.related[itm].fieldActions) {
for (var act in form.related[itm].fieldActions) {
var fAction = form.related[itm].fieldActions[act];
html += "<a ";
html += (fAction.href) ? "href=\"" + fAction.href + "\" " : "";

View File

@ -7,6 +7,8 @@
*
*/
'use strict';
angular.module('GeneratorHelpers', ['GeneratorHelpers'])
.factory('Attr', function() {
@ -386,7 +388,7 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
html += "<div class=\"nav-path\">\n";
html += "<ul class=\"breadcrumb\" id=\"breadcrumb-list\">\n";
html += "<li ng-repeat=\"crumb in breadcrumbs\"><a href=\"{{ '#' + crumb.path }}\">{{ crumb.title | capitalize }}</a></li>\n";
html += "<li ng-repeat=\"crumb in breadcrumbs\"><a href=\"\{\{ \'#\' + crumb.path \}\}\">\{\{ crumb.title \| capitalize \}\}</a></li>\n";
if (list.navigationLinks) {
var navigation = list.navigationLinks;

View File

@ -7,6 +7,8 @@
*
*/
'use strict';
angular.module('ListGenerator', ['GeneratorHelpers'])
.factory('GenerateList', [ '$location', '$compile', '$rootScope', 'SearchWidget', 'PaginateWidget', 'Attr', 'Icon',
'Column', 'DropDown', 'NavigationLink', 'Button', 'SelectIcon', 'Breadcrumbs',
@ -124,7 +126,7 @@ angular.module('ListGenerator', ['GeneratorHelpers'])
// before navigation
html += "<div class=\"nav-path\">\n";
html += "<ul class=\"breadcrumb\">\n";
html += "<li ng-repeat=\"crumb in breadcrumbs\"><a href=\"\" ng-click=\"{{ crumb.ngClick }}\">{{ crumb.title | capitalize }}</a></li>\n";
html += "<li ng-repeat=\"crumb in breadcrumbs\"><a href=\"\" ng-click=\"crumb.ngClick\">{{ crumb.title | capitalize }}</a></li>\n";
html += "<li class=\"active\">";
html += list.editTitle;
html += "</li>\n</ul>\n</div>\n";
@ -190,7 +192,7 @@ angular.module('ListGenerator', ['GeneratorHelpers'])
html += "<div class=\"list-actions\">\n";
// Add toolbar buttons or 'actions'
for (action in list.actions) {
for (var action in list.actions) {
if (list.actions[action].mode == 'all' || list.actions[action].mode == options.mode) {
if ( (list.actions[action].basePaths == undefined) ||
(list.actions[action].basePaths && list.actions[action].basePaths.indexOf(base) > -1) ) {
@ -341,7 +343,7 @@ angular.module('ListGenerator', ['GeneratorHelpers'])
html += (fAction.awPopOver) ? "aw-pop-over=\"" + fAction.awPopOver + "\" " : "";
html += (fAction.dataPlacement) ? Attr(fAction, 'dataPlacement') : "";
html += (fAction.dataTitle) ? Attr(fAction, 'dataTitle') : "";
for (itm in fAction) {
for (var itm in fAction) {
if (itm != 'ngHref' && itm != 'href' && itm != 'label' && itm != 'icon' && itm != 'class' &&
itm != 'iconClass' && itm != "dataPlacement" && itm != "awPopOver" && itm != "dataTitle") {
html += Attr(fAction, itm);

View File

@ -14,6 +14,8 @@
* }
*/
'use strict';
angular.module('PromptDialog', ['Utilities'])
.factory('Prompt', ['$rootScope', '$compile', 'Alert', function($rootScope, $compile, Alert) {
return function(params) {