diff --git a/awx/ui/client/features/credentials/add-credentials.controller.js b/awx/ui/client/features/credentials/add-credentials.controller.js index 5fa9eea0cb..41fbcb5c6a 100644 --- a/awx/ui/client/features/credentials/add-credentials.controller.js +++ b/awx/ui/client/features/credentials/add-credentials.controller.js @@ -2,9 +2,11 @@ function AddCredentialsController (credentialType) { let vm = this || {}; vm.name = { + state: { + required: true + }, label: { text: 'Name', - required: true, popover: { text: 'a, b, c' } @@ -22,9 +24,11 @@ function AddCredentialsController (credentialType) { }; vm.kind = { + state: { + required: true, + }, label: { text: 'Type', - required: true, popover: { text: 'x, y, z' } diff --git a/awx/ui/client/features/credentials/add-credentials.view.html b/awx/ui/client/features/credentials/add-credentials.view.html index b4ca5857f3..d9ac817beb 100644 --- a/awx/ui/client/features/credentials/add-credentials.view.html +++ b/awx/ui/client/features/credentials/add-credentials.view.html @@ -8,13 +8,13 @@ - - - + + + - - + + diff --git a/awx/ui/client/lib/components/action/action.directive.js b/awx/ui/client/lib/components/action/action.directive.js index 47c1625405..55b6c752f6 100644 --- a/awx/ui/client/lib/components/action/action.directive.js +++ b/awx/ui/client/lib/components/action/action.directive.js @@ -1,30 +1,33 @@ let $state; -function applyCancelProperties (scope) { - scope.text = scope.config.text || 'CANCEL'; - scope.fill = 'Hollow'; - scope.color = 'white'; - scope.disabled = false; - scope.action = () => $state.go('^'); -} - -function applySaveProperties (scope) { - scope.text = 'SAVE'; - scope.fill = ''; - scope.color = 'green'; - scope.disabled = true; -} - function link (scope, el, attrs, form) { - form.use('action', scope, el); + scope.config.state = scope.config.state || {}; + let state = scope.config.state; + + scope.form = form.use('action', state); switch(scope.config.type) { case 'cancel': - applyCancelProperties(scope); + setCancelDefaults(scope); break; case 'save': - applySaveProperties(scope); + setSaveDefaults(scope); break; + default: + break; + } + + function setCancelDefaults (scope) { + scope.text = 'CANCEL'; + scope.fill = 'Hollow'; + scope.color = 'white'; + scope.action = () => $state.go('^'); + } + + function setSaveDefaults (scope) { + scope.text = 'SAVE'; + scope.fill = ''; + scope.color = 'green'; } } diff --git a/awx/ui/client/lib/components/action/action.partial.html b/awx/ui/client/lib/components/action/action.partial.html index cded0da9f0..cb46276e8b 100644 --- a/awx/ui/client/lib/components/action/action.partial.html +++ b/awx/ui/client/lib/components/action/action.partial.html @@ -1,4 +1,5 @@ - - {{ text }} + + {{::text}} diff --git a/awx/ui/client/lib/components/form/form.directive.js b/awx/ui/client/lib/components/form/form.directive.js index a32fe009ba..4cd7e7b186 100644 --- a/awx/ui/client/lib/components/form/form.directive.js +++ b/awx/ui/client/lib/components/form/form.directive.js @@ -1,56 +1,70 @@ -function use (type, componentScope, componentElement) { +function use (type, component, el) { let vm = this; - let component; + let state; switch (type) { case 'input': - component = vm.trackInput(componentElement); + state = vm.trackInput(component, el); break; case 'action': - component = vm.trackAction(componentElement); + state = vm.trackAction(component, el); break; default: throw new Error('An at-form cannot use component type:', type); } - componentScope.meta = component; + return state; } -function trackInput (componentElement) { +function trackInput (component, el) { let vm = this; - let input = { - el: componentElement, - tabindex: vm.inputs.length + 1 + let form = { + state: vm.state, + disabled: false }; - if (vm.inputs.length === 0) { - input.autofocus = true; - componentElement.find('input').focus(); - } + vm.inputs.push(component) - vm.inputs.push(input) - - return input; + return form; } -function trackAction (componentElement) { +function trackAction (component) { let vm = this; - let action = { - el: componentElement + let form = { + state: vm.state, + disabled: false }; - vm.actions.push(action); + vm.actions.push(component); - return action; + return form; } -function update () { +function validate () { let vm = this; - vm.inputs.forEach(input => console.log(input)); + let isValid = true; + + vm.inputs.forEach(input => { + if (!input.isValid) { + isValid = false; + } + }); + + return isValid; +} + +function check () { + let vm = this; + + let isValid = vm.validate(); + + if (isValid !== vm.state.isValid) { + vm.state.isValid = isValid; + } } function remove (id) { @@ -62,13 +76,18 @@ function remove (id) { function AtFormController () { let vm = this; + vm.state = { + isValid: false + }; + vm.inputs = []; vm.actions = []; vm.use = use; vm.trackInput = trackInput; vm.trackAction = trackAction; - vm.update = update; + vm.validate = validate; + vm.check = check; vm.remove = remove; } diff --git a/awx/ui/client/lib/components/form/form.partial.html b/awx/ui/client/lib/components/form/form.partial.html index 95ccc844b1..3303ed535e 100644 --- a/awx/ui/client/lib/components/form/form.partial.html +++ b/awx/ui/client/lib/components/form/form.partial.html @@ -1,5 +1,5 @@ - - - + + + diff --git a/awx/ui/client/lib/components/input/label.partial.html b/awx/ui/client/lib/components/input/label.partial.html index 6c008fd771..f1a53a6203 100644 --- a/awx/ui/client/lib/components/input/label.partial.html +++ b/awx/ui/client/lib/components/input/label.partial.html @@ -1,5 +1,5 @@ - * - {{ config.text }} - + * + {{::config.label.text}} + diff --git a/awx/ui/client/lib/components/input/select.directive.js b/awx/ui/client/lib/components/input/select.directive.js index a8c8c5ce4b..0378721552 100644 --- a/awx/ui/client/lib/components/input/select.directive.js +++ b/awx/ui/client/lib/components/input/select.directive.js @@ -2,16 +2,24 @@ let eventService; let pathService; function link (scope, el, attrs, form) { - form.use('input', scope, el); // avoid passing scope? assign to scope.meta instead or reference form properties in view + scope.config.state = scope.config.state || {}; let input = el.find('input')[0]; let select = el.find('select')[0]; + let state = scope.config.state; + + setDefaults(); + + scope.form = form.use('input', state); let listeners = eventService.addListeners(scope, [ - [input, 'focus', () => select.focus()], - [select, 'mousedown', () => scope.open = !scope.open], + [input, 'focus', () => select.focus], + [select, 'mousedown', () => scope.$apply(scope.open = !scope.open)], [select, 'focus', () => input.classList.add('at-Input--focus')], - [select, 'change', () => scope.open = false], + [select, 'change', () => { + scope.open = false; + check(); + }], [select, 'blur', () => { input.classList.remove('at-Input--focus'); scope.open = scope.open && false; @@ -20,13 +28,38 @@ function link (scope, el, attrs, form) { scope.$on('$destroy', () => eventService.remove(listeners)); - /* - * Should notify form on: - * - valid (required, passes validation) state change - * - * Should get from form: - * - display as disabled - */ + function setDefaults () { + if (scope.tab === 1) { + select.focus(); + } + + state.isValid = state.isValid || false; + state.validate = state.validate ? validate.bind(null, state.validate) : validate; + state.check = state.check || check; + state.message = state.message || ''; + state.required = state.required || false; + } + + function validate (fn) { + let isValid = true; + + if (state.required && !state.value) { + isValid = false; + } else if (fn && !fn(scope.config.input)) { + isValid = false; + } + + return isValid; + } + + function check () { + let isValid = state.validate(); + + if (isValid !== state.isValid) { + state.isValid = isValid; + form.check(); + } + } } function atInputSelect (_eventService_, _pathService_) { @@ -42,7 +75,8 @@ function atInputSelect (_eventService_, _pathService_) { link, scope: { config: '=', - col: '@' + col: '@', + tab: '@' } }; } diff --git a/awx/ui/client/lib/components/input/select.partial.html b/awx/ui/client/lib/components/input/select.partial.html index eb57c7b9e2..12348d42e2 100644 --- a/awx/ui/client/lib/components/input/select.partial.html +++ b/awx/ui/client/lib/components/input/select.partial.html @@ -1,14 +1,17 @@ - + - - + placeholder="{{ config.placeholder | uppercase }}" + ng-model="config.state.value" ng-disabled="form.disabled" + ng-change="config.state.check" /> + + + {{ item.name }} diff --git a/awx/ui/client/lib/components/input/text.directive.js b/awx/ui/client/lib/components/input/text.directive.js index c46a7a9a18..fbf8f6cf9d 100644 --- a/awx/ui/client/lib/components/input/text.directive.js +++ b/awx/ui/client/lib/components/input/text.directive.js @@ -1,5 +1,44 @@ function link (scope, el, attrs, form) { - form.use('input', scope, el); + scope.config.state = scope.config.state || {}; + let state = scope.config.state; + let input = el.find('input')[0]; + + setDefaults(); + + scope.form = form.use('input', state, input); + + function setDefaults () { + if (scope.tab === '1') { + input.focus(); + } + + state.isValid = state.isValid || false; + state.validate = state.validate ? validate.bind(null, state.validate) : validate; + state.check = state.check || check; + state.message = state.message || ''; + state.required = state.required || false; + } + + function validate (fn) { + let isValid = true; + + if (state.required && !state.value) { + isValid = false; + } else if (fn && !fn(scope.config.input)) { + isValid = false; + } + + return isValid; + } + + function check () { + let isValid = state.validate(); + + if (isValid !== state.isValid) { + state.isValid = isValid; + form.check(); + } + } } function atInputText (pathService) { @@ -12,7 +51,8 @@ function atInputText (pathService) { link, scope: { config: '=', - col: '@' + col: '@', + tab: '@' } }; } diff --git a/awx/ui/client/lib/components/input/text.partial.html b/awx/ui/client/lib/components/input/text.partial.html index 775d76754c..df0fabdc92 100644 --- a/awx/ui/client/lib/components/input/text.partial.html +++ b/awx/ui/client/lib/components/input/text.partial.html @@ -1,8 +1,9 @@ - + - - + + diff --git a/awx/ui/client/lib/components/popover/popover.partial.html b/awx/ui/client/lib/components/popover/popover.partial.html index b2f4be77d9..18fbfdac3b 100644 --- a/awx/ui/client/lib/components/popover/popover.partial.html +++ b/awx/ui/client/lib/components/popover/popover.partial.html @@ -6,6 +6,6 @@ - {{ config.text }} + {{::config.text}} diff --git a/awx/ui/client/lib/services/event.service.js b/awx/ui/client/lib/services/event.service.js index 7473b65aa0..24e4dd25bf 100644 --- a/awx/ui/client/lib/services/event.service.js +++ b/awx/ui/client/lib/services/event.service.js @@ -8,11 +8,9 @@ function addListeners (scope, list) { return listeners; } -function addListener (scope, el, name, fn, type) { - type = type || '$apply'; - +function addListener (scope, el, name, fn) { let listener = { - fn: () => scope[type](fn), + fn, name, el };