Catalog alignment
[sdc.git] / catalog-ui / src / app / directives / property-types / type-map / type-map-directive.ts
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
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
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
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=========================================================
19  */
20
21 /**
22  * Created by rcohen on 9/15/2016.
23  */
24 'use strict';
25 import {ValidationUtils, PROPERTY_TYPES} from "app/utils";
26 import {DataTypesService} from "app/services";
27 import {SchemaProperty} from "app/models";
28
29 export interface ITypeMapScope extends ng.IScope {
30     parentFormObj:ng.IFormController;
31     schemaProperty:SchemaProperty;
32     isMapKeysUnique:boolean;
33     isSchemaTypeDataType:boolean;
34     valueObjRef:any;
35     mapKeys:Array<string>;//array of map keys
36     mapKeysStatic:Array<string>;
37     MapKeyValidationPattern:RegExp;
38     fieldsPrefixName:string;
39     readOnly:boolean;
40     mapDefaultValue:any;
41     maxLength:number;
42     constraints:string[];
43
44     getValidationPattern(type:string):RegExp;
45     validateIntRange(value:string):boolean;
46     changeKeyOfMap(newKey:string, index:number, fieldName:string):void;
47     deleteMapItem(index:number):void;
48     addMapItemFields():void;
49     parseToCorrectType(objectOfValues:any, locationInObj:string, type:string):void;
50     getNumber(num:number):Array<any>;
51 }
52
53
54 export class TypeMapDirective implements ng.IDirective {
55
56     constructor(private DataTypesService:DataTypesService,
57                 private MapKeyValidationPattern:RegExp,
58                 private ValidationUtils:ValidationUtils,
59                 private $timeout:ng.ITimeoutService) {
60     }
61
62     scope = {
63         valueObjRef: '=',//ref to map object in the parent value object
64         schemaProperty: '=',//get the schema.property object
65         parentFormObj: '=',//ref to parent form (get angular form object)
66         fieldsPrefixName: '=',//prefix for form fields names
67         readOnly: '=',//is form read only
68         defaultValue: '@',//this map default value
69         maxLength: '=',
70         constraints: '='
71         
72     };
73
74     restrict = 'E';
75     replace = true;
76     template = ():string => {
77         return require('./type-map-directive.html');
78     };
79
80     link = (scope:ITypeMapScope, element:any, $attr:any) => {
81         scope.MapKeyValidationPattern = this.MapKeyValidationPattern;
82         scope.isMapKeysUnique = true;
83
84         //reset valueObjRef and mapKeys when schema type is changed
85         scope.$watchCollection('schemaProperty.type', (newData:any):void => {
86             scope.isSchemaTypeDataType = this.DataTypesService.isDataTypeForSchemaType(scope.schemaProperty);
87             if (scope.valueObjRef) {
88                 scope.mapKeys = Object.keys(scope.valueObjRef);
89                 //keeping another copy of the keys, as the mapKeys gets overridden sometimes
90                 scope.mapKeysStatic = Object.keys(scope.valueObjRef);
91             }
92         });
93
94         //when user brows between properties in "edit property form"
95         scope.$watchCollection('fieldsPrefixName', (newData:any):void => {
96             if (!scope.valueObjRef) {
97                 scope.valueObjRef = {};
98             }
99             scope.mapKeys = Object.keys(scope.valueObjRef);
100             //keeping another copy of the keys, as the mapKeys gets overridden sometimes
101             scope.mapKeysStatic = Object.keys(scope.valueObjRef);
102
103             if ($attr.defaultValue) {
104                 scope.mapDefaultValue = JSON.parse($attr.defaultValue);
105             }
106         });
107
108         //return dummy array in order to prevent rendering map-keys ng-repeat again when a map key is changed
109         scope.getNumber = (num:number):Array<any> => {
110             return new Array(num);
111         };
112
113         scope.getValidationPattern = (type:string):RegExp => {
114             return this.ValidationUtils.getValidationPattern(type);
115         };
116
117         scope.validateIntRange = (value:string):boolean => {
118             return !value || this.ValidationUtils.validateIntRange(value);
119         };
120
121         scope.changeKeyOfMap = (newKey:string, index:number, fieldName:string):void => {
122             let oldKey = Object.keys(scope.valueObjRef)[index];
123             let existsKeyIndex = Object.keys(scope.valueObjRef).indexOf(newKey);
124             if (existsKeyIndex > -1 && existsKeyIndex != index) {
125                 scope.parentFormObj[fieldName].$setValidity('keyExist', false);
126                 scope.isMapKeysUnique = false;
127             } else {
128                 scope.parentFormObj[fieldName].$setValidity('keyExist', true);
129                 scope.isMapKeysUnique = true;
130                 if (!scope.parentFormObj[fieldName].$invalid) {
131                     //To preserve the order of the keys, delete each one and recreate
132                     let newObj = {};
133                     angular.copy(scope.valueObjRef , newObj);
134                     angular.forEach(newObj,function(value:any,key:string){
135                         delete scope.valueObjRef[key];
136                         if(key == oldKey){
137                             scope.valueObjRef[newKey] = value;
138                         }else{
139                             scope.valueObjRef[key] = value;
140                         }
141                     });
142                 }
143             }
144         };
145
146         scope.deleteMapItem = (index:number):void=> {
147             delete scope.valueObjRef[scope.mapKeys[index]];
148             scope.mapKeys.splice(index, 1);
149             if (!scope.mapKeys.length) {//only when user removes all pairs of key-value fields - put the default
150                 if (scope.mapDefaultValue) {
151                     angular.copy(scope.mapDefaultValue, scope.valueObjRef);
152                     scope.mapKeys = Object.keys(scope.valueObjRef);
153                 }
154             }
155         };
156
157         scope.addMapItemFields = ():void => {
158             scope.valueObjRef[''] = null;
159             scope.mapKeys = Object.keys(scope.valueObjRef);
160         };
161
162         scope.parseToCorrectType = (objectOfValues:any, locationInObj:string, type:string):void => {
163             if (objectOfValues[locationInObj] && type != PROPERTY_TYPES.STRING) {
164                 objectOfValues[locationInObj] = JSON.parse(objectOfValues[locationInObj]);
165             }
166         }
167     };
168
169     public static factory = (DataTypesService:DataTypesService,
170                              MapKeyValidationPattern:RegExp,
171                              ValidationUtils:ValidationUtils,
172                              $timeout:ng.ITimeoutService)=> {
173         return new TypeMapDirective(DataTypesService, MapKeyValidationPattern, ValidationUtils, $timeout);
174     };
175 }
176
177 TypeMapDirective.factory.$inject = ['Sdc.Services.DataTypesService', 'MapKeyValidationPattern', 'ValidationUtils', '$timeout'];