[sdc] rebase update
[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     MapKeyValidationPattern:RegExp;
37     fieldsPrefixName:string;
38     readOnly:boolean;
39     mapDefaultValue:any;
40     maxLength:number;
41
42     getValidationPattern(type:string):RegExp;
43     validateIntRange(value:string):boolean;
44     changeKeyOfMap(newKey:string, index:number, fieldName:string):void;
45     deleteMapItem(index:number):void;
46     addMapItemFields():void;
47     parseToCorrectType(objectOfValues:any, locationInObj:string, type:string):void;
48     getNumber(num:number):Array<any>;
49 }
50
51
52 export class TypeMapDirective implements ng.IDirective {
53
54     constructor(private DataTypesService:DataTypesService,
55                 private MapKeyValidationPattern:RegExp,
56                 private ValidationUtils:ValidationUtils,
57                 private $timeout:ng.ITimeoutService) {
58     }
59
60     scope = {
61         valueObjRef: '=',//ref to map object in the parent value object
62         schemaProperty: '=',//get the schema.property object
63         parentFormObj: '=',//ref to parent form (get angular form object)
64         fieldsPrefixName: '=',//prefix for form fields names
65         readOnly: '=',//is form read only
66         defaultValue: '@',//this map default value
67         maxLength: '='
68     };
69
70     restrict = 'E';
71     replace = true;
72     template = ():string => {
73         return require('./type-map-directive.html');
74     };
75
76     link = (scope:ITypeMapScope, element:any, $attr:any) => {
77         scope.MapKeyValidationPattern = this.MapKeyValidationPattern;
78         scope.isMapKeysUnique = true;
79
80         //reset valueObjRef and mapKeys when schema type is changed
81         scope.$watchCollection('schemaProperty.type', (newData:any):void => {
82             scope.isSchemaTypeDataType = this.DataTypesService.isDataTypeForSchemaType(scope.schemaProperty);
83             if (scope.valueObjRef) {
84                 scope.mapKeys = Object.keys(scope.valueObjRef);
85             }
86         });
87
88         //when user brows between properties in "edit property form"
89         scope.$watchCollection('fieldsPrefixName', (newData:any):void => {
90             if (!scope.valueObjRef) {
91                 scope.valueObjRef = {};
92             }
93             scope.mapKeys = Object.keys(scope.valueObjRef);
94
95             if ($attr.defaultValue) {
96                 scope.mapDefaultValue = JSON.parse($attr.defaultValue);
97             }
98         });
99
100         //return dummy array in order to prevent rendering map-keys ng-repeat again when a map key is changed
101         scope.getNumber = (num:number):Array<any> => {
102             return new Array(num);
103         };
104
105         scope.getValidationPattern = (type:string):RegExp => {
106             return this.ValidationUtils.getValidationPattern(type);
107         };
108
109         scope.validateIntRange = (value:string):boolean => {
110             return !value || this.ValidationUtils.validateIntRange(value);
111         };
112
113         scope.changeKeyOfMap = (newKey:string, index:number, fieldName:string):void => {
114             let oldKey = Object.keys(scope.valueObjRef)[index];
115             let existsKeyIndex = Object.keys(scope.valueObjRef).indexOf(newKey);
116             if (existsKeyIndex > -1 && existsKeyIndex != index) {
117                 scope.parentFormObj[fieldName].$setValidity('keyExist', false);
118                 scope.isMapKeysUnique = false;
119             } else {
120                 scope.parentFormObj[fieldName].$setValidity('keyExist', true);
121                 scope.isMapKeysUnique = true;
122                 if (!scope.parentFormObj[fieldName].$invalid) {
123                     //To preserve the order of the keys, delete each one and recreate
124                     let newObj = {};
125                     angular.copy(scope.valueObjRef , newObj);
126                     angular.forEach(newObj,function(value:any,key:string){
127                         delete scope.valueObjRef[key];
128                         if(key == oldKey){
129                             scope.valueObjRef[newKey] = value;
130                         }else{
131                             scope.valueObjRef[key] = value;
132                         }
133                     });
134                 }
135             }
136         };
137
138         scope.deleteMapItem = (index:number):void=> {
139             delete scope.valueObjRef[scope.mapKeys[index]];
140             scope.mapKeys.splice(index, 1);
141             if (!scope.mapKeys.length) {//only when user removes all pairs of key-value fields - put the default
142                 if (scope.mapDefaultValue) {
143                     angular.copy(scope.mapDefaultValue, scope.valueObjRef);
144                     scope.mapKeys = Object.keys(scope.valueObjRef);
145                 }
146             }
147         };
148
149         scope.addMapItemFields = ():void => {
150             scope.valueObjRef[''] = null;
151             scope.mapKeys = Object.keys(scope.valueObjRef);
152         };
153
154         scope.parseToCorrectType = (objectOfValues:any, locationInObj:string, type:string):void => {
155             if (objectOfValues[locationInObj] && type != PROPERTY_TYPES.STRING) {
156                 objectOfValues[locationInObj] = JSON.parse(objectOfValues[locationInObj]);
157             }
158         }
159     };
160
161     public static factory = (DataTypesService:DataTypesService,
162                              MapKeyValidationPattern:RegExp,
163                              ValidationUtils:ValidationUtils,
164                              $timeout:ng.ITimeoutService)=> {
165         return new TypeMapDirective(DataTypesService, MapKeyValidationPattern, ValidationUtils, $timeout);
166     };
167 }
168
169 TypeMapDirective.factory.$inject = ['Sdc.Services.DataTypesService', 'MapKeyValidationPattern', 'ValidationUtils', '$timeout'];