re base code
[sdc.git] / catalog-ui / src / app / directives / graphs-v2 / palette / palette.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 import * as _ from "lodash";
21 import {Component, IAppMenu, LeftPanelModel, NodesFactory, LeftPaletteComponent, CompositionCiNodeBase, ComponentInstance, Point} from "app/models";
22 import {CompositionGraphGeneralUtils} from "../composition-graph/utils/composition-graph-general-utils";
23 import {EventListenerService} from "app/services";
24 import {ResourceType, GRAPH_EVENTS, EVENTS, ComponentInstanceFactory, ModalsHandler} from "app/utils";
25 import 'sdc-angular-dragdrop';
26 import {LeftPaletteLoaderService} from "../../../services/components/utils/composition-left-palette-service";
27 import {Resource} from "app/models/components/resource";
28 import {ComponentType} from "app/utils/constants";
29 import {LeftPaletteMetadataTypes} from "../../../models/components/displayComponent";
30 import { IDirectiveLinkFn, IScope } from "angular";
31
32
33 interface IPaletteScope extends IScope{
34     components:Array<LeftPaletteComponent>;
35     currentComponent:Component;
36     model:any;
37     displaySortedCategories:any;
38     expandedSection:string;
39     dragElement:JQuery;
40     dragbleNode:{
41         event:JQueryEventObject,
42         components:LeftPaletteComponent,
43         ui:any
44     }
45
46     addInstanceClick: ()=>void; // added code
47     onPopupMouseOver: ()=>void  // added code
48     onPopupMouseOut: ()=>void   // added code
49
50     sectionClick:(section:string)=>void;
51     searchComponents:(searchText:string)=>void;
52     onMouseOver:(displayComponent:LeftPaletteComponent, elem: HTMLElement)=>void;
53     onMouseOut:(displayComponent:LeftPaletteComponent)=>void;
54
55     dragStartCallback:(event:JQueryEventObject, ui, displayComponent:LeftPaletteComponent)=>void;
56     dragStopCallback:()=>void;
57     onDragCallback:(event:JQueryEventObject) => void;
58
59     setElementTemplate:(e:JQueryEventObject)=>void;
60
61     isOnDrag:boolean;
62     isDragable:boolean;
63     isLoading:boolean;
64     isViewOnly:boolean;
65 }
66
67 export class Palette implements ng.IDirective {
68     constructor(private $log:ng.ILogService,
69                 private LeftPaletteLoaderService: LeftPaletteLoaderService,
70                 private sdcConfig,
71                 private ComponentFactory,
72                 private ComponentInstanceFactory:ComponentInstanceFactory,
73                 private NodesFactory:NodesFactory,
74                 private CompositionGraphGeneralUtils:CompositionGraphGeneralUtils,
75                 private EventListenerService:EventListenerService,
76                 private sdcMenu:IAppMenu,
77                 private ModalsHandler:ModalsHandler
78             ) {
79     }
80
81     private fetchingComponentFromServer:boolean = false;
82     private nodeHtmlSubstitute:JQuery;
83
84     scope = {
85         currentComponent: '=',
86         isViewOnly: '=',
87         isLoading: '='
88     };
89     restrict = 'E';
90     template = require('./palette.html');
91
92     link:IDirectiveLinkFn = (scope:IPaletteScope, el:JQuery) => {
93         this.LeftPaletteLoaderService.loadLeftPanel(scope.currentComponent);
94         this.nodeHtmlSubstitute = $('<div class="node-substitute"><span></span><img /></div>');
95         el.append(this.nodeHtmlSubstitute);
96         this.registerEventListenerForLeftPalette(scope);
97
98         this.initComponents(scope);
99         this.initEvents(scope);
100         this.initDragEvents(scope);
101         this._initExpandedSection(scope, '');
102         el.on('$destroy', ()=> {
103             //remove listener of download event
104             this.unRegisterEventListenerForLeftPalette(scope);
105         });
106     };
107
108
109     private registerEventListenerForLeftPalette = (scope:IPaletteScope):void => {
110         this.EventListenerService.registerObserverCallback(EVENTS.LEFT_PALETTE_UPDATE_EVENT, () => {
111             this.updateLeftPanelDisplay(scope);
112         });
113     };
114
115     private unRegisterEventListenerForLeftPalette = (scope:IPaletteScope):void => {
116         this.EventListenerService.unRegisterObserver(EVENTS.LEFT_PALETTE_UPDATE_EVENT);
117     };
118
119     private leftPanelResourceFilter(resourcesNotAbstract:Array<LeftPaletteComponent>, resourceFilterTypes:Array<string>):Array<LeftPaletteComponent> {
120         let filterResources = _.filter(resourcesNotAbstract, (component) => {
121             return resourceFilterTypes.indexOf(component.getComponentSubType()) > -1;
122         });
123         return filterResources;
124     }
125
126     private initLeftPanel(leftPanelComponents:Array<LeftPaletteComponent>, resourceFilterTypes:Array<string>):LeftPanelModel {
127         let leftPanelModel = new LeftPanelModel();
128
129         if (resourceFilterTypes && resourceFilterTypes.length) {
130             leftPanelComponents = this.leftPanelResourceFilter(leftPanelComponents, resourceFilterTypes);
131         }
132         leftPanelModel.numberOfElements = leftPanelComponents && leftPanelComponents.length || 0;
133
134         if (leftPanelComponents && leftPanelComponents.length) {
135
136             let categories:any = _.groupBy(leftPanelComponents, 'mainCategory');
137             for (let category in categories)
138                 categories[category] = _.groupBy(categories[category], 'subCategory');
139
140             leftPanelModel.sortedCategories = categories;
141         }
142         return leftPanelModel;
143     }
144
145
146     private initEvents(scope:IPaletteScope) {
147
148         scope.sectionClick = (section:string) => {
149             if (section === scope.expandedSection) {
150                 scope.expandedSection = '';
151                 return;
152             }
153             scope.expandedSection = section;
154         };
155
156         scope.onMouseOver = (displayComponent:LeftPaletteComponent, sectionElem: HTMLElement) => {
157             if (this.isGroupOrPolicy(displayComponent)) {
158                 this.EventListenerService.notifyObservers(GRAPH_EVENTS.ON_PALETTE_COMPONENT_SHOW_POPUP_PANEL, scope.currentComponent, displayComponent, sectionElem);
159             } else {
160                 if (scope.isOnDrag) {
161                     return;
162                 }
163                 scope.isOnDrag = true;
164                 this.EventListenerService.notifyObservers(GRAPH_EVENTS.ON_PALETTE_COMPONENT_HOVER_IN, displayComponent);
165                 this.$log.debug('palette::onMouseOver:: fired');
166             }
167
168         };
169
170         scope.onMouseOut = (displayComponent:LeftPaletteComponent) => {
171             if(this.isGroupOrPolicy(displayComponent)) {
172                 this.EventListenerService.notifyObservers(GRAPH_EVENTS.ON_PALETTE_COMPONENT_HIDE_POPUP_PANEL);
173             } else {
174                 scope.isOnDrag = false;
175                 this.EventListenerService.notifyObservers(GRAPH_EVENTS.ON_PALETTE_COMPONENT_HOVER_OUT);
176             }
177         };
178     }
179
180     private isGroupOrPolicy(component:LeftPaletteComponent): boolean {
181         if(component &&
182             (component.categoryType === LeftPaletteMetadataTypes.Group ||
183                 component.categoryType === LeftPaletteMetadataTypes.Policy)) {
184             return true;
185         }
186         return false;
187     }
188
189     private initComponents(scope:IPaletteScope) {
190         scope.searchComponents = (searchText:any):void => {
191             scope.displaySortedCategories = this._searchComponents(searchText, scope.model.sortedCategories);
192             this._initExpandedSection(scope, searchText);
193         };
194
195         scope.isDragable = scope.currentComponent.isComplex();
196         this.updateLeftPanelDisplay(scope);
197     }
198
199     private updateLeftPanelDisplay(scope:IPaletteScope) {
200         let entityType:string = scope.currentComponent.componentType.toLowerCase();
201         let resourceFilterTypes:Array<string> = this.sdcConfig.resourceTypesFilter[entityType];
202          scope.components = this.LeftPaletteLoaderService.getLeftPanelComponentsForDisplay(scope.currentComponent);
203         //remove the container component  from the list
204         let componentTempToDisplay = angular.copy(scope.components);
205         componentTempToDisplay = _.remove(componentTempToDisplay, function (leftPalettecomponent) {
206             return leftPalettecomponent.invariantUUID !== scope.currentComponent.invariantUUID;
207         });
208         scope.model = this.initLeftPanel(componentTempToDisplay, resourceFilterTypes);
209         scope.displaySortedCategories = angular.copy(scope.model.sortedCategories);
210     };
211
212     private _initExpandedSection(scope:IPaletteScope, searchText:string):void {
213         if (searchText == '') {
214             let isContainingCategory:boolean = false;
215             let categoryToExpand:string;
216             if (scope.currentComponent && scope.currentComponent.categories && scope.currentComponent.categories[0]) {
217                 categoryToExpand = this.sdcMenu.categoriesDictionary[scope.currentComponent.categories[0].name];
218                 for (let category in scope.model.sortedCategories) {
219                     if (categoryToExpand == category) {
220                         isContainingCategory = true;
221                         break;
222                     }
223                 }
224             }
225             isContainingCategory ? scope.expandedSection = categoryToExpand : scope.expandedSection = 'Generic';
226         }
227         else {
228             scope.expandedSection = Object.keys(scope.displaySortedCategories).sort()[0];
229         }
230     };
231
232     private initDragEvents(scope:IPaletteScope) {
233         scope.dragStartCallback = (event:IDragDropEvent, ui, displayComponent:LeftPaletteComponent):void => {
234             if (scope.isLoading || !scope.isDragable || scope.isViewOnly || this.isGroupOrPolicy(displayComponent)) {
235                 return;
236             }
237
238             let component = _.find(this.LeftPaletteLoaderService.getLeftPanelComponentsForDisplay(scope.currentComponent), (componentFullData:LeftPaletteComponent) => {
239                 return displayComponent.uniqueId === componentFullData.uniqueId;
240             });
241             this.EventListenerService.notifyObservers(GRAPH_EVENTS.ON_PALETTE_COMPONENT_DRAG_START, scope.dragElement, component);
242
243             scope.isOnDrag = true;
244
245             // this.graphUtils.showMatchingNodes(component, myDiagram, scope.sdcConfig.imagesPath);
246             // document.addEventListener('mousemove', moveOnDocument);
247             event.dataTransfer.component = component;
248         };
249
250         scope.dragStopCallback = () => {
251             scope.isOnDrag = false;
252         };
253
254         scope.onDragCallback = (event:IDragDropEvent):void => {
255             this.EventListenerService.notifyObservers(GRAPH_EVENTS.ON_PALETTE_COMPONENT_DRAG_ACTION, event);
256         };
257         scope.setElementTemplate = (e) => {
258             let dragComponent:LeftPaletteComponent = _.find(this.LeftPaletteLoaderService.getLeftPanelComponentsForDisplay(scope.currentComponent),
259                 (fullComponent:LeftPaletteComponent) => {
260                     return (<any>angular.element(e.currentTarget).scope()).component.uniqueId === fullComponent.uniqueId;
261                 });
262             let componentInstance:ComponentInstance = this.ComponentInstanceFactory.createComponentInstanceFromComponent(dragComponent);
263             let node:CompositionCiNodeBase = this.NodesFactory.createNode(componentInstance);
264
265             // myDiagram.dragFromPalette = node;
266             this.nodeHtmlSubstitute.find("img").attr('src', node.img);
267             scope.dragElement = this.nodeHtmlSubstitute.clone().show();
268
269             return scope.dragElement;
270         };
271     }
272
273     private _searchComponents = (searchText:string, categories:any):void => {
274         let displaySortedCategories = angular.copy(categories);
275         if (searchText != '') {
276             angular.forEach(categories, function (category:any, categoryKey) {
277
278                 angular.forEach(category, function (subcategory:Array<LeftPaletteComponent>, subcategoryKey) {
279                     let filteredResources = [];
280                     angular.forEach(subcategory, function (component:LeftPaletteComponent) {
281
282                         let resourceFilterTerm:string = component.searchFilterTerms.toLowerCase();
283                         if (resourceFilterTerm.indexOf(searchText.toLowerCase()) >= 0) {
284                             filteredResources.push(component);
285                         }
286                     });
287                     if (filteredResources.length > 0) {
288                         displaySortedCategories[categoryKey][subcategoryKey] = filteredResources;
289                     }
290                     else {
291                         delete  displaySortedCategories[categoryKey][subcategoryKey];
292                     }
293                 });
294                 if (!(Object.keys(displaySortedCategories[categoryKey]).length > 0)) {
295                     delete  displaySortedCategories[categoryKey];
296                 }
297
298             });
299         }
300         return displaySortedCategories;
301     };
302
303     public static factory = ($log,
304                              LeftPaletteLoaderService,
305                              sdcConfig,
306                              ComponentFactory,
307                              ComponentInstanceFactory,
308                              NodesFactory,
309                              CompositionGraphGeneralUtils,
310                              EventListenerService,
311                              sdcMenu,
312                              ModalsHandler
313                             ) => {
314         return new Palette($log,
315             LeftPaletteLoaderService,
316             sdcConfig,
317             ComponentFactory,
318             ComponentInstanceFactory,
319             NodesFactory,
320             CompositionGraphGeneralUtils,
321             EventListenerService,
322             sdcMenu,
323             ModalsHandler
324         );
325     };
326 }
327
328 Palette.factory.$inject = [
329     '$log',
330     'LeftPaletteLoaderService',
331     'sdcConfig',
332     'ComponentFactory',
333     'ComponentInstanceFactory',
334     'NodesFactory',
335     'CompositionGraphGeneralUtils',
336     'EventListenerService',
337     'sdcMenu',
338     'ModalsHandler'
339 ];