diff options
author | Michael Lando <ml636r@att.com> | 2017-06-09 03:19:04 +0300 |
---|---|---|
committer | Michael Lando <ml636r@att.com> | 2017-06-09 03:19:04 +0300 |
commit | ed64b5edff15e702493df21aa3230b81593e6133 (patch) | |
tree | a4cb01fdaccc34930a8db403a3097c0d1e40914b /catalog-ui/src/app/directives/select-property-types | |
parent | 280f8015d06af1f41a3ef12e8300801c7a5e0d54 (diff) |
[SDC-29] catalog 1707 rebase commit.
Change-Id: I43c3dc5cf44abf5da817649bc738938a3e8388c1
Signed-off-by: Michael Lando <ml636r@att.com>
Diffstat (limited to 'catalog-ui/src/app/directives/select-property-types')
9 files changed, 909 insertions, 0 deletions
diff --git a/catalog-ui/src/app/directives/select-property-types/select-data-type-fields-structure/select-data-type-fields-structure.html b/catalog-ui/src/app/directives/select-property-types/select-data-type-fields-structure/select-data-type-fields-structure.html new file mode 100644 index 0000000000..8560e66978 --- /dev/null +++ b/catalog-ui/src/app/directives/select-property-types/select-data-type-fields-structure/select-data-type-fields-structure.html @@ -0,0 +1,81 @@ +<div class="data-type-fields-structure"> + <div class="open-close"> + <div class="open-close-button" data-ng-class="{'expand':expand,'collapse':!expand}" + data-ng-click="expandAndCollapse()"></div> + <span class="data-type-name">{{typeName.replace("org.openecomp.datatypes.heat.","")}}</span> + </div> + <div data-ng-show="expand" data-ng-repeat="property in dataTypeProperties" class="property" data-ng-init="property.isAlreadyInput = isAlreadyInput(property)"> + + <sdc-radio-button sdc-model="dataTypesService.selectedPropertiesName" value="{{path + '#' + property.name}}" data-ng-if="path && !property.isAlreadyInput" + disabled="false" elem-name="selectedPropertiesName" elem-id="{{path + '#' + property.name}}" class="selectPropertyType" + on-value-change="setSelectedType(property)" data-tests-id="propertyRadioButton_{{property.name}}"></sdc-radio-button> + <div class="existInputContainer" data-ng-if="property.isAlreadyInput"><span class="existInput"></span></div> + <div class="i-sdc-form-item property-name"> + <div tooltips tooltip-content="{{property.name}}"> + <input class="i-sdc-form-input" + type="text" + data-ng-disabled="true" + value="{{property.name}}"/> + </div> + </div> + <div data-ng-if="dataTypesService.isDataTypeForDataTypePropertyType(property)" class="inner-structure"> + <select-fields-structure value-obj-ref="(valueObjRef[property.name])" + type-name="property.type" + parent-form-obj="parentFormObj" + fields-prefix-name="fieldsPrefixName+property.name" + read-only="readOnly" + default-value="{{currentTypeDefaultValue[property.name]}}" + path="{{path + '#' + property.name}}" + is-parent-already-input="isParentAlreadyInput" + ></select-fields-structure> + + </div> + <div data-ng-if="!dataTypesService.isDataTypeForDataTypePropertyType(property)" ng-switch="property.type"> + <div ng-switch-when="map"> + <select-type-map value-obj-ref="valueObjRef[property.name]" + schema-property="property.schema.property" + parent-form-obj="parentFormObj" + fields-prefix-name="fieldsPrefixName+property.name" + read-only="readOnly" + default-value="{{currentTypeDefaultValue[property.name]}}" + ></select-type-map> + </div> + <div ng-switch-when="list"> + <select-type-list value-obj-ref="valueObjRef[property.name]" + schema-property="property.schema.property" + parent-form-obj="parentFormObj" + fields-prefix-name="fieldsPrefixName+property.name" + read-only="readOnly" + default-value="{{currentTypeDefaultValue[property.name]}}" + ></select-type-list> + </div> + <div ng-switch-default class="primitive-value-field"> + <div class="i-sdc-form-item" + data-ng-class="{error:(parentFormObj[fieldsPrefixName+property.name].$dirty && parentFormObj[fieldsPrefixName+property.name].$invalid)}"> + <input class="i-sdc-form-input" + data-tests-id="{{fieldsPrefixName+property.name}}" + ng-if="!((property.simpleType||property.type) == 'boolean')" + data-ng-maxlength="100" + data-ng-disabled="readOnly" + maxlength="100" + data-ng-model="valueObjRef[property.name]" + type="text" + name="{{fieldsPrefixName+property.name}}" + data-ng-model-options="{ debounce: 200 }" + data-ng-change="!parentFormObj[fieldsPrefixName+property.name].$error.pattern && ('integer'==property.type && parentFormObj[fieldsPrefixName+property.name].$setValidity('pattern', validateIntRange(valueObjRef[property.name])) || onValueChange(property.name, (property.simpleType||property.type)))" + autofocus/> + <select class="i-sdc-form-select" + data-tests-id="{{fieldsPrefixName+property.name}}" + ng-if="(property.simpleType||property.type) == 'boolean'" + data-ng-disabled="readOnly" + name="{{fieldsPrefixName+property.name}}" + data-ng-change="onValueChange(property.name,'boolean')" + data-ng-model="valueObjRef[property.name]" + data-ng-options="option.v as option.n for option in [{ n: '', v: undefined }, { n: 'false', v: false }, { n: 'true', v: true }]"> + </select> + + </div> + </div> + </div> + </div> +</div> diff --git a/catalog-ui/src/app/directives/select-property-types/select-data-type-fields-structure/select-data-type-fields-structure.less b/catalog-ui/src/app/directives/select-property-types/select-data-type-fields-structure/select-data-type-fields-structure.less new file mode 100644 index 0000000000..43d2d646a1 --- /dev/null +++ b/catalog-ui/src/app/directives/select-property-types/select-data-type-fields-structure/select-data-type-fields-structure.less @@ -0,0 +1,117 @@ + +.selectPropertyType { + .tlv-radio-label { + margin-top: -7px; + } +} + +.data-type-fields-structure { + background-color: @tlv_color_v; + padding: 10px; + display: table-caption; + .open-close { + position: relative; + .open-close-button { + position: absolute; + top: 50%; + margin-top: -7px; + &.expand { + .sprite-new; + .expand-collapse-minus-icon; + } + &.collapse { + .sprite-new; + .expand-collapse-plus-icon; + } + } + + } + + .existInputContainer { + height: 30px; + width: 20px; + position: relative; + } + .existInput { + .sprite-new; + .sdc-success; + position: absolute; + top: 18px; + left: 3px; + } + + .data-type-name { + .m_16_m; + margin-left: 22px; + } + + .i-sdc-form-input:disabled{ + .disabled; + &[type="text"]{ + opacity: 1 !important; + background-color: @tlv_color_t; + color:black; + } + } + + .property { + display: flex; + min-width: 365px; + min-height: 46px; + input[type="text"], select { + width: 170px; + } + .property-name { + float: left; + margin-top: 8px; + } + .primitive-value-field { + float: right; + margin-top: 8px; + margin-left: 10px; + } + .inner-structure { + display: -webkit-box; + } + } + + [ng-switch-when="map"] { + margin-top: 8px; + margin-left: 10px; + .map-item { + border: solid 1px @main_color_o; + min-width: 401px; + min-height: 69px; + float: none !important; + } + .add-map-item { + width: auto; + float: none; + &:nth-child(1) { + position: relative; + top: 6px; + } + .add-btn { + float: none; + } + } + + } + + [ng-switch-when="list"] { + float: left; + margin-top: 8px; + margin-left: 10px; + min-width: 280px; + .dt-list-item { + border: solid 1px @main_color_o; + } + .list-value-items { + width: 280px; + } + } +} + + + + diff --git a/catalog-ui/src/app/directives/select-property-types/select-data-type-fields-structure/select-data-type-fields-structure.ts b/catalog-ui/src/app/directives/select-property-types/select-data-type-fields-structure/select-data-type-fields-structure.ts new file mode 100644 index 0000000000..aee4b3b6af --- /dev/null +++ b/catalog-ui/src/app/directives/select-property-types/select-data-type-fields-structure/select-data-type-fields-structure.ts @@ -0,0 +1,184 @@ +/** + * Created by obarda on 1/27/2016. + */ +'use strict'; +import {ValidationUtils} from "app/utils"; +import { DataTypesService } from "app/services"; +import { DataTypePropertyModel } from "app/models/data-type-properties"; +import {DataTypesMap, PropertyModel} from "app/models"; + +export interface ISelectDataTypeFieldsStructureScope extends ng.IScope { + parentFormObj:ng.IFormController; + dataTypeProperties:Array<DataTypePropertyModel>; + typeName:string; + valueObjRef:any; + propertyNameValidationPattern:RegExp; + fieldsPrefixName:string; + readOnly:boolean; + currentTypeDefaultValue:any; + types:DataTypesMap; + expandByDefault:boolean; + expand:boolean; + expanded:boolean; + dataTypesService:DataTypesService; + path:string; + isParentAlreadyInput:boolean; + + expandAndCollapse():void; + getValidationPattern(type:string):RegExp; + validateIntRange(value:string):boolean; + isAlreadyInput(property:PropertyModel):boolean; + setSelectedType(property:PropertyModel):void; + onValueChange(propertyName:string, type:string):void; +} + + +export class SelectDataTypeFieldsStructureDirective implements ng.IDirective { + + constructor(private DataTypesService:DataTypesService, + private PropertyNameValidationPattern:RegExp, + private ValidationUtils:ValidationUtils) { + } + + scope = { + valueObjRef: '=', + typeName: '=', + parentFormObj: '=', + fieldsPrefixName: '=', + readOnly: '=', + defaultValue: '@', + expandByDefault: '=', + path: '@', + isParentAlreadyInput: '=' + }; + + restrict = 'E'; + replace = true; + template = ():string => { + return require('./select-data-type-fields-structure.html'); + }; + // public types=Utils.Constants.PROPERTY_DATA.TYPES; + + //get data type properties array and return object with the properties and their default value + //(for example: get: [{name:"prop1",defaultValue:1 ...},{name:"prop2", defaultValue:"bla bla" ...}] + // return: {prop1: 1, prop2: "bla bla"} + private getDefaultValue = (dataTypeProperties:Array<DataTypePropertyModel>):any => { + let defaultValue = {}; + for (let i = 0; i < dataTypeProperties.length; i++) { + if (dataTypeProperties[i].type != 'string') { + if (!angular.isUndefined(dataTypeProperties[i].defaultValue)) { + defaultValue[dataTypeProperties[i].name] = JSON.parse(dataTypeProperties[i].defaultValue); + } + } else { + defaultValue[dataTypeProperties[i].name] = dataTypeProperties[i].defaultValue; + } + } + return defaultValue; + }; + + private initDataOnScope = (scope:ISelectDataTypeFieldsStructureScope, $attr:any):void => { + scope.dataTypesService = this.DataTypesService; + scope.dataTypeProperties = angular.copy(this.DataTypesService.getFirsLevelOfDataTypeProperties(scope.typeName)); + if ($attr.defaultValue) { + scope.currentTypeDefaultValue = JSON.parse($attr.defaultValue); + } else { + scope.currentTypeDefaultValue = this.getDefaultValue(scope.dataTypeProperties); + } + + if (!scope.valueObjRef) { + scope.valueObjRef = {}; + } + + _.forEach(scope.currentTypeDefaultValue, (value, key)=> { + if (angular.isUndefined(scope.valueObjRef[key])) { + if (typeof scope.currentTypeDefaultValue[key] == 'object') { + angular.copy(scope.currentTypeDefaultValue[key], scope.valueObjRef[key]); + } else { + scope.valueObjRef[key] = scope.currentTypeDefaultValue[key]; + } + } + }); + }; + + private rerender = (scope:any):void => { + scope.expanded = false; + scope.expand = false; + if (scope.expandByDefault) { + scope.expandAndCollapse(); + } + }; + + link = (scope:ISelectDataTypeFieldsStructureScope, element:any, $attr:any) => { + scope.propertyNameValidationPattern = this.PropertyNameValidationPattern; + + scope.$watchCollection('[typeName,fieldsPrefixName]', (newData:any):void => { + this.rerender(scope); + }); + + + scope.expandAndCollapse = ():void => { + if (!scope.expanded) { + this.initDataOnScope(scope, $attr); + scope.expanded = true; + } + scope.expand = !scope.expand; + }; + + scope.getValidationPattern = (type:string):RegExp => { + return this.ValidationUtils.getValidationPattern(type); + }; + + scope.validateIntRange = (value:string):boolean => { + return !value || this.ValidationUtils.validateIntRange(value); + }; + + /* + check if property is alrady declered on the service by meatching the input name & the property name + + */ + scope.isAlreadyInput = (property:PropertyModel):boolean => { + if (scope.path) { + if (scope.isParentAlreadyInput) { + return true; + } + let parentInputName = this.DataTypesService.selectedInstance.normalizedName + '_' + scope.path.replace('#', '_');// set the input parent as he need to declared as input + let inputName = parentInputName + '_' + property.name;// set the input name as he need to declared as input + let selectedProperty = _.find(this.DataTypesService.selectedComponentInputs, (componentInput)=> { + if (componentInput.name == parentInputName) { //check if the parent(all the complex) is already declared + scope.isParentAlreadyInput = true; + return true; + } else if (componentInput.name.substring(0, inputName.length) == inputName) { //check if specific property inside the complex + return true; + } + //return componentInput.name == parentInputName || componentInput.name.substring(0,inputName.length) == inputName;//check if the parent(all the complex) is already declared or specific property inside the complex + }); + if (selectedProperty) { + return true; + } + } + return false; + }; + + scope.setSelectedType = (property:PropertyModel):void=> { + scope.dataTypesService.selectedInput = property; + scope.dataTypesService.selectedPropertiesName = scope.path + '#' + property.name; + }; + + scope.onValueChange = (propertyName:string, type:string):void => { + scope.valueObjRef[propertyName] = !angular.isUndefined(scope.valueObjRef[propertyName]) ? scope.valueObjRef[propertyName] : scope.currentTypeDefaultValue[propertyName]; + if (scope.valueObjRef[propertyName] && type != 'string') { + scope.valueObjRef[propertyName] = JSON.parse(scope.valueObjRef[propertyName]); + } + }; + + + }; + + public static factory = (DataTypesService:DataTypesService, + PropertyNameValidationPattern:RegExp, + ValidationUtils:ValidationUtils)=> { + return new SelectDataTypeFieldsStructureDirective(DataTypesService, PropertyNameValidationPattern, ValidationUtils); + }; +} + +SelectDataTypeFieldsStructureDirective.factory.$inject = ['Sdc.Services.DataTypesService', 'PropertyNameValidationPattern', 'ValidationUtils']; diff --git a/catalog-ui/src/app/directives/select-property-types/select-type-list/select-type-list-directive.html b/catalog-ui/src/app/directives/select-property-types/select-type-list/select-type-list-directive.html new file mode 100644 index 0000000000..f439147301 --- /dev/null +++ b/catalog-ui/src/app/directives/select-property-types/select-type-list/select-type-list-directive.html @@ -0,0 +1,56 @@ +<div> + <div data-ng-if="!isSchemaTypeDataType"> + <div class="i-sdc-form-item list-new-item" data-ng-class="{error:(parentFormObj['listNewItem'+fieldsPrefixName].$dirty && parentFormObj['listNewItem'+fieldsPrefixName].$invalid)}"> + <input class="i-sdc-form-input" + data-tests-id="listNewItem{{fieldsPrefixName}}" + ng-if="!((schemaProperty.simpleType||schemaProperty.type) == 'boolean')" + data-ng-disabled="readOnly" + data-ng-model="listNewItem.value" + type="text" + name="listNewItem{{fieldsPrefixName}}" + data-ng-model-options="{ debounce: 200 }" + placeholder="Type a value and then click ADD" + data-ng-maxlength="maxLength" + maxlength="{{maxLength}}" + sdc-keyboard-events="" key-enter="schemaProperty.type && !parentFormObj['listNewItem'+fieldsPrefixName].$invalid && listNewItem.value && addListItem" + autofocus /> + <select class="i-sdc-form-select" + data-tests-id="listNewItem{{fieldsPrefixName}}" + ng-if="(schemaProperty.simpleType||schemaProperty.type) == 'boolean'" + data-ng-disabled="readOnly" + name="listNewItem{{fieldsPrefixName}}" + data-ng-model="listNewItem.value"> + <option value="true">true</option> + <option value="false">false</option> + </select> + <div class="input-error" data-ng-show="parentFormObj['listNewItem'+fieldsPrefixName].$dirty && parentFormObj['listNewItem'+fieldsPrefixName].$invalid"> + <span ng-show="parentFormObj['listNewItem'+fieldsPrefixName].$error.pattern" translate="PROPERTY_EDIT_PATTERN"></span> + <span ng-show="parentFormObj['listNewItem'+fieldsPrefixName].$error.maxlength" translate="VALIDATION_ERROR_MAX_LENGTH" translate-values="{'max': '{{maxLength}}' }"></span> + </div> + </div> + <!--<div class="add-btn add-list-item" data-tests-id="add-list-item{{fieldsPrefixName}}"--> + <!--data-ng-class="{'disabled': readOnly || !schemaProperty.type || parentFormObj['listNewItem'+fieldsPrefixName].$invalid || !listNewItem.value}" data-ng-click="addListItem()">Add</div>--> + <div class="list-value-items"> + <span class="list-value-item" data-ng-repeat="value in valueObjRef track by $index"> + {{value}} + <span ng-if="!readOnly" class="delete-list-item sprite-new small-x-button" data-ng-click="deleteListItem($index)"></span> + </span> + </div> + </div> + <div data-ng-if="isSchemaTypeDataType"> + <div class="dt-list"> + <div data-ng-repeat="value in valueObjRef track by $index" class="dt-list-item"> + <select-fields-structure value-obj-ref="valueObjRef[$index]" + type-name="schemaProperty.type" + parent-form-obj="parentFormObj" + fields-prefix-name="fieldsPrefixName+''+$index" + read-only="readOnly"> + <!--path="{{path}}"--> + </select-fields-structure> + </div> + <!--<div class="add-btn add-list-item" data-tests-id="add-list-item"--> + <!--data-ng-class="{'disabled': readOnly}" data-ng-click="listNewItem.value='{}';addListItem();">Add</div>--> + </div> + + </div> +</div> diff --git a/catalog-ui/src/app/directives/select-property-types/select-type-list/select-type-list-directive.less b/catalog-ui/src/app/directives/select-property-types/select-type-list/select-type-list-directive.less new file mode 100644 index 0000000000..71263f2642 --- /dev/null +++ b/catalog-ui/src/app/directives/select-property-types/select-type-list/select-type-list-directive.less @@ -0,0 +1,85 @@ +.list-new-item{ + float: left; + width: 50%; + min-width: 221px; + margin-right: 15px; + input{ + min-width: 221px; + } +} + +.list-value-items{ + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + border: 1px solid @main_color_o; + padding-bottom: 10px; + min-height: 100px; + clear: both; + background-color: white; + .list-value-item{ + display: inline-block; + background-color: @tlv_color_v; + margin: 10px 0 0 10px; + padding: 0 8px; + .delete-list-item{ + margin: 0 0 0 2px; + .hand; + } + } +} + +.add-btn { + .f-color.a; + .f-type._14_m; + .hand; + + &.add-list-item { + float: left; + margin-top: 5px; + width: 44px; + } + + &:before { + .sprite-new; + .plus-icon; + margin-right: 5px; + content: ""; + + } + &:hover { + .f-color.b; + &:before { + .sprite-new; + .plus-icon-hover; + } + } + +} + +.dt-list{ + display: table-caption; + .dt-list-item { + border-radius: 3px; + background-color: @tlv_color_v; + display: inline-block; + .delete-dt-list-item{ + float: right; + position: relative; + top: 5px; + right: 5px; + .sprite-new; + .delete-icon; + &:hover{ + .delete-icon-hover; + } + } + .data-type-name{ + margin-right: 16px; + } + } + &>.add-list-item{ + float:none; + } +} + diff --git a/catalog-ui/src/app/directives/select-property-types/select-type-list/select-type-list-directive.ts b/catalog-ui/src/app/directives/select-property-types/select-type-list/select-type-list-directive.ts new file mode 100644 index 0000000000..d277040798 --- /dev/null +++ b/catalog-ui/src/app/directives/select-property-types/select-type-list/select-type-list-directive.ts @@ -0,0 +1,108 @@ +/** + * Created by rcohen on 9/15/2016. + */ +'use strict'; +import {DataTypesService} from "app/services/data-types-service"; +import {SchemaProperty} from "app/models/aschema-property"; +import {ValidationUtils, PROPERTY_TYPES} from "app/utils"; + +export interface ISelectTypeListScope extends ng.IScope { + parentFormObj:ng.IFormController; + schemaProperty:SchemaProperty; + isSchemaTypeDataType:boolean; + valueObjRef:any; + propertyNameValidationPattern:RegExp; + fieldsPrefixName:string; + readOnly:boolean; + listDefaultValue:any; + listNewItem:any; + maxLength:number; + dataTypesService:DataTypesService; + + getValidationPattern(type:string):RegExp; + validateIntRange(value:string):boolean; + addListItem():void; + deleteListItem(listItemIndex:number):void +} + +export class SelectTypeListDirective implements ng.IDirective { + + constructor(private DataTypesService:DataTypesService, + private PropertyNameValidationPattern:RegExp, + private ValidationUtils:ValidationUtils) { + } + + scope = { + valueObjRef: '=',//ref to list object in the parent value object + schemaProperty: '=',//get the schema.property object + parentFormObj: '=',//ref to parent form (get angular form object) + fieldsPrefixName: '=',//prefix for form fields names + readOnly: '=',//is form read only + defaultValue: '@',//this list default value + maxLength: '=', + path: '@' + }; + + restrict = 'E'; + replace = true; + template = ():string => { + return require('./select-type-list-directive.html'); + }; + + link = (scope:ISelectTypeListScope, element:any, $attr:any) => { + scope.dataTypesService = this.DataTypesService; + scope.propertyNameValidationPattern = this.PropertyNameValidationPattern; + + //reset valueObjRef when schema type is changed + scope.$watchCollection('schemaProperty.type', (newData:any):void => { + scope.isSchemaTypeDataType = this.DataTypesService.isDataTypeForSchemaType(scope.schemaProperty); + //insert 1 empty item dt by default + if (scope.isSchemaTypeDataType && (!scope.valueObjRef || !scope.valueObjRef.length)) { + scope.valueObjRef = scope.valueObjRef || []; + scope.valueObjRef.push({}); + } + }); + + //when user brows between properties in "edit property form" + scope.$watchCollection('fieldsPrefixName', (newData:any):void => { + scope.listNewItem = {value: ''}; + + if ($attr.defaultValue) { + scope.listDefaultValue = JSON.parse($attr.defaultValue); + } + }); + + scope.getValidationPattern = (type:string):RegExp => { + return this.ValidationUtils.getValidationPattern(type); + }; + + scope.validateIntRange = (value:string):boolean => { + return !value || this.ValidationUtils.validateIntRange(value); + }; + + scope.addListItem = ():void => { + scope.valueObjRef = scope.valueObjRef || []; + let newVal = ((scope.schemaProperty.simpleType || scope.schemaProperty.type) == PROPERTY_TYPES.STRING ? scope.listNewItem.value : JSON.parse(scope.listNewItem.value)); + scope.valueObjRef.push(newVal); + scope.listNewItem.value = ""; + }; + + scope.deleteListItem = (listItemIndex:number):void => { + scope.valueObjRef.splice(listItemIndex, 1); + if (!scope.valueObjRef.length) { + if (scope.listDefaultValue) { + angular.copy(scope.listDefaultValue, scope.valueObjRef); + } + } + }; + }; + + public static factory = (DataTypesService:DataTypesService, + PropertyNameValidationPattern:RegExp, + ValidationUtils:ValidationUtils)=> { + return new SelectTypeListDirective(DataTypesService, PropertyNameValidationPattern, ValidationUtils); + }; +} + +SelectTypeListDirective.factory.$inject = ['Sdc.Services.DataTypesService', 'PropertyNameValidationPattern', 'ValidationUtils']; + diff --git a/catalog-ui/src/app/directives/select-property-types/select-type-map/select-type-map-directive.html b/catalog-ui/src/app/directives/select-property-types/select-type-map/select-type-map-directive.html new file mode 100644 index 0000000000..a56428e5c2 --- /dev/null +++ b/catalog-ui/src/app/directives/select-property-types/select-type-map/select-type-map-directive.html @@ -0,0 +1,56 @@ +<div> + <div data-ng-repeat="i in getNumber(mapKeys.length) track by $index" class="map-item" data-ng-class="{'primitive-value-map':!isSchemaTypeDataType}"> + <div class="i-sdc-form-item map-item-field" data-ng-class="{error:(parentFormObj['mapKey'+fieldsPrefixName+$index].$dirty && parentFormObj['mapKey'+fieldsPrefixName+$index].$invalid)}"> + <label class="i-sdc-form-label required">Key</label> + <input class="i-sdc-form-input" + data-tests-id="mapKey{{fieldsPrefixName}}{{$index}}" + data-ng-model="mapKeys[$index]" + type="text" + data-ng-maxlength="50" + maxlength="50" + name="mapKey{{fieldsPrefixName}}{{$index}}" + data-ng-model-options="{ debounce: 200 }" + data-ng-change="changeKeyOfMap(mapKeys[$index], $index,'mapKey'+fieldsPrefixName+$index);$event.stopPropagation();" + data-ng-disabled="readOnly" + data-required + autofocus/> + </div> + <div data-ng-if="!isSchemaTypeDataType" class="i-sdc-form-item map-item-field" data-ng-class="{error:(parentFormObj['mapValue'+fieldsPrefixName+$index].$dirty && parentFormObj['mapValue'+fieldsPrefixName+$index].$invalid)}"> + <label class="i-sdc-form-label required">Value</label> + <input class="i-sdc-form-input" + ng-if="!((schemaProperty.simpleType||schemaProperty.type) == 'boolean')" + data-ng-disabled="readOnly" + data-ng-model="valueObjRef[mapKeys[$index]]" + type="text" + name="mapValue{{fieldsPrefixName}}{{$index}}" + data-tests-id="mapValue{{fieldsPrefixName}}{{$index}}" + data-ng-change="!parentFormObj['mapValue'+fieldsPrefixName+$index].$error.pattern && parseToCorrectType(valueObjRef, key, (schemaProperty.simpleType||schemaProperty.type))" + data-ng-model-options="{ debounce: 200 }" + data-ng-maxlength="maxLength" + maxlength="{{maxLength}}" + data-required + autofocus /> + <select class="i-sdc-form-select" + data-tests-id="mapValue{{fieldsPrefixName}}{{$index}}" + ng-if="(schemaProperty.simpleType||schemaProperty.type) == 'boolean'" + data-ng-disabled="readOnly" + name="mapValue{{fieldsPrefixName}}{{$index}}" + data-ng-model="valueObjRef[mapKeys[$index]]" + data-required> + <option value="true">true</option> + <option value="false">false</option> + </select> + </div> + <div data-ng-if="isSchemaTypeDataType" class="i-sdc-form-item map-item-field"> + <label class="i-sdc-form-label">Value</label> + <select-fields-structure value-obj-ref="valueObjRef[mapKeys[$index]]" + type-name="schemaProperty.type" + parent-form-obj="parentFormObj" + fields-prefix-name="'mapValue'+fieldsPrefixName+''+$index" + read-only="readOnly"> + <!--path="{{path + '#' + mapKeys[$index]}}"--> + </select-fields-structure> + </div> + </div> +</div> + diff --git a/catalog-ui/src/app/directives/select-property-types/select-type-map/select-type-map-directive.less b/catalog-ui/src/app/directives/select-property-types/select-type-map/select-type-map-directive.less new file mode 100644 index 0000000000..2480b626f2 --- /dev/null +++ b/catalog-ui/src/app/directives/select-property-types/select-type-map/select-type-map-directive.less @@ -0,0 +1,83 @@ +.add-map-item{ + &:nth-child(odd){ + float: right; + } + &:nth-child(1){ + float: none; + .add-btn{ + float: none; + } + } + width: 400px; + .add-btn{ + width: 44px; + float: right; + } + &.schema-data-type{ + float:none; + .add-btn{ + float: none; + } + } +} + +.add-btn { + .f-color.a; + .f-type._14_m; + .hand; + + &:before { + .sprite-new; + .plus-icon; + margin-right: 5px; + content: ""; + + } + &:hover { + .f-color.b; + &:before { + .sprite-new; + .plus-icon-hover; + } + } + +} + +.map-item{ + min-width: 389px; + min-height: 65px; + background-color: @tlv_color_v; + border-radius: 3px; + margin-bottom: 8px; + float: left; + display: flex; + &:nth-child(even).primitive-value-map{ + float: right; + } + .delete-map-item { + float: right; + position: relative; + top: 5px; + right: 5px; + .sprite-new; + .delete-icon; + &:hover{ + .delete-icon-hover; + } + } + .map-item-field { + margin: 7px 12px !important; + float: left; + min-width: 170px; + min-height: 50px; + select{ + width:171px; + } + input[type="text"]{ + width: 170px; + } + &>.data-type-fields-structure{ + padding: 0; + } + } +} diff --git a/catalog-ui/src/app/directives/select-property-types/select-type-map/select-type-map-directive.ts b/catalog-ui/src/app/directives/select-property-types/select-type-map/select-type-map-directive.ts new file mode 100644 index 0000000000..19df8dfb71 --- /dev/null +++ b/catalog-ui/src/app/directives/select-property-types/select-type-map/select-type-map-directive.ts @@ -0,0 +1,139 @@ +/** + * Created by rcohen on 9/15/2016. + */ +'use strict'; +import {SchemaProperty} from "app/models"; +import {DataTypesService} from "app/services"; +import {ValidationUtils, PROPERTY_TYPES} from "app/utils"; + +export interface ISelectTypeMapScope extends ng.IScope { + parentFormObj:ng.IFormController; + schemaProperty:SchemaProperty; + isSchemaTypeDataType:boolean; + valueObjRef:any; + mapKeys:Array<string>;//array of map keys + MapKeyValidationPattern:RegExp; + fieldsPrefixName:string; + readOnly:boolean; + mapDefaultValue:any; + maxLength:number; + dataTypesService:DataTypesService; + + getValidationPattern(type:string):RegExp; + validateIntRange(value:string):boolean; + changeKeyOfMap(newKey:string, index:number, fieldName:string):void; + deleteMapItem(index:number):void; + addMapItemFields():void; + parseToCorrectType(objectOfValues:any, locationInObj:string, type:string):void; + getNumber(num:number):Array<any>; +} + + +export class SelectTypeMapDirective implements ng.IDirective { + + constructor(private DataTypesService:DataTypesService, + private MapKeyValidationPattern:RegExp, + private ValidationUtils:ValidationUtils, + private $timeout:ng.ITimeoutService) { + } + + scope = { + valueObjRef: '=',//ref to map object in the parent value object + schemaProperty: '=',//get the schema.property object + parentFormObj: '=',//ref to parent form (get angular form object) + fieldsPrefixName: '=',//prefix for form fields names + readOnly: '=',//is form read only + defaultValue: '@',//this map default value + maxLength: '=', + path: '@' + }; + + restrict = 'E'; + replace = true; + template = ():string => { + return require('./select-type-map-directive.html'); + }; + + link = (scope:ISelectTypeMapScope, element:any, $attr:any) => { + + scope.dataTypesService = this.DataTypesService; + scope.MapKeyValidationPattern = this.MapKeyValidationPattern; + + //reset valueObjRef and mapKeys when schema type is changed + scope.$watchCollection('schemaProperty.type', (newData:any):void => { + scope.isSchemaTypeDataType = this.DataTypesService.isDataTypeForSchemaType(scope.schemaProperty); + if (scope.valueObjRef) { + scope.mapKeys = Object.keys(scope.valueObjRef); + } + }); + + //when user brows between properties in "edit property form" + scope.$watchCollection('fieldsPrefixName', (newData:any):void => { + if (!scope.valueObjRef) { + scope.valueObjRef = {}; + } + scope.mapKeys = Object.keys(scope.valueObjRef); + + if ($attr.defaultValue) { + scope.mapDefaultValue = JSON.parse($attr.defaultValue); + } + }); + + //return dummy array in order to prevent rendering map-keys ng-repeat again when a map key is changed + scope.getNumber = (num:number):Array<any> => { + return new Array(num); + }; + + scope.getValidationPattern = (type:string):RegExp => { + return this.ValidationUtils.getValidationPattern(type); + }; + + scope.validateIntRange = (value:string):boolean => { + return !value || this.ValidationUtils.validateIntRange(value); + }; + + scope.changeKeyOfMap = (newKey:string, index:number, fieldName:string):void => { + let oldKey = Object.keys(scope.valueObjRef)[index]; + let existsKeyIndex = Object.keys(scope.valueObjRef).indexOf(newKey); + if (existsKeyIndex > -1 && existsKeyIndex != index) { + scope.parentFormObj[fieldName].$setValidity('keyExist', false); + } else { + scope.parentFormObj[fieldName].$setValidity('keyExist', true); + if (!scope.parentFormObj[fieldName].$invalid) { + angular.copy(JSON.parse(JSON.stringify(scope.valueObjRef).replace('"' + oldKey + '":', '"' + newKey + '":')), scope.valueObjRef);//update key + } + } + }; + + scope.deleteMapItem = (index:number):void=> { + delete scope.valueObjRef[scope.mapKeys[index]]; + scope.mapKeys.splice(index, 1); + if (!scope.mapKeys.length) {//only when user removes all pairs of key-value fields - put the default + if (scope.mapDefaultValue) { + angular.copy(scope.mapDefaultValue, scope.valueObjRef); + scope.mapKeys = Object.keys(scope.valueObjRef); + } + } + }; + + scope.addMapItemFields = ():void => { + scope.valueObjRef[''] = null; + scope.mapKeys = Object.keys(scope.valueObjRef); + }; + + scope.parseToCorrectType = (objectOfValues:any, locationInObj:string, type:string):void => { + if (objectOfValues[locationInObj] && type != PROPERTY_TYPES.STRING) { + objectOfValues[locationInObj] = JSON.parse(objectOfValues[locationInObj]); + } + } + }; + + public static factory = (DataTypesService:DataTypesService, + MapKeyValidationPattern:RegExp, + ValidationUtils:ValidationUtils, + $timeout:ng.ITimeoutService)=> { + return new SelectTypeMapDirective(DataTypesService, MapKeyValidationPattern, ValidationUtils, $timeout); + }; +} + +SelectTypeMapDirective.factory.$inject = ['Sdc.Services.DataTypesService', 'MapKeyValidationPattern', 'ValidationUtils', '$timeout']; |