diff options
Diffstat (limited to 'catalog-ui')
34 files changed, 512 insertions, 59 deletions
diff --git a/catalog-ui/src/app/app.ts b/catalog-ui/src/app/app.ts index 707d7e456e..805e5f0b5d 100644 --- a/catalog-ui/src/app/app.ts +++ b/catalog-ui/src/app/app.ts @@ -53,6 +53,7 @@ import {downgradeComponent} from "@angular/upgrade/static"; import {AppModule} from './ng2/app.module'; import {PropertiesAssignmentComponent} from "./ng2/pages/properties-assignment/properties-assignment.page.component"; +import { SearchWithAutoCompleteComponent } from "./ng2/shared/search-with-autocomplete/search-with-autocomplete.component"; import {Component} from "./models/components/component"; import {ComponentServiceNg2} from "./ng2/services/component-services/component.service"; import {ComponentMetadata} from "./models/component-metadata"; @@ -145,6 +146,13 @@ _.each(hostedApplications, (hostedApp)=> { export const ng1appModule:ng.IModule = angular.module(moduleName, dependentModules); angular.module('sdcApp').directive('propertiesAssignment', downgradeComponent({component: PropertiesAssignmentComponent}) as angular.IDirectiveFactory); +angular.module('sdcApp').directive('ng2SearchWithAutocomplete', + downgradeComponent({ + component: SearchWithAutoCompleteComponent, + inputs: ['searchPlaceholder', 'searchBarClass', 'autoCompleteValues'], + outputs: ['searchChanged', 'searchButtonClicked'] + }) as angular.IDirectiveFactory); + ng1appModule.config([ '$stateProvider', @@ -161,7 +169,7 @@ ng1appModule.config([ NotificationProvider:any):void => { NotificationProvider.setOptions({ - delay: 10000, + delay: 5000, startTop: 10, startRight: 10, closeOnClick: true, @@ -170,6 +178,7 @@ ng1appModule.config([ positionX: 'right', positionY: 'top' }); + NotificationProvider.options.templateUrl = 'notification-custom-template.html'; $translateProvider.useStaticFilesLoader({ prefix: pathPrefix + 'assets/languages/', @@ -617,6 +626,7 @@ ng1appModule.run([ 'LeftPaletteLoaderService', 'Sdc.Services.DataTypesService', 'AngularJSBridge', + '$templateCache', ($http:ng.IHttpService, cacheService:CacheService, cookieService:CookieService, @@ -632,8 +642,9 @@ ng1appModule.run([ ecompHeaderService:EcompHeaderService, LeftPaletteLoaderService:LeftPaletteLoaderService, DataTypesService:DataTypesService, - AngularJSBridge):void => { - + AngularJSBridge, + $templateCache:ng.ITemplateCacheService):void => { + $templateCache.put('notification-custom-template.html', require('./view-models/shared/notification-custom-template.html')); //handle cache data - version let initAsdcVersion:Function = ():void => { diff --git a/catalog-ui/src/app/directives/graphs-v2/common/style/component-instances-nodes-style.ts b/catalog-ui/src/app/directives/graphs-v2/common/style/component-instances-nodes-style.ts index 0dcc93dfa7..64197594e2 100644 --- a/catalog-ui/src/app/directives/graphs-v2/common/style/component-instances-nodes-style.ts +++ b/catalog-ui/src/app/directives/graphs-v2/common/style/component-instances-nodes-style.ts @@ -231,7 +231,7 @@ export class ComponentInstanceNodesStyle { public static getBasicNodeHanlde = () => { return { - positionX: "center", + positionX: "right", positionY: "top", offsetX: 15, offsetY: -20, @@ -248,7 +248,7 @@ export class ComponentInstanceNodesStyle { public static getBasicSmallNodeHandle = () => { return { - positionX: "center", + positionX: "right", positionY: "top", offsetX: 3, offsetY: -25, diff --git a/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.directive.ts b/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.directive.ts index 651a4281fa..9aa7941272 100644 --- a/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.directive.ts +++ b/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.directive.ts @@ -47,7 +47,8 @@ interface ICompositionGraphScope extends ng.IScope { component:Component; isLoading: boolean; - isViewOnly:boolean; + isViewOnly: boolean; + withSidebar: boolean; // Link menu - create link menu relationMenuDirectiveObj:RelationMenuDirectiveObj; isLinkMenuOpen:boolean; @@ -65,6 +66,14 @@ interface ICompositionGraphScope extends ng.IScope { //Links menus deleteRelation(link:Cy.CollectionEdges):void; hideRelationMenu(); + + //search,zoom in/out/all + componentInstanceNames: Array<string>; //id, name + zoom(zoomIn: boolean): void; + zoomAll(nodes?:Cy.CollectionNodes): void; + getAutoCompleteValues(searchTerm: string):void; + highlightSearchMatches(searchTerm: string): void; + /*//asset popover menu assetPopoverObj:AssetPopoverObj; assetPopoverOpen:boolean; @@ -101,7 +110,8 @@ export class CompositionGraph implements ng.IDirective { template = require('./composition-graph.html'); scope = { component: '=', - isViewOnly: '=' + isViewOnly: '=', + withSidebar: '=' }; link = (scope:ICompositionGraphScope, el:JQuery) => { @@ -147,7 +157,11 @@ export class CompositionGraph implements ng.IDirective { this._cy = cytoscape({ container: graphEl, style: ComponentInstanceNodesStyle.getCompositionGraphStyle(), - zoomingEnabled: false, + zoomingEnabled: true, + maxZoom: 2.5, + minZoom: .1, + userZoomingEnabled: false, + userPanningEnabled: true, selectionType: 'single', boxSelectionEnabled: true, autolock: isViewOnly, @@ -270,6 +284,40 @@ export class CompositionGraph implements ng.IDirective { this.loadGraphData(scope); }); + scope.zoom = (zoomIn: boolean):void => { + let currentZoom: number = this._cy.zoom(); + if (zoomIn) { + this.GeneralGraphUtils.zoomGraphTo(this._cy, currentZoom + .1); + } else { + this.GeneralGraphUtils.zoomGraphTo(this._cy, currentZoom - .1); + } + } + + //Zooms to fit all of the nodes in the collection passed in. If no nodes are passed in, will zoom to fit all nodes on graph + scope.zoomAll = (nodes?:Cy.CollectionNodes) => { + scope.withSidebar = false; + this._cy.animate({ + fit: { eles: nodes, padding: 20 }, + center: { eles: nodes } + }, { duration: 400 }); + }; + + scope.getAutoCompleteValues = (searchTerm: string) => { + if (searchTerm.length > 1) { //US requirement: only display search results after 2nd letter typed. + let nodes: Cy.CollectionNodes = this.NodesGraphUtils.getMatchingNodesByName(this._cy, searchTerm); + scope.componentInstanceNames = _.map(nodes, node => node.data('name')); + } else { + scope.componentInstanceNames = []; + } + }; + + scope.highlightSearchMatches = (searchTerm: string) => { + if (searchTerm === undefined) return; //dont zoom & highlight if click on Search initially (searchTerm will be undefined). However, allow highlights to be cleared after subsequent search (searchTerm will be "") + + this.NodesGraphUtils.highlightMatchingNodesByName(this._cy, searchTerm); + let matchingNodes: Cy.CollectionNodes = this.NodesGraphUtils.getMatchingNodesByName(this._cy, searchTerm); + scope.zoomAll(matchingNodes); + }; scope.createLinkFromMenu = (chosenMatch:MatchBase):void => { scope.isLinkMenuOpen = false; @@ -367,7 +415,7 @@ export class CompositionGraph implements ng.IDirective { });*/ this._cy.on('handlemouseover', (event, payload) => { - if (payload.node.grabbed() /* || this._cy.scratch('_edge_editation_highlights') === true*/) { //no need to add opacity while we are dragging and hovering othe nodes- or if opacity was already calculated for these nodes + if (payload.node.grabbed() || this._cy.scratch('_edge_editation_highlights') === true) { //no need to add opacity while we are dragging and hovering othe nodes- or if opacity was already calculated for these nodes return; } let nodesData = this.NodesGraphUtils.getAllNodesData(this._cy.nodes()); @@ -377,9 +425,9 @@ export class CompositionGraph implements ng.IDirective { let filteredNodesData = this.matchCapabilitiesRequirementsUtils.findByMatchingCapabilitiesToRequirements(payload.node.data().componentInstance, linkableNodes, nodesLinks); this.matchCapabilitiesRequirementsUtils.highlightMatchingComponents(filteredNodesData, this._cy); this.matchCapabilitiesRequirementsUtils.fadeNonMachingComponents(filteredNodesData, nodesData, this._cy, payload.node.data()); - /* + this._cy.scratch()._edge_editation_highlights = true; - scope.hideAssetPopover();*/ + /*scope.hideAssetPopover();*/ }); this._cy.on('handlemouseout', () => { diff --git a/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.html b/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.html index 1e69d3384a..248f19fb70 100644 --- a/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.html +++ b/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.html @@ -20,4 +20,11 @@ </div> + <div class="w-sdc-search-menu" data-ng-class="{'with-sidebar': withSidebar}"> + <ng2-search-with-autocomplete [search-placeholder]="'Type to search'" [auto-complete-values]="componentInstanceNames" (search-changed)="getAutoCompleteValues($event)" (search-button-clicked)="highlightSearchMatches($event)" + [search-bar-class]="'composition-search'"></ng2-search-with-autocomplete> + <div class="zoom-icons sprite-new canvas-fit-all" data-ng-click="zoomAll()"></div> + <div class="zoom-icons sprite-new zoom-plus" data-ng-click="zoom(true)"></div> + <div class="zoom-icons sprite-new zoom-minus" data-ng-click="zoom(false)"></div> + </div> <!--<asset-popover ng-if="assetPopoverOpen" asset-popover-obj="assetPopoverObj" delete-asset="deleteNode(assetPopoverObj.nodeId)"></asset-popover>--> diff --git a/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-general-utils.ts b/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-general-utils.ts index 608031430b..0ea38af825 100644 --- a/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-general-utils.ts +++ b/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-general-utils.ts @@ -64,6 +64,14 @@ export class CompositionGraphGeneralUtils { }; + public zoomGraphTo = (cy:Cy.Instance, zoomLevel: number):void => { + let zy = cy.height() / 2; + let zx = cy.width() / 2; + cy.zoom({ + level: zoomLevel, + renderedPosition: { x: zx, y: zy } + }); + } /** * will return true/false if two nodes overlapping * diff --git a/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-nodes-utils.ts b/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-nodes-utils.ts index feb6ac9a54..449d551cc0 100644 --- a/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-nodes-utils.ts +++ b/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-nodes-utils.ts @@ -48,6 +48,21 @@ export class CompositionGraphNodesUtils { }) }; + + public highlightMatchingNodesByName = (cy: Cy.Instance, nameToMatch: string) => { + + cy.batch(() => { + cy.nodes("[name !@^= '" + nameToMatch + "']").style({ 'background-image-opacity': 0.4 }); + cy.nodes("[name @^= '" + nameToMatch + "']").style({ 'background-image-opacity': 1 }); + }) + + } + + //Returns all nodes whose name starts with searchTerm + public getMatchingNodesByName = (cy: Cy.Instance, nameToMatch: string): Cy.CollectionNodes => { + return cy.nodes("[name @^= '" + nameToMatch + "']"); + }; + /** * Deletes component instances on server and then removes it from the graph as well * @param cy diff --git a/catalog-ui/src/app/models/components/component.ts b/catalog-ui/src/app/models/components/component.ts index 9b2c942483..53e8f05cbe 100644 --- a/catalog-ui/src/app/models/components/component.ts +++ b/catalog-ui/src/app/models/components/component.ts @@ -923,16 +923,17 @@ export abstract class Component implements IComponent { } public toJSON = ():any => { - this.componentService = undefined; - this.filterTerm = undefined; - this.iconSprite = undefined; - this.mainCategory = undefined; - this.subCategory = undefined; - this.selectedInstance = undefined; - this.showMenu = undefined; - this.$q = undefined; - this.selectedCategory = undefined; - return this; + let temp = angular.copy(this); + temp.componentService = undefined; + temp.filterTerm = undefined; + temp.iconSprite = undefined; + temp.mainCategory = undefined; + temp.subCategory = undefined; + temp.selectedInstance = undefined; + temp.showMenu = undefined; + temp.$q = undefined; + temp.selectedCategory = undefined; + return temp; }; } diff --git a/catalog-ui/src/app/models/components/resource.ts b/catalog-ui/src/app/models/components/resource.ts index 138b413028..cd839786c5 100644 --- a/catalog-ui/src/app/models/components/resource.ts +++ b/catalog-ui/src/app/models/components/resource.ts @@ -163,17 +163,18 @@ export class Resource extends Component { }; public toJSON = ():any => { - this.componentService = undefined; - this.filterTerm = undefined; - this.iconSprite = undefined; - this.mainCategory = undefined; - this.subCategory = undefined; - this.selectedInstance = undefined; - this.showMenu = undefined; - this.$q = undefined; - this.selectedCategory = undefined; - this.importedFile = undefined; - return this; + let temp = angular.copy(this); + temp.componentService = undefined; + temp.filterTerm = undefined; + temp.iconSprite = undefined; + temp.mainCategory = undefined; + temp.subCategory = undefined; + temp.selectedInstance = undefined; + temp.showMenu = undefined; + temp.$q = undefined; + temp.selectedCategory = undefined; + temp.importedFile = undefined; + return temp; }; } diff --git a/catalog-ui/src/app/ng2/app.module.ts b/catalog-ui/src/app/ng2/app.module.ts index 09b40e920f..57adb8fd66 100644 --- a/catalog-ui/src/app/ng2/app.module.ts +++ b/catalog-ui/src/app/ng2/app.module.ts @@ -40,6 +40,8 @@ import {ComponentInstanceServiceNg2} from "./services/component-instance-service import { InterceptorService } from 'ng2-interceptors'; import { XHRBackend, RequestOptions } from '@angular/http'; import {HttpInterceptor} from "./services/http.interceptor.service"; +import { SearchBarComponent } from './shared/search-bar/search-bar.component'; +import { SearchWithAutoCompleteComponent } from './shared/search-with-autocomplete/search-with-autocomplete.component'; export const upgradeAdapter = new UpgradeAdapter(forwardRef(() => AppModule)); @@ -60,7 +62,9 @@ export function interceptorFactory(xhrBackend: XHRBackend, requestOptions: Reque @NgModule({ declarations: [ - AppComponent + AppComponent, + SearchBarComponent, + SearchWithAutoCompleteComponent ], imports: [ BrowserModule, @@ -70,7 +74,7 @@ export function interceptorFactory(xhrBackend: XHRBackend, requestOptions: Reque PropertiesAssignmentModule ], exports: [], - entryComponents: [], + entryComponents: [SearchWithAutoCompleteComponent], providers: [ DataTypesServiceProvider, SharingServiceProvider, diff --git a/catalog-ui/src/app/ng2/components/inputs-table/inputs-table.component.less b/catalog-ui/src/app/ng2/components/inputs-table/inputs-table.component.less index 05378f0eb9..89c7287449 100644 --- a/catalog-ui/src/app/ng2/components/inputs-table/inputs-table.component.less +++ b/catalog-ui/src/app/ng2/components/inputs-table/inputs-table.component.less @@ -85,7 +85,7 @@ border-right:#d2d2d2 solid 1px; } &.col1 { - flex: 0 0 300px; + flex: 1 0 200px; max-width:300px; display: flex; justify-content: space-between; diff --git a/catalog-ui/src/app/ng2/components/properties-table/properties-table.component.less b/catalog-ui/src/app/ng2/components/properties-table/properties-table.component.less index 3eb7e960ab..9ede84faff 100644 --- a/catalog-ui/src/app/ng2/components/properties-table/properties-table.component.less +++ b/catalog-ui/src/app/ng2/components/properties-table/properties-table.component.less @@ -91,7 +91,7 @@ border-right:#d2d2d2 solid 1px; } &.col1 { - flex: 0 0 300px; + flex: 1 0 210px; max-width:300px; display: flex; justify-content: space-between; @@ -100,7 +100,7 @@ .property-name { flex: 1; display: flex; - max-width: 270px; + max-width: 90%; } .property-description-icon { @@ -123,7 +123,7 @@ } &.valueCol { - flex: 1 0 350px; + flex: 2 0 300px; display: flex; @media @smaller-screen { flex: 1 0 40%;} } diff --git a/catalog-ui/src/app/ng2/shared/search-bar/search-bar.component.html b/catalog-ui/src/app/ng2/shared/search-bar/search-bar.component.html new file mode 100644 index 0000000000..36629594b0 --- /dev/null +++ b/catalog-ui/src/app/ng2/shared/search-bar/search-bar.component.html @@ -0,0 +1,5 @@ +<div class="search-bar-container {{class}}"> + <input class="search-bar-input" type="text" [placeholder]="placeholder" [(ngModel)]="searchQuery" (ngModelChange)="searchQueryChange($event)"/> + <span class="clear-search-x" *ngIf="searchQuery" (click)="clearSearchQuery()">x</span> + <button class="search-bar-button" (click)="searchButtonClick()"></button> +</div>
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/shared/search-bar/search-bar.component.less b/catalog-ui/src/app/ng2/shared/search-bar/search-bar.component.less new file mode 100644 index 0000000000..cfeb8d3b01 --- /dev/null +++ b/catalog-ui/src/app/ng2/shared/search-bar/search-bar.component.less @@ -0,0 +1,58 @@ +.search-bar-container { + display:flex; + border-radius: 4px; + box-shadow: 0px 2px 3.88px 0.12px rgba(0, 0, 0, 0.29); + + .search-bar-input { + border: 1px solid #cdcdcd; + border-radius: 4px; + border-right:none; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + outline:none; + padding:2px 50px 2px 10px; + color: #5a5a5a; + font-size: 1em; + font-style: italic; + } + + .clear-search-x { + position:absolute; + right:40px; + top:5px; + padding: 0 5px; + + &:hover { + border-radius:2px; + background-color: #ebebeb; + cursor:pointer; + } + } + + .search-bar-button { + //background: url('../../../../assets/styles/svg/source/search-magnify.svg') no-repeat 50%; + background: url('../../../../assets/styles/images/sprites/sprite-global.png') no-repeat -206px -1275px; + background-color: rgba(234, 234, 234, 0.88); + width: 30px; + height: 30px; + padding: 0; + cursor:pointer; + border:solid 1px #cdcdcd; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + + &:hover { + background-position:-126px -1275px; + } + + &:active { + background-color: rgba(31, 171, 223, 0.88); + background-position:-45px -1275px; + border-left:none; + } + &:focus { + outline:none; + } + + } +} diff --git a/catalog-ui/src/app/ng2/shared/search-bar/search-bar.component.ts b/catalog-ui/src/app/ng2/shared/search-bar/search-bar.component.ts new file mode 100644 index 0000000000..2835d20ba4 --- /dev/null +++ b/catalog-ui/src/app/ng2/shared/search-bar/search-bar.component.ts @@ -0,0 +1,30 @@ +import { Component, Input, Output, EventEmitter, ViewEncapsulation } from '@angular/core'; + +@Component({ + selector: 'search-bar', + templateUrl: './search-bar.component.html', + styleUrls: ['./search-bar.component.less'], + encapsulation: ViewEncapsulation.None +}) +export class SearchBarComponent { + + @Input() placeholder: string; + @Input() class: string; + @Input() searchQuery: string; + @Output() searchChanged: EventEmitter<any> = new EventEmitter<any>(); + @Output() searchButtonClicked: EventEmitter<string> = new EventEmitter<string>(); + + searchButtonClick = (): void => { + this.searchButtonClicked.emit(this.searchQuery); + } + + searchQueryChange = ($event): void => { + this.searchChanged.emit($event); + } + + private clearSearchQuery = (): void => { + this.searchQuery = ""; + this.searchButtonClick(); + } +} + diff --git a/catalog-ui/src/app/ng2/shared/search-with-autocomplete/search-with-autocomplete.component.html b/catalog-ui/src/app/ng2/shared/search-with-autocomplete/search-with-autocomplete.component.html new file mode 100644 index 0000000000..c9769ba5ae --- /dev/null +++ b/catalog-ui/src/app/ng2/shared/search-with-autocomplete/search-with-autocomplete.component.html @@ -0,0 +1,6 @@ +<div class="search-with-autocomplete-container {{searchBarClass}}" [class.autocomplete-visible]="autoCompleteValues && autoCompleteValues.length" [class.active]="searchQuery && searchQuery.length"> + <search-bar [placeholder]="searchPlaceholder" [searchQuery]="searchQuery" (searchButtonClicked)="updateSearch($event)" (searchChanged)="searchChange($event)"></search-bar> + <div class="autocomplete-results"> + <div *ngFor="let item of autoCompleteValues" class="autocomplete-result-item" (click)="updateSearch(item)">{{item}}</div> + </div> +</div>
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/shared/search-with-autocomplete/search-with-autocomplete.component.less b/catalog-ui/src/app/ng2/shared/search-with-autocomplete/search-with-autocomplete.component.less new file mode 100644 index 0000000000..92b054cd85 --- /dev/null +++ b/catalog-ui/src/app/ng2/shared/search-with-autocomplete/search-with-autocomplete.component.less @@ -0,0 +1,35 @@ + +.search-with-autocomplete-container{ + &.autocomplete-visible { + + .search-bar-input { + border-bottom-left-radius: 0; + } + .search-bar-button { + border-bottom-right-radius: 0; + } + .autocomplete-results { + border: solid 1px #d2d2d2; + border-top:none; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + background-color: #fff; + padding: 10px 20px; + width:100%; + position:absolute; + max-height: 200px; + overflow-y: scroll; + } + + .autocomplete-result-item { + color:#5a5a5a; + padding: 5px 0; + cursor:pointer; + + &:hover { + color: #999; + } + } + } +} + diff --git a/catalog-ui/src/app/ng2/shared/search-with-autocomplete/search-with-autocomplete.component.ts b/catalog-ui/src/app/ng2/shared/search-with-autocomplete/search-with-autocomplete.component.ts new file mode 100644 index 0000000000..ced056d1fc --- /dev/null +++ b/catalog-ui/src/app/ng2/shared/search-with-autocomplete/search-with-autocomplete.component.ts @@ -0,0 +1,30 @@ +import { Component, Input, Output, EventEmitter, ViewEncapsulation } from '@angular/core'; +import { SearchBarComponent } from '../search-bar/search-bar.component'; + +@Component({ + selector: 'search-with-autocomplete', + templateUrl: './search-with-autocomplete.component.html', + styleUrls: ['./search-with-autocomplete.component.less'], + encapsulation: ViewEncapsulation.None +}) +export class SearchWithAutoCompleteComponent { + + @Input() searchPlaceholder: string; + @Input() searchBarClass: string; + @Input() searchQuery: string; + @Input() autoCompleteValues: Array<string>; + @Output() searchChanged: EventEmitter<any> = new EventEmitter<any>(); + @Output() searchButtonClicked: EventEmitter<string> = new EventEmitter<string>(); + + searchChange = (searchTerm: string) => { + this.searchQuery = searchTerm; + this.searchChanged.emit(searchTerm); + } + + updateSearch = (searchTerm: string) => { + this.searchQuery = searchTerm; + this.searchButtonClicked.emit(searchTerm); + this.autoCompleteValues = []; + } +} + diff --git a/catalog-ui/src/app/view-models/shared/notification-custom-template.html b/catalog-ui/src/app/view-models/shared/notification-custom-template.html new file mode 100644 index 0000000000..d8fdf135b9 --- /dev/null +++ b/catalog-ui/src/app/view-models/shared/notification-custom-template.html @@ -0,0 +1,14 @@ +<div class="ui-notification"> + <div class="notification-container"> + <div class="icon-container"> + <div class="icon-circle"> + <div class="icon sprite-new"> + </div> + </div> + </div> + <div class="msg-content"> + <h3 ng-show="title" ng-bind-html="title"></h3> + <div class="message" ng-bind-html="message"></div> + </div> + </div> +</div> diff --git a/catalog-ui/src/app/view-models/workspace/tabs/composition/composition-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/composition/composition-view-model.ts index fbd32cc967..0e5a5fcd6c 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/composition/composition-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/composition/composition-view-model.ts @@ -30,7 +30,8 @@ import {ResourceType} from "../../../../utils/constants"; export interface ICompositionViewModelScope extends IWorkspaceViewModelScope { currentComponent:Component; - selectedComponent:Component; + selectedComponent: Component; + componentInstanceNames: Array<string>; isLoading:boolean; graphApi:any; sharingService:SharingService; @@ -130,7 +131,6 @@ export class CompositionViewModel { private openUpdateComponentInstanceNameModal = ():void => { this.ModalsHandler.openUpdateComponentInstanceNameModal(this.$scope.currentComponent).then(()=> { this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_COMPONENT_INSTANCE_NAME_CHANGED, this.$scope.currentComponent.selectedInstance); - }); }; @@ -225,7 +225,7 @@ export class CompositionViewModel { this.$scope.openUpdateModal = ():void => { this.openUpdateComponentInstanceNameModal(); }; - + this.$scope.deleteSelectedComponentInstance = ():void => { let state = "deleteInstance"; let onOk = ():void => { diff --git a/catalog-ui/src/app/view-models/workspace/tabs/composition/composition-view.html b/catalog-ui/src/app/view-models/workspace/tabs/composition/composition-view.html index cef942e853..e05574e8c8 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/composition/composition-view.html +++ b/catalog-ui/src/app/view-models/workspace/tabs/composition/composition-view.html @@ -6,7 +6,7 @@ is-loading="isLoading"></palette> <composition-graph component="currentComponent" data-tests-id="canvas" - is-view-only="isViewOnly"></composition-graph> + is-view-only="isViewOnly" with-sidebar="displayDesignerRightSidebar"></composition-graph> </div> <div class="w-sdc-designer-sidebar-toggle" data-ng-class="{'active': displayDesignerRightSidebar}" @@ -21,7 +21,7 @@ <div class="w-sdc-designer-sidebar-logo-ph"> <div class="large {{selectedComponent.iconSprite}} {{selectedComponent.icon}}"> <div ng-if="isComponentInstanceSelected()" - data-ng-class="{'non-certified':'CERTIFIED' !== selectedComponent.lifecycleState, 'smaller-icon': selectedComponent.icon==='vl' || selectedComponent.icon==='cp'}" + data-ng-class="{'non-certified':'CERTIFIED' !== selectedComponent.lifecycleState}" tooltips tooltip-side="top" tooltip-content="Not certified"></div> </div> </div> diff --git a/catalog-ui/src/app/view-models/workspace/tabs/composition/composition.less b/catalog-ui/src/app/view-models/workspace/tabs/composition/composition.less index 7a775bdb11..262dfd9be8 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/composition/composition.less +++ b/catalog-ui/src/app/view-models/workspace/tabs/composition/composition.less @@ -781,6 +781,71 @@ line-height: 18px; } + //Canvas search menu + .w-sdc-search-menu { + position:absolute; + right: 18px; + top:53px; + transition: right 0.2s; + display: flex; + flex-direction: column; + align-items: flex-end; + margin-right:10px; + + &.with-sidebar { + right:320px; + } + + .search-with-autocomplete-container.composition-search { + margin-top: 12px; + + .search-bar-input { + width: 250px; + padding:2px 50px 2px 10px; + transition:all 0.4s; + } + .clear-search-x { + top: 17px + } + + &:not(:hover):not(.autocomplete-visible):not(.active){ + border-radius: 0; + box-shadow:none; + + .search-bar-input:not(:focus){ + width: 0px; + padding:0; + border:none; + } + .clear-search-x { + display:none; + } + .search-bar-input:not(:focus) ~ .search-bar-button { + border-radius: 2px; + border:solid 1px #fff; + } + } + } + + .zoom-icons { + border:solid 1px #fff; + border-radius: 2px; + box-shadow: 0px 2px 3.88px 0.12px rgba(0, 0, 0, 0.29); + background-color: rgba(234, 234, 234, 0.88); + background-repeat: no-repeat; + margin-top: 10px; + + &:hover { + cursor:pointer; + } + + &:active { + border:none; + background-color: rgba(31, 171, 223, 0.88); + } + } + } + // --------------------------------------------------------------------------------------------------- // Canvas inline menu // --------------------------------------------------------------------------------------------------- diff --git a/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/artifacts/artifacts-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/artifacts/artifacts-view-model.ts index 83e4653954..c4c63fae06 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/artifacts/artifacts-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/artifacts/artifacts-view-model.ts @@ -33,13 +33,14 @@ import {ICompositionViewModelScope} from "../../composition-view-model"; import {ArtifactsUtils, ModalsHandler, ArtifactGroupType} from "app/utils"; import {GRAPH_EVENTS} from "app/utils/constants"; import {EventListenerService} from "app/services/event-listener-service"; +import {Dictionary} from "../../../../../../utils/dictionary/dictionary"; export interface IArtifactsViewModelScope extends ICompositionViewModelScope { artifacts:Array<ArtifactModel>; artifactType:string; downloadFile:IFileDownload; isLoading:boolean; - + displayDeleteButtonMap:Dictionary<string, boolean>; getTitle():string; addOrUpdate(artifact:ArtifactModel):void; delete(artifact:ArtifactModel):void; @@ -125,6 +126,10 @@ export class ResourceArtifactsViewModel { } } this.$scope.artifacts = artifacts; + this.$scope.displayDeleteButtonMap = new Dictionary<string, boolean>(); + _.forEach(this.$scope.artifacts, (artifact:ArtifactModel)=>{ + this.$scope.displayDeleteButtonMap[artifact.artifactLabel] = this.displayDeleteButton(artifact); + }); this.$scope.isLoading = false; }; @@ -229,6 +234,17 @@ export class ResourceArtifactsViewModel { }); }; + private displayDeleteButton = (artifact:ArtifactModel):boolean => { + if(!this.$scope.isViewMode() && artifact.esId){ + if(this.$scope.isComponentInstanceSelected()){//is artifact of instance + return !this.$scope.selectedComponent.deploymentArtifacts || !this.$scope.selectedComponent.deploymentArtifacts[artifact.artifactLabel];//if the artifact is not from instance parent + }else{//is artifact of main component + return (!artifact.isHEAT() && !artifact.isThirdParty() && !this.$scope.isLicenseArtifact(artifact)); + } + } + return false; +}; + private initScope = ():void => { this.$scope.isLoading = false; diff --git a/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/artifacts/artifacts-view.html b/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/artifacts/artifacts-view.html index 8221c67eca..dfbd639eb4 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/artifacts/artifacts-view.html +++ b/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/artifacts/artifacts-view.html @@ -36,7 +36,7 @@ <span class="i-sdc-designer-sidebar-section-content-item-artifact-details-desc-label" data-ng-show="artifact.description">Description:</span>{{artifact.description}} </div> </div> - <button ng-if="!isViewMode() && artifact.esId && !isComponentInstanceSelected() && !artifact.isHEAT() && !artifact.isThirdParty() && !isLicenseArtifact(artifact)" class="i-sdc-designer-sidebar-section-content-item-button delete sprite e-sdc-small-icon-delete" + <button ng-if="displayDeleteButtonMap[artifact.artifactLabel]" class="i-sdc-designer-sidebar-section-content-item-button delete sprite e-sdc-small-icon-delete" data-tests-id="delete_{{artifact.artifactDisplayName}}" data-ng-click="delete(artifact)" type="button"></button> <button ng-if="!isViewMode() && artifact.isHEAT() && isComponentInstanceSelected() && artifact.heatParameters.length" class="i-sdc-designer-sidebar-section-content-item-button attach sprite e-sdc-small-icon-pad" diff --git a/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/details/details-view.html b/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/details/details-view.html index 8607d65964..0418515789 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/details/details-view.html +++ b/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/details/details-view.html @@ -23,9 +23,9 @@ <span class="i-sdc-designer-sidebar-section-content-item-label">Version:</span> <span class="i-sdc-designer-sidebar-section-content-item-value" - data-ng-if="!isComponentInstanceSelected() || selectedComponent.isVl()" data-tests-id="rightTab_version" data-ng-bind="selectedComponent.version"></span> + data-ng-if="!isComponentInstanceSelected()" data-tests-id="rightTab_version" data-ng-bind="selectedComponent.version"></span> - <ng-form name="editForm" data-ng-if="isComponentInstanceSelected() && !selectedComponent.isVl()"> + <ng-form name="editForm" data-ng-if="isComponentInstanceSelected()"> <select data-ng-model="editResourceVersion.changeVersion" name="changeVersion" data-tests-id="changeVersion" data-ng-disabled="$parent.isViewOnly" class="i-sdc-designer-sidebar-section-content-item-value i-sdc-form-select" data-ng-class="{'minor': (editResourceVersion.changeVersion)%1}" diff --git a/catalog-ui/src/app/view-models/workspace/workspace.less b/catalog-ui/src/app/view-models/workspace/workspace.less index b7331b5f93..d0799f4bac 100644 --- a/catalog-ui/src/app/view-models/workspace/workspace.less +++ b/catalog-ui/src/app/view-models/workspace/workspace.less @@ -170,6 +170,9 @@ line-height: 110px; .f-type ._28; } + &.composition .w-sdc-main-container-body-content { + height: calc(~'100% - @{action_nav_height}'); //composition is the only tab without a tab title. need to exclude from calculation. + } .w-sdc-main-container-body-content { height:calc(~'100% - @{action_nav_height} - @{tab_title}'); align-items: center; diff --git a/catalog-ui/src/assets/styles/app.less b/catalog-ui/src/assets/styles/app.less index 13d88a388e..fde4cc8888 100644 --- a/catalog-ui/src/assets/styles/app.less +++ b/catalog-ui/src/assets/styles/app.less @@ -34,6 +34,7 @@ @import 'welcome-sprite.less'; @import 'welcome-style.less'; @import 'sdc-ui.css'; +@import 'notification-template.less'; // Less insides specific files. @import '../../app/directives/ecomp-footer/ecomp-footer.less'; diff --git a/catalog-ui/src/assets/styles/images/sprites/sprite-global.png b/catalog-ui/src/assets/styles/images/sprites/sprite-global.png Binary files differindex 962478fed3..87e5d43b4d 100644 --- a/catalog-ui/src/assets/styles/images/sprites/sprite-global.png +++ b/catalog-ui/src/assets/styles/images/sprites/sprite-global.png diff --git a/catalog-ui/src/assets/styles/notification-template.less b/catalog-ui/src/assets/styles/notification-template.less new file mode 100644 index 0000000000..5baf10d411 --- /dev/null +++ b/catalog-ui/src/assets/styles/notification-template.less @@ -0,0 +1,53 @@ +.notification-container{ + display: flex; + padding: 15px 11px; + float: left; + .icon-container{ + flex-grow: 1; + margin-right: 20px; + .icon-circle{ + background-color: black; + height: 40px; + width: 40px; + border-radius: 50%; + display: flex; + align-items: center; + margin-right: 0; + background-color: rgba(255, 255, 255, 0.3); + .icon{ + margin: 0 auto; + display: block; + } + } + } + .msg-content{ + flex-grow: 3; + h3{ + border-bottom: none; + font-weight: 400; + .f-type._18_m; + } + .message{ + font-weight: 300; + .f-type._14_m; + } + } +} +.ui-notification.success{ + background-color: @main_color_d; + .icon{ + .notification-success-icon; + } +} +.ui-notification.error{ + background-color: @func_color_q; + .icon{ + .notification-error-icon; + } +} +.ui-notification.info{ + background-color: @main_color_a; + .icon{ + .notification-process-icon; + } +} diff --git a/catalog-ui/src/assets/styles/sprite.less b/catalog-ui/src/assets/styles/sprite.less index 2076744854..3f82e488db 100644 --- a/catalog-ui/src/assets/styles/sprite.less +++ b/catalog-ui/src/assets/styles/sprite.less @@ -238,8 +238,12 @@ .round-expand-icon:hover { background-position: -100px -1188px; width: 15px; height: 15px; } .round-expand-icon.open { background-position: -50px -1216px; width: 15px; height: 15px; } .round-expand-icon.open:hover { background-position: -100px -1216px; width: 15px; height: 15px; } -.update-component-icon { background-position: -140px -1183px; width: 20px; height: 20px;} -.update-component-icon:hover { background-position: -170px -1183px; width: 20px; height: 20px;} +.update-component-icon { background-position: -140px -1213px; width: 20px; height: 20px;} +.update-component-icon:hover { background-position: -169px -1213px; width: 20px; height: 20px;} +.notification-user-icon{ background-position: -206px -1211px; width: 18px; height: 22px;} +.notification-error-icon{ background-position: -244px -1216px; width: 17px; height: 17px;} +.notification-success-icon{ background-position: -281px -1215px; width: 21px; height: 19px;} +.notification-process-icon{ background-position: -322px -1206px; width: 28px; height: 28px;} /* .sprite-new.expand-asset-icon { background-position: -740px -590px; width: 40px; height: 40px; } .sprite-new.view-info-icon { background-position: -739px -621px; width: 40px; height: 40px; } @@ -259,3 +263,20 @@ .sprite-new.vl-icon:active, .sprite-new.vl-icon.disabled-icon { background-position: -820px -682px; } .sprite-new.trash-icon:active, .sprite-new.trash-icon.disabled-icon { background-position: -820px -712px; } */ + + +.sprite-new.magnify-search { background-position: -206px -1276px; width: 30px; height: 30px; } +.sprite-new.magnify-search:hover { background-position: -125px -1276px; } +.sprite-new.magnify-search:active { background-position: -46px -1275px; } + +.sprite-new.zoom-plus { background-position: -208px -1380px; width: 30px; height: 30px; } +.sprite-new.zoom-plus:hover { background-position: -128px -1380px; } +.sprite-new.zoom-plus:active { background-position: -47px -1379px; } + +.sprite-new.zoom-minus { background-position: -208px -1433px; width: 30px; height: 30px; } +.sprite-new.zoom-minus:hover { background-position: -128px -1433px; } +.sprite-new.zoom-minus:active { background-position: -47px -1432px; } + +.sprite-new.canvas-fit-all { background-position: -208px -1326px; width: 30px; height: 30px;} +.sprite-new.canvas-fit-all:hover { background-position: -128px -1326px; } +.sprite-new.canvas-fit-all:active { background-position: -47px -1325px;} diff --git a/catalog-ui/src/assets/styles/svg/source/fit-all.svg b/catalog-ui/src/assets/styles/svg/source/fit-all.svg new file mode 100644 index 0000000000..dbea90963f --- /dev/null +++ b/catalog-ui/src/assets/styles/svg/source/fit-all.svg @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<svg xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + width="18px" height="19px" viewBox="0 0 18 19"> +<path fillRule="evenodd" d="M 17.94 18.86C 17.77 18.92 17.63 19 17.4 18.94 16.03 18.93 12.86 19 12.86 19 12.5 19 11.92 18.85 12 18 12.08 17.07 12.5 17 12.86 17 12.86 17 14.79 17 14.79 17 14.79 17 10.44 11.98 10.44 11.98 10.44 11.98 11.77 10.51 11.77 10.51 11.77 10.51 16.33 15.76 16.33 15.76 16.33 15.76 16.33 12.99 16.33 12.99 16.23 12.09 17.03 11.99 17.4 11.99 17.77 11.99 18.01 12.27 18.01 12.69 18.01 12.69 18.01 18.23 18.01 18.23 18.01 17.81 18 18.55 17.94 18.86ZM 17.33 7.36C 16.92 7.36 16.04 7.25 16.15 6.31 16.15 6.31 16.15 3.62 16.15 3.62 16.15 3.62 11.37 9 11.37 9 11.37 9 10.01 7.53 10.01 7.53 10.01 7.53 14.82 2.1 14.82 2.1 14.82 2.1 12.33 2.1 12.33 2.1 11.92 2.1 11.47 2.02 11.37 1.05 11.29 0.16 11.92-0 12.33-0 12.33-0 15.82 0.07 17.33 0.06 17.59 0 17.74 0.08 17.93 0.15 17.99 0.47 18 1.25 18 0.8 18 0.8 18 6.62 18 6.62 18 7.06 17.73 7.36 17.33 7.36ZM 5.67 16.9C 6.08 16.9 6.53 16.98 6.63 17.95 6.71 18.84 6.08 19 5.67 19 5.67 19 2.18 18.93 0.67 18.94 0.41 19 0.26 18.92 0.07 18.85 0.01 18.53-0 17.75-0 18.2-0 18.2-0 12.38-0 12.38-0 11.94 0.27 11.64 0.67 11.64 1.08 11.64 1.96 11.75 1.85 12.69 1.85 12.69 1.85 15.38 1.85 15.38 1.85 15.38 6.63 10 6.63 10 6.63 10 7.99 11.47 7.99 11.47 7.99 11.47 3.18 16.9 3.18 16.9 3.18 16.9 5.67 16.9 5.67 16.9ZM 6.63 9C 6.63 9 1.85 3.62 1.85 3.62 1.85 3.62 1.85 6.31 1.85 6.31 1.96 7.25 1.08 7.36 0.67 7.36 0.27 7.36-0 7.06-0 6.62-0 6.62-0 0.8-0 0.8-0 1.25 0.01 0.47 0.07 0.15 0.26 0.08 0.41 0 0.67 0.06 2.18 0.07 5.67-0 5.67-0 6.08-0 6.71 0.16 6.63 1.05 6.53 2.02 6.08 2.1 5.67 2.1 5.67 2.1 3.18 2.1 3.18 2.1 3.18 2.1 7.99 7.53 7.99 7.53 7.99 7.53 6.63 9 6.63 9Z" fill="rgb(89,89,89)"/></svg>
\ No newline at end of file diff --git a/catalog-ui/src/assets/styles/svg/source/minus.svg b/catalog-ui/src/assets/styles/svg/source/minus.svg new file mode 100644 index 0000000000..4ced110098 --- /dev/null +++ b/catalog-ui/src/assets/styles/svg/source/minus.svg @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<svg xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + width="16px" height="2px" viewBox="0 0 16 2"> +<path fillRule="evenodd" d="M 1-0C 1-0 15-0 15-0 15.55-0 16 0.45 16 1 16 1.55 15.55 2 15 2 15 2 1 2 1 2 0.45 2 0 1.55 0 1 0 0.45 0.45-0 1-0Z" fill="rgb(99,99,99)"/></svg>
\ No newline at end of file diff --git a/catalog-ui/src/assets/styles/svg/source/plus.svg b/catalog-ui/src/assets/styles/svg/source/plus.svg new file mode 100644 index 0000000000..dff172c54d --- /dev/null +++ b/catalog-ui/src/assets/styles/svg/source/plus.svg @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<svg xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + width="18px" height="18px" viewBox="0 0 18 18"> +<path fillRule="evenodd" d="M 17 10C 17 10 10 10 10 10 10 10 10 17 10 17 10 17.55 9.55 18 9 18 8.45 18 8 17.55 8 17 8 17 8 10 8 10 8 10 1 10 1 10 0.45 10 0 9.55 0 9 0 8.45 0.45 8 1 8 1 8 8 8 8 8 8 8 8 1 8 1 8 0.45 8.45 0 9 0 9.55 0 10 0.45 10 1 10 1 10 8 10 8 10 8 17 8 17 8 17.55 8 18 8.45 18 9 18 9.55 17.55 10 17 10Z" fill="rgb(99,99,99)"/></svg>
\ No newline at end of file diff --git a/catalog-ui/src/assets/styles/svg/source/search-magnify.svg b/catalog-ui/src/assets/styles/svg/source/search-magnify.svg new file mode 100644 index 0000000000..279c13fd52 --- /dev/null +++ b/catalog-ui/src/assets/styles/svg/source/search-magnify.svg @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<svg xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + width="23px" height="26px" viewBox="0 0 23 26"> +<path fillRule="evenodd" d="M 17.53 4.53C 14.5 0.28 8.55-0.71 4.3 2.32 0.05 5.36-0.94 11.31 2.09 15.56 3.56 17.63 5.74 18.99 8.25 19.41 10.42 19.77 12.58 19.38 14.48 18.32 14.48 18.32 20.28 25.23 20.28 25.23 20.44 25.47 20.7 25.61 20.93 25.65 21.16 25.69 21.45 25.64 21.68 25.47 22.15 25.13 22.26 24.5 21.92 24.06 21.92 24.06 16.11 17.15 16.11 17.15 17.73 15.7 18.81 13.79 19.17 11.61 19.58 9.14 19.01 6.6 17.53 4.53ZM 3.76 14.4C 1.37 11.04 2.14 6.4 5.5 4 7.18 2.8 9.16 2.41 11.07 2.73 12.97 3.05 14.73 4.07 15.92 5.74 17.09 7.38 17.52 9.34 17.19 11.32 16.86 13.29 15.79 15 14.18 16.17 12.58 17.35 10.58 17.77 8.61 17.44 6.65 17.08 4.9 16.03 3.76 14.4Z" fill="rgb(99,99,99)"/></svg>
\ No newline at end of file diff --git a/catalog-ui/src/third-party/cytoscape.js-edge-editation/CytoscapeEdgeEditation.js b/catalog-ui/src/third-party/cytoscape.js-edge-editation/CytoscapeEdgeEditation.js index 2da6f786ea..9be07f2ea1 100644 --- a/catalog-ui/src/third-party/cytoscape.js-edge-editation/CytoscapeEdgeEditation.js +++ b/catalog-ui/src/third-party/cytoscape.js-edge-editation/CytoscapeEdgeEditation.js @@ -250,13 +250,14 @@ _drawHandle: function (handle, target) { var position = this._getHandlePosition(handle, target); - + var handleSize = target.renderedWidth() / 4; + this._ctx.beginPath(); if (handle.imageUrl) { var base_image = new Image(); base_image.src = handle.imageUrl; - this._ctx.drawImage(base_image, position.x, position.y, this.HANDLE_SIZE, this.HANDLE_SIZE); + this._ctx.drawImage(base_image, position.x, position.y, handleSize, handleSize); } else { this._ctx.arc(position.x, position.y, this.HANDLE_SIZE, 0, 2 * Math.PI, false); this._ctx.fillStyle = handle.color; @@ -461,17 +462,17 @@ }, _getHandlePosition: function (handle, target) { var position = target.renderedPosition(); - var width = target.renderedOuterWidth(); - var height = target.renderedOuterHeight(); + var width = target.renderedWidth(); + var height = target.renderedHeight(); var xpos = null; var ypos = null; switch (handle.positionX) { case "left": - xpos = position.x - width / 2 + this.HANDLE_SIZE; + xpos = position.x - width / 4; break; case "right": - xpos = position.x + width / 2 - this.HANDLE_SIZE; + xpos = position.x + width / 4; break; case "center": xpos = position.x; @@ -480,18 +481,18 @@ switch (handle.positionY) { case "top": - ypos = position.y - height / 2 + this.HANDLE_SIZE; + ypos = position.y - width / 2; break; case "center": ypos = position.y; break; case "bottom": - ypos = position.y + height / 2 - this.HANDLE_SIZE; + ypos = position.y + width / 2; break; } - var offsetX = handle.offsetX ? handle.offsetX : 0; - var offsetY = handle.offsetY ? handle.offsetY : 0; + var offsetX = 0; + var offsetY = 0; return {x: xpos + offsetX, y: ypos + offsetY}; }, _getEdgeCSSByHandle: function (handle) { |