Skip to content

Commit

Permalink
added context-menu support for path and definition items in the left-…
Browse files Browse the repository at this point in the history
…hand panel. closes #61
  • Loading branch information
EricWittmann committed Mar 20, 2017
1 parent 54fc02b commit 8569e5c
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export class DeletePathCommand extends AbstractCommand implements ICommand {
* @param document
*/
public execute(document: OasDocument): void {
console.info("[DeletePathCommand] Executing.");
console.info("[DeletePathCommand] Executing for path: %s", this._path);
this._oldPath = null;
let doc: Oas20Document = <Oas20Document>document;
let paths: Oas20Paths = doc.paths;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<span class="context-help">
<span class="context-help" (window:keydown)="onGlobalKeyDown($event)">
<a (click)="open($event)"><span class="context-help-icon fa fa-fw fa-info-circle"></span></a>
<div #helppanel *ngIf="isOpen()" class="context-help-panel" [style.left]="left" [style.top]="top">
<ng-content></ng-content>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,14 @@ export class ContextHelpComponent {
return this._open;
}

/**
* Called whenever the user presses a key.
* @param event
*/
public onGlobalKeyDown(event: KeyboardEvent): void {
if (event.key === "Escape" && !event.metaKey && !event.altKey && !event.ctrlKey) {
this.close();
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</button>
<ul class="dropdown-menu " aria-labelledby="dropdownKebab">
<li>
<a href="javascript:return false" (click)="delete()">
<a href="#" onclick="return false" (click)="delete()">
<span class="pficon pficon-delete"></span>
<span>Delete Definition</span>
</a>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,45 @@
<div (window:keydown)="onGlobalKeyDown($event)" class="api-editor" [class.light]="theme === 'light'" [class.dark]="theme === 'dark'">
<div class="editor-master">
<!-- Path Context Menu -->
<ul id="path-context-menu" class="dropdown-menu context-menu" *ngIf="contextMenuType === 'path'"
[style.left]="contextMenuPos.left" [style.top]="contextMenuPos.top">
<li>
<a href="#" onclick="return false" (click)="newPath()">
<span class="pficon pficon-add-circle-o"></span>
<span>New Sub-Path</span>
</a>
</li>
<li class="divider"></li>
<li>
<a href="#" onclick="return false" (click)="deletePath()">
<span class="pficon pficon-delete"></span>
<span>Delete Path</span>
</a>
</li>
</ul>

<!-- Definition Context Menu -->
<ul id="definition-context-menu" class="dropdown-menu context-menu" *ngIf="contextMenuType === 'definition'"
[style.left]="contextMenuPos.left" [style.top]="contextMenuPos.top">
<li>
<a href="#" onclick="return false" (click)="deleteDefinition()">
<span class="pficon pficon-delete"></span>
<span>Delete Definition</span>
</a>
</li>
</ul>

<!-- Main Editor Selector (name of API, select to show Main Form -->
<div class="editor-main" [class.selected]="selectedType === 'main'" (click)="selectMain()">
<h2>{{ document().info.title }}</h2>
</div>

<!-- Search - Used to Filter Paths and Definitions -->
<div class="editor-search">
<search [placeholder]="'Search everything...'" [searchId]="'masterSearch'" (onSearch)="filterAll($event)"></search>
</div>

<!-- Outline - Paths, Defintions, Responses -->
<div class="editor-outline">
<!-- Paths Section -->
<div class="section path-section panel-group">
Expand Down Expand Up @@ -33,8 +67,9 @@ <h2>{{ document().info.title }}</h2>
</div>
<div class="section-body collapse in" id="path-section-body">
<div class="api-path" *ngFor="let pathName of pathNames()"
[class.contexted]="contextMenuType === 'path' && contextMenuItem === pathName"
[class.selected]="selectedItem === pathName && (selectedType === 'path' || selectedType === 'operation')">
<div path-item [path]="pathName" (click)="selectPath(pathName)"></div>
<div path-item [path]="pathName" (click)="selectPath(pathName)" (contextmenu)="showPathContextMenu($event, pathName)"></div>
<div class="api-operations" *ngIf="selectedItem === pathName && (selectedType === 'path' || selectedType === 'operation') && hasAtLeastOneOperation(pathName)">
<span *ngIf="hasOperation(pathName, 'get')" class="label label-success" (click)="selectOperation(selectedItem, 'get')"
[class.selected]="selectedType === 'operation' && subselectedItem === 'get'">GET</span>
Expand Down Expand Up @@ -83,7 +118,8 @@ <h2>{{ document().info.title }}</h2>
</div>
<div class="section-body collapse in" id="definition-section-body">
<div definition-item class="api-definition" *ngFor="let defName of definitionNames()" [name]="defName"
(click)="selectDefinition(defName)"
(click)="selectDefinition(defName)" (contextmenu)="showDefinitionContextMenu($event, defName)"
[class.contexted]="contextMenuType === 'definition' && contextMenuItem === defName"
[class.selected]="selectedItem === defName && selectedType === 'definition'"></div>
<div class="alert alert-info" *ngIf="definitionNames().length === 0">
<span class="pficon pficon-info"></span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
padding: 10px;
border: 1px solid #bbb;
border-radius: 3px;
box-shadow: 3px 3px 3px #aaa;
box-shadow: 0 6px 12px rgba(0,0,0,.175);
z-index: 150;
background: white;
font-size: 15px;
Expand Down Expand Up @@ -187,11 +187,15 @@
}
.api-editor .editor-master .editor-outline .api-path.selected .label.selected {
}

.api-editor .editor-master .editor-outline .api-path .api-operations {
margin-top: 5px;
padding-bottom: 10px;
}

.api-editor .editor-master .editor-outline .api-path.contexted {
cursor: default;
}

.api-editor .editor-master .editor-outline .api-definition {
padding-left: 15px;
Expand All @@ -203,6 +207,8 @@
.api-editor .editor-master .editor-outline .api-definition.selected {
cursor: default;
}
.api-editor .editor-master .editor-outline .api-definition.contexted {
}

.api-editor .editor-master .editor-outline .api-response {
padding-left: 15px;
Expand Down Expand Up @@ -534,3 +540,9 @@
.api-editor .editor-detail table tbody tr:hover td.actions > div {
visibility: visible;
}

#path-context-menu, #definition-context-menu {
display: block;
position: fixed;
}

Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
@themes-light-api-bg-color: white;
@themes-light-bg-transition: 200ms;
@themes-light-shadow-transition: 350ms;
@themes-light-api-ctxmenu-color: #E89F3D;
@themes-light-api-ctxmenu-color-light: #FFCC87;

.api-editor.light span.empty, .api-editor.light div.empty, .api-editor.light button.empty {
color: @themes-light-api-empty-label-color;
Expand Down Expand Up @@ -149,8 +151,6 @@
}




.api-editor.light .editor-master .editor-outline .api-path {
-webkit-transition: background-color @themes-light-bg-transition;
-moz-transition: background-color @themes-light-bg-transition;
Expand All @@ -161,10 +161,15 @@
.api-editor.light .editor-master .editor-outline .api-path:hover {
background-color: @themes-light-api-hover-color;
}

.api-editor.light .editor-master .editor-outline .api-path.selected {
background-color: @themes-light-api-selected-color-light;
border-left: 2px solid @themes-light-api-selected-color;
}
.api-editor.light .editor-master .editor-outline .api-path.contexted, .api-editor .editor-master .editor-outline .api-path.contexted:hover {
background-color: @themes-light-api-ctxmenu-color-light;
border-left: 2px dotted @themes-light-api-ctxmenu-color;
}
.api-editor.light .editor-master .editor-outline .api-path.selected span.path-param {
}
.api-editor.light .editor-master .editor-outline .api-path.selected .label {
Expand All @@ -182,6 +187,7 @@
border: 1px solid black;
box-shadow: 0 0 3px rgb(20,20,20);
}

.api-editor.light .editor-master .editor-outline .api-path .api-operations {
}

Expand All @@ -199,6 +205,10 @@
background-color: @themes-light-api-selected-color-light;
border-left: 2px solid @themes-light-api-selected-color;
}
.api-editor.light .editor-master .editor-outline .api-definition.contexted, .api-editor .editor-master .editor-outline .api-definition.contexted:hover {
background-color: @themes-light-api-ctxmenu-color-light;
border-left: 2px dotted @themes-light-api-ctxmenu-color;
}

.api-editor.light .editor-master .editor-outline .api-response {
-webkit-transition: background-color @themes-light-bg-transition;
Expand Down
90 changes: 88 additions & 2 deletions front-end/app/studio/pages/apis/{apiId}/editor/editor.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@
* limitations under the License.
*/

import {Component, EventEmitter, Output, Input, ViewEncapsulation, ViewChild} from "@angular/core";
import {Component, EventEmitter, Output, Input, ViewEncapsulation, ViewChild, HostListener} from "@angular/core";
import {ApiDefinition} from "../../../../models/api.model";
import {Oas20Document, OasLibraryUtils, Oas20PathItem, Oas20Operation, Oas20DefinitionSchema} from "oai-ts-core";
import {CommandsManager, ICommand} from "./commands.manager";
import {ModalDirective} from "ng2-bootstrap";
import {NewPathCommand} from "./commands/new-path.command";
import {NewDefinitionCommand} from "./commands/new-definition.command";
import {AddPathDialogComponent} from "./components/dialogs/add-path.component";
import {DeletePathCommand, DeleteDefinitionSchemaCommand} from "./commands/delete.command";


@Component({
Expand All @@ -45,6 +46,15 @@ export class ApiEditorComponent {
selectedType: string = "main";
subselectedItem: string = null;

contextMenuItem: string = null;
contextMenuType: string = null;
contextMenuPos: any = {
left: "0px",
top: "0px"
};

@ViewChild("addPathDialog") addPathDialog: AddPathDialogComponent;

filterCriteria: string = null;

/**
Expand Down Expand Up @@ -221,6 +231,9 @@ export class ApiEditorComponent {
this._commands.redoLastCommand(this.document());
this.onDirty.emit(true);
}
if (event.key === "Escape" && !event.metaKey && !event.altKey && !event.ctrlKey) {
this.closeContextMenu();
}
}

/**
Expand Down Expand Up @@ -393,4 +406,77 @@ export class ApiEditorComponent {
return name.toLowerCase().indexOf(this.filterCriteria) != -1;
}

/**
* Called when the user right-clicks on a path.
* @param event
* @param pathName
*/
public showPathContextMenu(event: MouseEvent, pathName: string): void {
event.preventDefault();
event.stopPropagation();
this.contextMenuPos.left = event.clientX + "px";
this.contextMenuPos.top = event.clientY + "px";
this.contextMenuType = "path";
this.contextMenuItem = pathName;
}

@HostListener("document:click", ["$event"])
public onDocumentClick(event: MouseEvent): void {
this.closeContextMenu();
}

/**
* Closes the context menu.
*/
private closeContextMenu(): void {
this.contextMenuItem = null;
this.contextMenuType = null;
}

/**
* Called when the user clicks "New Path" in the context-menu for a path.
*/
public newPath(): void {
this.addPathDialog.open(this.contextMenuItem);
this.closeContextMenu();
}

/**
* Called when the user clicks "Delete Path" in the context-menu for a path.
*/
public deletePath(): void {
let command: ICommand = new DeletePathCommand(this.contextMenuItem);
this.onCommand(command);
if (this.contextMenuItem === this.selectedItem) {
this.selectMain();
}
this.closeContextMenu();
}

/**
* Called when the user right-clicks on a path.
* @param event
* @param pathName
*/
public showDefinitionContextMenu(event: MouseEvent, definitionName: string): void {
event.preventDefault();
event.stopPropagation();
this.contextMenuPos.left = event.clientX + "px";
this.contextMenuPos.top = event.clientY + "px";
this.contextMenuType = "definition";
this.contextMenuItem = definitionName;
}

/**
* Called when the user clicks the "Delete Definition" item in the context-menu for a definition.
*/
public deleteDefinition(): void {
let command: ICommand = new DeleteDefinitionSchemaCommand(this.contextMenuItem);
this.onCommand(command);
if (this.contextMenuItem === this.selectedItem) {
this.selectMain();
}
this.closeContextMenu();
}

}

0 comments on commit 8569e5c

Please sign in to comment.