2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
22 * Created by rcohen on 9/15/2016.
25 import {ValidationUtils, PROPERTY_TYPES, PROPERTY_DATA} from "app/utils";
26 import {DataTypesService} from "app/services";
27 import {SchemaProperty, PropertyModel, DataTypesMap} from "app/models";
28 import {InstanceFeDetails} from "app/models/instance-fe-details";
29 import {ToscaGetFunction} from "app/models/tosca-get-function";
30 import {SubPropertyToscaFunction} from "app/models/sub-property-tosca-function";
32 export interface ITypeMapScope extends ng.IScope {
33 parentFormObj:ng.IFormController;
34 schemaProperty:SchemaProperty;
35 parentProperty:PropertyModel;
36 componentInstanceMap: Map<string, InstanceFeDetails>;
37 isMapKeysUnique:boolean;
38 isSchemaTypeDataType:boolean;
40 mapKeys:Array<string>;//array of map keys
41 mapKeysStatic:Array<string>;
42 MapKeyValidationPattern:RegExp;
43 fieldsPrefixName:string;
49 showToscaFunction: Array<boolean>;
52 getValidationPattern(type:string):RegExp;
53 validateIntRange(value:string):boolean;
54 changeKeyOfMap(newKey:string, index:number, fieldName:string):void;
55 deleteMapItem(index:number):void;
56 addMapItemFields():void;
57 parseToCorrectType(objectOfValues:any, locationInObj:string, type:string):void;
58 getNumber(num:number):Array<any>;
59 validateSubToscaFunction(key:string):boolean;
60 onEnableTosca(toscaFlag:boolean,index:number);
61 onGetToscaFunction(toscaGetFunction: ToscaGetFunction, key:string);
65 export class TypeMapDirective implements ng.IDirective {
67 constructor(private DataTypesService:DataTypesService,
68 private MapKeyValidationPattern:RegExp,
69 private ValidationUtils:ValidationUtils,
70 private $timeout:ng.ITimeoutService) {
74 valueObjRef: '=',//ref to map object in the parent value object
75 componentInstanceMap: '=',
76 schemaProperty: '=',//get the schema.property object
77 parentFormObj: '=',//ref to parent form (get angular form object)
78 fieldsPrefixName: '=',//prefix for form fields names
79 readOnly: '=',//is form read only
80 defaultValue: '@',//this map default value
90 template = (): string => {
91 return require('./type-map-directive.html');
94 private isDataTypeForSchemaType = (property:SchemaProperty, types:DataTypesMap):boolean=> {
95 property.simpleType = "";
96 if (property.type && PROPERTY_DATA.TYPES.indexOf(property.type) > -1) {
99 let simpleType = this.getTypeForDataTypeDerivedFromSimple(property.type, types);
101 property.simpleType = simpleType;
107 private getTypeForDataTypeDerivedFromSimple = (dataTypeName:string, types:DataTypesMap):string => {
108 if (!types[dataTypeName]) {
111 if (types[dataTypeName].derivedFromName == "tosca.datatypes.Root" || types[dataTypeName].properties) {
114 if (PROPERTY_DATA.SIMPLE_TYPES.indexOf(types[dataTypeName].derivedFromName) > -1) {
115 return types[dataTypeName].derivedFromName
117 return this.getTypeForDataTypeDerivedFromSimple(types[dataTypeName].derivedFromName, types);
120 link = (scope:ITypeMapScope, element:any, $attr:any) => {
121 scope.showAddBtn = angular.isDefined(scope.showAddBtn) ? scope.showAddBtn : true;
122 scope.MapKeyValidationPattern = this.MapKeyValidationPattern;
123 scope.isMapKeysUnique = true;
124 if (scope.mapKeys === undefined) {
125 scope.mapKeys = Object.keys(scope.valueObjRef);
127 scope.showToscaFunction = new Array(scope.mapKeys.length);
128 scope.mapKeys.forEach((key, index) => {
129 scope.showToscaFunction[index] = false;
130 if (scope.parentProperty.subPropertyToscaFunctions != null) {
131 scope.parentProperty.subPropertyToscaFunctions.forEach(SubPropertyToscaFunction => {
132 if (SubPropertyToscaFunction.subPropertyPath.indexOf(key) != -1) {
133 scope.showToscaFunction[index] = true;
139 //reset valueObjRef and mapKeys when schema type is changed
140 scope.$watchCollection('schemaProperty.type', (newData:any):void => {
141 scope.isSchemaTypeDataType = this.isDataTypeForSchemaType(scope.schemaProperty, scope.types);
142 if (scope.valueObjRef) {
143 scope.mapKeys = Object.keys(scope.valueObjRef);
144 //keeping another copy of the keys, as the mapKeys gets overridden sometimes
145 scope.mapKeysStatic = Object.keys(scope.valueObjRef);
149 scope.$watchCollection('valueObjRef', (newData: any): void => {
150 scope.mapKeys = Object.keys(scope.valueObjRef);
151 scope.mapKeysStatic = Object.keys(scope.valueObjRef);
154 //when user brows between properties in "edit property form"
155 scope.$watchCollection('fieldsPrefixName', (newData:any):void => {
156 if (!scope.valueObjRef) {
157 scope.valueObjRef = {};
159 scope.mapKeys = Object.keys(scope.valueObjRef);
160 //keeping another copy of the keys, as the mapKeys gets overridden sometimes
161 scope.mapKeysStatic = Object.keys(scope.valueObjRef);
163 if ($attr.defaultValue) {
164 scope.mapDefaultValue = JSON.parse($attr.defaultValue);
168 //return dummy array in order to prevent rendering map-keys ng-repeat again when a map key is changed
169 scope.getNumber = (num:number):Array<any> => {
170 return new Array(num);
173 scope.getValidationPattern = (type:string):RegExp => {
174 return this.ValidationUtils.getValidationPattern(type);
177 scope.validateIntRange = (value:string):boolean => {
178 return !value || this.ValidationUtils.validateIntRange(value);
181 scope.changeKeyOfMap = (newKey:string, index:number, fieldName:string):void => {
182 const currentKeySet = Object.keys(scope.valueObjRef);
183 const currentKey = currentKeySet[index];
184 const existingKeyIndex = currentKeySet.indexOf(newKey);
185 if (existingKeyIndex > -1 && existingKeyIndex != index) {
186 scope.parentFormObj[fieldName].$setValidity('keyExist', false);
187 scope.isMapKeysUnique = false;
191 scope.parentFormObj[fieldName].$setValidity('keyExist', true);
192 scope.isMapKeysUnique = true;
193 if (!scope.parentFormObj[fieldName].$invalid) {
194 //To preserve the order of the keys, delete each one and recreate
196 angular.copy(scope.valueObjRef, newObj);
197 angular.forEach(newObj, function (value: any, key: string) {
198 delete scope.valueObjRef[key];
199 if (key == currentKey) {
200 scope.valueObjRef[newKey] = value;
202 scope.valueObjRef[key] = value;
208 scope.deleteMapItem = (index:number):void=> {
209 const keyToChange = scope.mapKeys[index];
210 delete scope.valueObjRef[scope.mapKeys[index]];
211 scope.mapKeys.splice(index, 1);
212 scope.showToscaFunction.splice(index, 1);
213 if (scope.parentProperty.subPropertyToscaFunctions != null) {
214 let subToscaFunctionList : Array<SubPropertyToscaFunction> = [];
215 scope.parentProperty.subPropertyToscaFunctions.forEach((SubPropertyToscaFunction, index) => {
216 if (SubPropertyToscaFunction.subPropertyPath.indexOf(keyToChange) == -1) {
217 subToscaFunctionList.push(SubPropertyToscaFunction);
220 scope.parentProperty.subPropertyToscaFunctions = subToscaFunctionList;
222 if (!scope.mapKeys.length) {//only when user removes all pairs of key-value fields - put the default
223 if (scope.mapDefaultValue) {
224 angular.copy(scope.mapDefaultValue, scope.valueObjRef);
225 scope.mapKeys = Object.keys(scope.valueObjRef);
230 scope.onEnableTosca = (toscaFlag:boolean,flagIndex:number):void => {
231 scope.showToscaFunction[flagIndex] = toscaFlag;
232 scope.valueObjRef[scope.mapKeys[flagIndex]] = null;
234 if (scope.parentProperty.subPropertyToscaFunctions != null) {
235 let subToscaFunctionList : Array<SubPropertyToscaFunction> = [];
236 scope.parentProperty.subPropertyToscaFunctions.forEach((SubPropertyToscaFunction, index) => {
237 if (SubPropertyToscaFunction.subPropertyPath.indexOf(scope.mapKeys[flagIndex]) == -1) {
238 subToscaFunctionList.push(SubPropertyToscaFunction);
241 scope.parentProperty.subPropertyToscaFunctions = subToscaFunctionList;
246 scope.onGetToscaFunction = (toscaGetFunction: ToscaGetFunction, key:string): void => {
247 if (scope.parentProperty.subPropertyToscaFunctions != null) {
248 scope.parentProperty.subPropertyToscaFunctions.forEach(SubPropertyToscaFunction => {
249 if (SubPropertyToscaFunction.subPropertyPath.indexOf(key) != -1) {
250 SubPropertyToscaFunction.toscaFunction = toscaGetFunction;
256 if (scope.parentProperty.subPropertyToscaFunctions == null){
257 scope.parentProperty.subPropertyToscaFunctions = [];
259 let subPropertyToscaFunction = new SubPropertyToscaFunction();
260 subPropertyToscaFunction.toscaFunction = toscaGetFunction;
261 subPropertyToscaFunction.subPropertyPath = [key];
262 scope.parentProperty.subPropertyToscaFunctions.push(subPropertyToscaFunction);
265 scope.addMapItemFields = ():void => {
266 scope.valueObjRef[''] = null;
267 scope.mapKeys = Object.keys(scope.valueObjRef);
268 scope.showToscaFunction.push(false);
271 scope.parseToCorrectType = (objectOfValues:any, locationInObj:string, type:string):void => {
272 if (objectOfValues[locationInObj] && type != PROPERTY_TYPES.STRING) {
273 objectOfValues[locationInObj] = JSON.parse(objectOfValues[locationInObj]);
277 scope.validateSubToscaFunction = (key:string):boolean => {
278 if (scope.parentProperty.subPropertyToscaFunctions != null) {
279 scope.parentProperty.subPropertyToscaFunctions.forEach(SubPropertyToscaFunction => {
280 if (SubPropertyToscaFunction.subPropertyPath.indexOf(key) != -1) {
289 public static factory = (DataTypesService:DataTypesService,
290 MapKeyValidationPattern:RegExp,
291 ValidationUtils:ValidationUtils,
292 $timeout:ng.ITimeoutService)=> {
293 return new TypeMapDirective(DataTypesService, MapKeyValidationPattern, ValidationUtils, $timeout);
297 TypeMapDirective.factory.$inject = ['Sdc.Services.DataTypesService', 'MapKeyValidationPattern', 'ValidationUtils', '$timeout'];