Add support for dynamic select inputs

This commit is contained in:
gconsidine 2017-05-31 17:16:26 -04:00
parent 475718a4de
commit 0ca53024f0
9 changed files with 143 additions and 24 deletions

View File

@ -11,6 +11,7 @@ function AddCredentialsController (models, $state) {
vm.form.credential_type._data = credentialType.get('results');
vm.form.credential_type._placeholder = 'SELECT A TYPE';
vm.form.credential_type._format = 'grouped-object';
vm.form.credential_type._display = 'name';
vm.form.credential_type._key = 'id';
vm.form.credential_type._exp = 'type as type.name group by type.kind for type in state._data';

View File

@ -9,6 +9,7 @@ import inputSelect from './input/select.directive';
import inputSecret from './input/secret.directive';
import inputText from './input/text.directive';
import inputTextarea from './input/textarea.directive';
import inputTextareaSecret from './input/textarea-secret.directive';
import panel from './panel/panel.directive';
import panelHeading from './panel/heading.directive';
import panelBody from './panel/body.directive';
@ -31,6 +32,7 @@ angular
.directive('atInputSelect', inputSelect)
.directive('atInputText', inputText)
.directive('atInputTextarea', inputTextarea)
.directive('atInputTextareaSecret', inputTextareaSecret)
.directive('atPanel', panel)
.directive('atPanelHeading', panelHeading)
.directive('atPanelBody', panelBody)

View File

@ -56,33 +56,62 @@ function AtInputGroupController ($scope, $compile) {
let group = [];
inputs.forEach((input, i) => {
if (input.type === 'string') {
if (input.secret && input.multiline) {
input._component = 'at-input-textarea';
} else if (input.secret) {
input._component = 'at-input-secret';
} else if (input.multiline) {
input._component = 'at-input-textarea';
} else {
input._component = 'at-input-text';
}
}
input = Object.assign(input, vm.getComponentType(input));
group.push(Object.assign({
_element: vm.createElement(input, i),
_key: 'inputs',
_group: true
_group: true,
_groupIndex: i
}, input));
});
return group;
};
vm.getComponentType = input => {
let config = {};
if (input.type === 'string') {
if (!input.multiline) {
if (input.secret) {
config._component = 'at-input-text';
} else {
config._component = 'at-input-secret';
}
} else {
config._expand = true;
if (input.secret) {
config._component = 'at-input-textarea-secret';
} else {
config._component = 'at-input-textarea';
}
}
if (input.format === 'ssh_private_key') {
config._format = 'ssh-key';
}
} else if (input.type === 'number') {
config._component = 'at-input-number';
} else if (input.choices) {
config._component = 'at-input-select';
config._format = 'array';
config._data = input.choices;
config._exp = 'index as choice for (index, choice) in state._data';
} else {
throw new Error('Unsupported input type: ' + input.type)
}
return config;
};
vm.createElement = (input, index) => {
let tabindex = Number(scope.tab) + index;
let col = input._expand ? 12 : scope.col;
let element =
`<${input._component} col="${scope.col}" tab="${tabindex}"
`<${input._component} col="${col}" tab="${tabindex}"
state="${state._reference}._group[${index}]">
</${input._component}>`;
@ -91,19 +120,35 @@ function AtInputGroupController ($scope, $compile) {
vm.insert = group => {
let container = document.createElement('div');
let divider = angular.element(`<div class="at-InputGroup-divider"></div>`)[0];
let col = 1;
let colPerRow = 12 / scope.col;
let isDivided = true;
for (let i = 0; i < group.length; i++) {
if (i !== 0 && (i % (12 / scope.col)) === 0) {
container.appendChild(divider);
group.forEach((input, i) => {
if (input._expand && !isDivided) {
container.appendChild(vm.createInputDivider());
}
container.appendChild(group[i]._element[0]);
}
container.appendChild(input._element[0]);
if ((input._expand || col % colPerRow === 0) && i !== group.length -1) {
container.appendChild(vm.createInputDivider());
isDivided = true;
col = 0;
} else {
isDivided = false;
}
col++;
});
element.appendChild(container);
};
vm.createInputDivider = () => {
return angular.element(`<div class="at-InputGroup-divider"></div>`)[0];
};
vm.compile = group => {
group.forEach(component => $compile(component._element[0])(scope.$parent));
};

View File

@ -46,6 +46,16 @@ function AtInputSelectController (baseInputController, eventService) {
scope.$on('$destroy', () => eventService.remove(listeners));
};
vm.updateDisplayModel = () => {
if (scope.state._format === 'array') {
scope.displayModel = scope.state._data[scope.state._value];
} else if (scope.state._format === 'grouped-object') {
scope.displayModel = scope.state._value[scope.state._display];
} else {
throw new Error('Unsupported display model type');
}
};
}
AtInputSelectController.$inject = ['BaseInputController', 'EventService'];

View File

@ -6,8 +6,8 @@
<input type="text"
class="form-control at-Input at-InputSelect-input"
placeholder="{{state._placeholder || undefined }}"
ng-class="{ 'at-Input--rejected': state.rejected }"
ng-model="state._value[state._display]"
ng-class="{ 'at-Input--rejected': state._rejected }"
ng-model="displayModel"
ng-disabled="state._disabled || form.disabled"
ng-change="vm.check()" />
@ -15,6 +15,7 @@
ng-model="state._value"
ng-attr-tabindex="{{ tab || undefined }}"
ng-disabled="state._disabled || form.disabled"
ng-change="vm.updateDisplayModel()"
ng-options="{{ state._exp }}"></select>
<i class="fa" ng-class="{ 'fa-chevron-down': !open, 'fa-chevron-up': open }"></i>

View File

@ -0,0 +1,44 @@
function atInputTextareaSecretLink (scope, element, attrs, controllers) {
let formController = controllers[0];
let inputController = controllers[1];
if (scope.tab === '1') {
element.find('input')[0].focus();
}
inputController.init(scope, element, formController);
}
function AtInputTextareaSecretController (baseInputController) {
let vm = this || {};
vm.init = (scope, element, form) => {
baseInputController.call(vm, 'input', scope, element, form);
vm.check();
};
}
AtInputTextareaSecretController.$inject = ['BaseInputController'];
function atInputTextareaSecret (pathService) {
return {
restrict: 'E',
transclude: true,
replace: true,
require: ['^^atForm', 'atInputTextareaSecret'],
templateUrl: pathService.getPartialPath('components/input/textarea-secret'),
controller: AtInputTextareaSecretController,
controllerAs: 'vm',
link: atInputTextareaSecretLink,
scope: {
state: '=',
col: '@',
tab: '@'
}
};
}
atInputTextareaSecret.$inject = ['PathService'];
export default atInputTextareaSecret;

View File

@ -0,0 +1,16 @@
<div class="col-sm-{{::col}}">
<div class="form-group at-u-flat">
<at-input-label></at-input-label>
<textarea class="form-control at-Input"
ng-model="state._value"
ng-class="{ 'at-Input--rejected': state._rejected }"
ng-attr-maxlength="{{ state.max_length || undefined }}"
ng-attr-tabindex="{{ tab || undefined }}"
ng-attr-placeholder="{{::state._placeholder || undefined }}"
ng-change="vm.check()"
ng-disabled="state._disabled || form.disabled" /></textarea>
<at-input-message></at-input-message>
</div>
</div>

View File

@ -19,7 +19,7 @@ function createFormSchema (type, config) {
function CredentialModel (method, id) {
BaseModel.call(this, 'credentials');
this.createFormSchema = createFormSchema;
this.createFormSchema = createFormSchema.bind(this);
return this.request(method, id)
.then(() => this);

View File

@ -29,8 +29,8 @@ function mergeInputProperties (type) {
function CredentialTypeModel (method, id) {
BaseModel.call(this, 'credential_types');
this.categorizeByKind = categorizeByKind;
this.mergeInputProperties = mergeInputProperties;
this.categorizeByKind = categorizeByKind.bind(this);
this.mergeInputProperties = mergeInputProperties.bind(this);
return this.request(method, id)
.then(() => this);