Palette visuals for no matches. Filter text placeholder binding.
This commit is contained in:
@@ -7,7 +7,9 @@
|
||||
Spring Flo Sample
|
||||
</div>
|
||||
<div id="flo-container">
|
||||
<flo-editor (floApi)="editorContext = $event" [metamodel]="metamodel" [renderer]="renderer" [editor]="editor" [paletteSize]="paletteSize" [paletteEntryPadding]="{width: 4, height: 4}" [(dsl)]="dsl" [paperPadding]="20" (validationMarkers)="markersChanged($event)">
|
||||
<flo-editor (floApi)="editorContext = $event" [metamodel]="metamodel" [renderer]="renderer" [editor]="editor"
|
||||
[paletteSize]="paletteSize" [paletteEntryPadding]="{width: 4, height: 4}" [(dsl)]="dsl"
|
||||
[paperPadding]="20" (validationMarkers)="markersChanged($event)" searchFilterPlaceHolder="Apps...">
|
||||
<div header>
|
||||
<div id="controls" class="controls">
|
||||
<button class="button" id="clearGraph" (click)="editorContext.clearGraph()">Create New Flow</button>
|
||||
@@ -15,27 +17,42 @@
|
||||
<button class="button" id="deleteSelectedNode" ng-click="flo.deleteSelectedNode()">Delete Selected Node</button>
|
||||
-->
|
||||
<button class="button" id="performLayout" (click)="arrangeAll()">Reset Layout</button>
|
||||
<button class="button" id="sync" (click)="editorContext.graphToTextSync = !editorContext.graphToTextSync" [ngClass]="{on:editorContext.graphToTextSync}">Synchronize</button>
|
||||
<button class="button" id="readOnly" (click)="editorContext.readOnlyCanvas = !editorContext.readOnlyCanvas" [ngClass]="{on:editorContext.readOnlyCanvas}">Read-Only</button>
|
||||
<button class="button" id="noPalette" (click)="editorContext.noPalette = !editorContext.noPalette" [ngClass]="{on:!editorContext.noPalette}">Palette</button>
|
||||
<button class="button" id="editor" (click)="dslEditor = !dslEditor" [ngClass]="{on:dslEditor}">{{dslEditor ? 'TextArea' : 'Editor'}}</button>
|
||||
<button class="button" id="sync" (click)="editorContext.graphToTextSync = !editorContext.graphToTextSync"
|
||||
[ngClass]="{on:editorContext.graphToTextSync}">Synchronize
|
||||
</button>
|
||||
<button class="button" id="readOnly" (click)="editorContext.readOnlyCanvas = !editorContext.readOnlyCanvas"
|
||||
[ngClass]="{on:editorContext.readOnlyCanvas}">Read-Only
|
||||
</button>
|
||||
<button class="button" id="noPalette" (click)="editorContext.noPalette = !editorContext.noPalette"
|
||||
[ngClass]="{on:!editorContext.noPalette}">Palette
|
||||
</button>
|
||||
<button class="button" id="editor" (click)="dslEditor = !dslEditor" [ngClass]="{on:dslEditor}">{{dslEditor ?
|
||||
'TextArea' : 'Editor'}}
|
||||
</button>
|
||||
<span class="button">
|
||||
<label>Zoom: </label>
|
||||
<input id="zoomInput" type="text" [(ngModel)]="editorContext.zoomPercent" size="3">
|
||||
<label>%</label>
|
||||
<input type="range" [(ngModel)]="editorContext.zoomPercent" [step]="editorContext.getZoomStep()" [max]="editorContext.getMaxZoom()" [min]="editorContext.getMinZoom()" data-type="range" name="range" class="range">
|
||||
<input type="range" [(ngModel)]="editorContext.zoomPercent" [step]="editorContext.getZoomStep()"
|
||||
[max]="editorContext.getMaxZoom()" [min]="editorContext.getMinZoom()" data-type="range" name="range"
|
||||
class="range">
|
||||
</span>
|
||||
<span class="button">
|
||||
<label>Grid Size: </label>
|
||||
<input id="gridSizeInput" type="text" [(ngModel)]="editorContext.gridSize" size="2">
|
||||
<label>pixels</label>
|
||||
<input type="range" [(ngModel)]="editorContext.gridSize" step="1" max="50" min="1" data-type="range" name="range" class="range">
|
||||
<input type="range" [(ngModel)]="editorContext.gridSize" step="1" max="50" min="1" data-type="range"
|
||||
name="range" class="range">
|
||||
</span>
|
||||
</div>
|
||||
<div class="flow-definition-container">
|
||||
<dsl-editor *ngIf="dslEditor" [(dsl)]="dsl" line-numbers="true" line-wrapping="true" (blur)="editorContext.graphToTextSync=true" (focus)="editorContext.graphToTextSync=false" placeholder="Enter stream definition..."></dsl-editor>
|
||||
<textarea *ngIf="!dslEditor" id="flow-definition" class="flow-definition" placeholder="Enter stream definition..."
|
||||
[value]="dsl" (keyup)="dsl=$event.target.value" (blur)="editorContext.graphToTextSync=true" (focus)="editorContext.graphToTextSync=false"></textarea>
|
||||
<dsl-editor *ngIf="dslEditor" [(dsl)]="dsl" line-numbers="true" line-wrapping="true"
|
||||
(blur)="editorContext.graphToTextSync=true" (focus)="editorContext.graphToTextSync=false"
|
||||
placeholder="Enter stream definition..."></dsl-editor>
|
||||
<textarea *ngIf="!dslEditor" id="flow-definition" class="flow-definition"
|
||||
placeholder="Enter stream definition..."
|
||||
[value]="dsl" (keyup)="dsl=$event.target.value" (blur)="editorContext.graphToTextSync=true"
|
||||
(focus)="editorContext.graphToTextSync=false"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</flo-editor>
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
[paletteEntryPadding]="paletteEntryPadding || {width: 12, height: 12}"
|
||||
(onPaletteEntryDrop)="handleDnDFromPalette($event)"
|
||||
(paletteReady)="updatePaletteReadyState($event)"
|
||||
(paletteFocus)="graphToTextSync=true"></flo-palette>
|
||||
(paletteFocus)="graphToTextSync=true"
|
||||
[searchFilterPlaceHolder]="searchFilterPlaceHolder">
|
||||
</flo-palette>
|
||||
</div>
|
||||
|
||||
<div id="sidebar-resizer" *ngIf="!noPalette"
|
||||
|
||||
@@ -113,6 +113,9 @@ export class EditorComponent implements OnInit, OnDestroy {
|
||||
this.paletteSizeChange.emit(newSize);
|
||||
}
|
||||
|
||||
@Input()
|
||||
searchFilterPlaceHolder = 'Search...';
|
||||
|
||||
/**
|
||||
* Palette entry padding
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<div id="palette-filter" class="palette-filter">
|
||||
<label class="palette-filter-label" for="palette-filter-textfield">
|
||||
<input type="search" id="palette-filter-textfield" class="palette-filter-textfield" [(ngModel)]="filterText" (focus)="onFocus()" placeholder="Applications"/>
|
||||
<input type="search" id="palette-filter-textfield" class="palette-filter-textfield" [(ngModel)]="filterText" (focus)="onFocus()" [placeholder]="searchFilterPlaceHolder"/>
|
||||
</label>
|
||||
</div>
|
||||
<div id="palette-paper-container">
|
||||
|
||||
@@ -35,6 +35,39 @@ joint.shapes.flo.PaletteGroupHeader = joint.shapes.basic.Generic.extend({
|
||||
}, joint.shapes.basic.Generic.prototype.defaults)
|
||||
});
|
||||
|
||||
joint.shapes.flo.NoMatchesFound = joint.shapes.basic.Generic.extend({
|
||||
// The path is the open/close arrow, defaults to vertical (open)
|
||||
markup: '<g class="scalable"><rect class="no-matches-label-border"/></g><rect class="no-mathes-label-bg"/><text class="no-matches-label"/>',
|
||||
defaults: joint.util.deepSupplement({
|
||||
size: {width: 170, height: 30},
|
||||
position: {x: 0, y: 0},
|
||||
attrs: {
|
||||
'.no-matches-label-border': {
|
||||
refWidth: 1,
|
||||
refHeight: 1,
|
||||
refX: 0,
|
||||
refY: 0,
|
||||
},
|
||||
'.no-macthes-label-bg': {
|
||||
ref: '.no-matches-label',
|
||||
refWidth: 10,
|
||||
refHeight: 2,
|
||||
'follow-scale': true
|
||||
},
|
||||
'.no-matches-label': {
|
||||
text: 'No Matches Found...',
|
||||
ref: '.no-matches-label-border',
|
||||
refX: 0.5,
|
||||
refY: 0.5,
|
||||
xAlignment: 'middle',
|
||||
yAlignment: 'middle',
|
||||
'fill': '#777777',
|
||||
'font-style': 'italic'
|
||||
},
|
||||
},
|
||||
}, joint.shapes.basic.Generic.prototype.defaults)
|
||||
});
|
||||
|
||||
@Component({
|
||||
selector: 'flo-palette',
|
||||
templateUrl: './palette.component.html',
|
||||
@@ -79,6 +112,8 @@ export class Palette implements OnInit, OnDestroy, OnChanges {
|
||||
|
||||
private filterTextModel = new Subject<string>();
|
||||
|
||||
private noMacthesFoundNode: dia.Cell;
|
||||
|
||||
@Input()
|
||||
metamodel: Flo.Metamodel;
|
||||
|
||||
@@ -88,6 +123,9 @@ export class Palette implements OnInit, OnDestroy, OnChanges {
|
||||
@Input()
|
||||
paletteEntryPadding: dia.Size = {width: 12, height: 12};
|
||||
|
||||
@Input()
|
||||
searchFilterPlaceHolder = 'Search...';
|
||||
|
||||
@Output()
|
||||
onPaletteEntryDrop = new EventEmitter<Flo.DnDEvent>();
|
||||
|
||||
@@ -292,7 +330,7 @@ export class Palette implements OnInit, OnDestroy, OnChanges {
|
||||
this.createPaletteGroup(group, !this.closedGroups.has(group));
|
||||
groupAdded.add(group);
|
||||
}
|
||||
if (!this.closedGroups.has(group)) {
|
||||
if (!(node.metadata && node.metadata.noPaletteEntry)) {
|
||||
this.createPaletteEntry(name, node);
|
||||
}
|
||||
}
|
||||
@@ -300,6 +338,9 @@ export class Palette implements OnInit, OnDestroy, OnChanges {
|
||||
}
|
||||
});
|
||||
|
||||
this.noMacthesFoundNode = new joint.shapes.flo.NoMatchesFound();
|
||||
this.palette.model.addCell(this.noMacthesFoundNode);
|
||||
|
||||
this.layout();
|
||||
|
||||
this.paletteReady.emit(true);
|
||||
@@ -321,16 +362,36 @@ export class Palette implements OnInit, OnDestroy, OnChanges {
|
||||
|
||||
this.palette.model.getCells().forEach((cell: dia.Cell) => {
|
||||
const metadata: Flo.ElementMetadata = cell.attr('metadata');
|
||||
if (cell.get('header') || metadata && metadata.group && metadata.name && !this.closedGroups.has(metadata.group)
|
||||
&& (!filterText || metadata.group.indexOf(filterText) >= 0 || metadata.group.indexOf(filterText) >= 0)) {
|
||||
if (cell.get('header')) {
|
||||
const previous = paletteNodes.length > 0 ? paletteNodes[paletteNodes.length - 1] : undefined;
|
||||
// If previous is a paletter header node as well then the previous header had no nodes under it and we can hide it and remove from paletteNodes aeeay
|
||||
if (previous && previous.get('header') && !this.closedGroups.has(previous.get('header'))) {
|
||||
paletteNodes.pop().attr('./display', 'none');
|
||||
}
|
||||
cell.attr('./display', 'block');
|
||||
cell.removeAttr('./display');
|
||||
paletteNodes.push(cell);
|
||||
} else if (metadata && metadata.group && metadata.name && !this.closedGroups.has(metadata.group)
|
||||
&& (!filterText || metadata.group.indexOf(filterText) >= 0 || metadata.name.indexOf(filterText) >= 0)) {
|
||||
cell.attr('./display', 'block');
|
||||
cell.removeAttr('./display');
|
||||
paletteNodes.push(cell);
|
||||
} else {
|
||||
cell.attr('./display', 'none');
|
||||
if (cell === this.noMacthesFoundNode) {
|
||||
|
||||
} else {
|
||||
cell.attr('./display', 'none');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Check if last group is empty
|
||||
const previous = paletteNodes.length > 0 ? paletteNodes[paletteNodes.length - 1] : undefined;
|
||||
// If previous is a paletter header node as well then the previous header had no nodes under it and we can hide it and remove from paletteNodes aeeay
|
||||
if (previous && previous.get('header') && !this.closedGroups.has(previous.get('header'))) {
|
||||
paletteNodes.pop().attr('./display', 'none');
|
||||
}
|
||||
|
||||
let cellWidth = 0, cellHeight = 0;
|
||||
// Determine the size of the palette entry cell (width and height)
|
||||
paletteNodes.forEach(pnode => {
|
||||
@@ -394,6 +455,20 @@ export class Palette implements OnInit, OnDestroy, OnChanges {
|
||||
}
|
||||
prevNode = pnode;
|
||||
});
|
||||
|
||||
this.noMacthesFoundNode.set('size', {width: parentWidth, height: this.noMacthesFoundNode.get('size').height || 30});
|
||||
this.noMacthesFoundNode.set('position', {x: 0, y: 0});
|
||||
if (paletteNodes.length === 0 && filterText) {
|
||||
// There is a filter present but everything is filtered out
|
||||
// Show no matches found node
|
||||
this.noMacthesFoundNode.attr('./display', 'block');
|
||||
this.noMacthesFoundNode.removeAttr('./display');
|
||||
ypos = this.noMacthesFoundNode.get('size').height;
|
||||
} else {
|
||||
// Hide no matches node in all other cases
|
||||
this.noMacthesFoundNode.attr('./display', 'none');
|
||||
}
|
||||
|
||||
this.palette.setDimensions(parentWidth, ypos);
|
||||
console.debug('buildPalette layout ' + (new Date().getTime() - startTime) + 'ms');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user