diff --git a/src/demo/app/editor.ts b/src/demo/app/editor.ts index b2e2d26..867f200 100644 --- a/src/demo/app/editor.ts +++ b/src/demo/app/editor.ts @@ -54,16 +54,15 @@ export class Editor implements Flo.Editor { createHandle(owner, Constants.REMOVE_HANDLE_TYPE, context.deleteSelectedNode, bbox.origin().offset(bbox.width + 3, bbox.height + 3)); // Properties handle - if (!owner.model.attr('metadata/unresolved')) { + if (!owner.model.get('metadata')?.unresolved) { createHandle(owner, Constants.PROPERTIES_HANDLE_TYPE, () => this.openPropertiesDialog(owner.model), bbox.origin().offset(-14, bbox.height + 3)); } } } openPropertiesDialog(cell : dia.Cell) { - console.log('Props view invoked!'); let bsModalRef = this.modelService.show(PropertiesDialogComponent); - let metadata : Flo.ElementMetadata = cell.attr('metadata'); + let metadata : Flo.ElementMetadata = cell.get('metadata'); bsModalRef.content.title = `Properties for ${metadata.name.toUpperCase()}`; let propertiesModel = new SamplePropertiesGroupModel(new Properties.DefaultCellPropertiesSource(cell)); propertiesModel.load(); @@ -102,11 +101,11 @@ export class Editor implements Flo.Editor { let graph = context.getGraph(); let source = dragDescriptor.source ? dragDescriptor.source.view.model : undefined; let target = dragDescriptor.target ? dragDescriptor.target.view.model : undefined; - if (target instanceof joint.dia.Element && target.attr('metadata/name')) { + if (target instanceof joint.dia.Element && target.get('metadata')?.name) { // Custom handling allowing a node to be dropped on a port and inserting // it into the flow directly without the user needing to do more link // drawing - let type = source.attr('metadata/name'); + let type = source.get('metadata')?.name; if (dragDescriptor.target.cssClassSelector === '.output-port') { this.moveNodeOnNode(context, source, target, 'right', true); relinking = true; @@ -128,7 +127,7 @@ export class Editor implements Flo.Editor { calculateDragDescriptor(context : Flo.EditorContext, draggedView : dia.CellView, targetUnderMouse : dia.CellView, point : g.Point, sourceComponent : string) : Flo.DnDDescriptor { let source = draggedView.model; - let sourceGroup = source.attr('metadata/group'); + let sourceGroup = source.get('metadata')?.group; // Find closest port let range = 30; @@ -148,7 +147,7 @@ export class Editor implements Flo.Editor { elements.forEach(function(model) { let view = paper.findViewByModel(model); if (view && view !== draggedView && model instanceof joint.dia.Element) { // jshint ignore:line - let targetGroup = model.attr('metadata/group'); + let targetGroup = model.get('metadata')?.group; let targetMaxIcomingLinks = targetGroup === 'source' ? 0 : 1; let targetMaxOutgoingLinks = targetGroup === 'sink' ? 0 : 1; let targetHasIncomingPort = targetGroup !== 'source'; @@ -211,14 +210,14 @@ export class Editor implements Flo.Editor { validate(graph : dia.Graph, dsl: string, flo: Flo.EditorContext) : Promise> { return new Promise((resolve, reject) => { let allMarkers = new Map>(); - graph.getElements().filter(e => e.attr('metadata')).forEach(e => { + graph.getElements().filter(e => e.get('metadata')).forEach(e => { let markers : Array = [] - let group = e.attr('metadata/group'); - if (e.attr('metadata/unresolved')) { + let group = e.get('metadata')?.group; + if (e.get('metadata')?.unresolved) { markers.push({ severity: Flo.Severity.Error, range: e.attr('range'), - message: `Unknown element '${e.attr('metadata/name')}` + (group ? ` from group '${e.attr('metadata/group')}'` : '') + message: `Unknown element '${e.get('metadata')?.name}` + (group ? ` from group '${e.get('metadata')?.group}'` : '') }); } else if (group) { let links = graph.getConnectedLinks(e); @@ -273,7 +272,7 @@ export class Editor implements Flo.Editor { markers.push({ severity: Flo.Severity.Error, range: e.attr('range'), - message: `Unknown element '${e.attr('metadata/name')} from group '${e.attr('metadata/group')}'` + message: `Unknown element '${e.get('metadata')?.name} from group '${e.get('metadata')?.group}'` }); } } @@ -285,7 +284,7 @@ export class Editor implements Flo.Editor { }); // var errors = []; // var graph = flo.getGraph(); - // var constraints = element.attr('metadata/constraints'); + // var constraints = element.get('metadata')?.constraints); // if (constraints) { // var incoming = graph.getConnectedLinks(element, {inbound: true}); // var outgoing = graph.getConnectedLinks(element, {outbound: true}); @@ -338,10 +337,10 @@ export class Editor implements Flo.Editor { // }); // } // } - // if (!element.attr('metadata') || element.attr('metadata/unresolved')) { - // var msg = 'Unknown element \'' + element.attr('metadata/name') + '\''; - // if (element.attr('metadata/group')) { - // msg += ' from group \'' + element.attr('metadata/group') + '\'.'; + // if (!element.get('metadata') || element.get('metadata').unresolved)) { + // var msg = 'Unknown element \'' + element.get('metadata')?.name + '\''; + // if (element.get('metadata')?.group) { + // msg += ' from group \'' + element.get('metadata')?.group + '\'.'; // } // errors.push({ // message: msg, @@ -354,7 +353,7 @@ export class Editor implements Flo.Editor { // // The format of a range is {'start':{'ch':NNNN,'line':NNNN},'end':{'ch':NNNN,'line':NNNN}} // var propertiesRanges = element.attr('propertiesranges'); // if (propertiesRanges) { - // var moduleSchema = element.attr('metadata'); + // var moduleSchema = element.get('metadata'); // // Grab the list of supported properties for this module type // moduleSchema.get('properties').then(function(moduleSchemaProperties) { // if (!moduleSchemaProperties) { @@ -370,7 +369,7 @@ export class Editor implements Flo.Editor { // var propertyRange = propertiesRanges[propertyName]; // if (propertyRange) { // errors.push({ - // message: 'unrecognized option \''+propertyName+'\' for module \''+element.attr('metadata/name')+'\'', + // message: 'unrecognized option \''+propertyName+'\' for module \''+element.get('metadata')?.name+'\'', // range: propertyRange // }); // } diff --git a/src/demo/app/graph-to-text.ts b/src/demo/app/graph-to-text.ts index 58e6538..ccbb6af 100644 --- a/src/demo/app/graph-to-text.ts +++ b/src/demo/app/graph-to-text.ts @@ -50,12 +50,12 @@ class GraphToTextConverter { this.nodesInDegrees = new Map(); this.g = graph; graph.getElements().forEach((element : dia.Element) => { - if (element.attr('metadata/name')) { + if (element.get('metadata')?.name) { this.nodesToVisit.add(element.get('id')); let indegree = 0; this.g.getConnectedLinks(element, {inbound: true}).forEach(link => { if (link.get('source') && link.get('source').id && this.g.getCell(link.get('source').id) && - this.g.getCell(link.get('source').id).attr('metadata/name')) { + this.g.getCell(link.get('source').id).get('metadata')?.name) { this.linksToVisit.add(link.get('id')); this.numberOfLinksToVisit++; indegree++; @@ -142,7 +142,7 @@ class GraphToTextConverter { if (!element) { return; } - text += element.attr('metadata/name'); + text += element.get('metadata')?.name; if (props) { Object.keys(props).forEach(propertyName => { text += ' --' + propertyName + '=' + props[propertyName]; diff --git a/src/demo/app/renderer.ts b/src/demo/app/renderer.ts index a6d11d2..a8e33bb 100644 --- a/src/demo/app/renderer.ts +++ b/src/demo/app/renderer.ts @@ -300,10 +300,10 @@ export class Renderer implements Flo.Renderer { } initializeNewNode(node : dia.Element, viewerDescriptor : Flo.ViewerDescriptor) { - let metadata : Flo.ElementMetadata = node.attr('metadata'); + let metadata : Flo.ElementMetadata = node.get('metadata'); if (metadata) { - node.attr('.label/text', node.attr('metadata/name')); - let group = node.attr('metadata/group'); + node.attr('.label/text', node.get('metadata').name); + let group = node.get('metadata')?.group; if (group === 'source') { node.attr('.input-port/display','none'); } diff --git a/src/lib/editor/editor.component.ts b/src/lib/editor/editor.component.ts index dafd31b..4f66c2f 100644 --- a/src/lib/editor/editor.component.ts +++ b/src/lib/editor/editor.component.ts @@ -432,7 +432,7 @@ export class EditorComponent implements OnInit, OnDestroy { if (newSelection && (newSelection.model.get('type') === joint.shapes.flo.DECORATION_TYPE || newSelection.model.get('type') === joint.shapes.flo.HANDLE_TYPE)) { newSelection = this.paper.findViewByModel(this.graph.getCell(newSelection.model.get('parent'))); } - if (newSelection && (!newSelection.model.attr('metadata') || newSelection.model.attr('metadata/metadata/unselectable'))) { + if (newSelection && (!newSelection.model.get('metadata') || newSelection.model.get('metadata')?.metadata?.unselectable)) { newSelection = undefined; } if (newSelection !== this._selection) { @@ -728,7 +728,7 @@ export class EditorComponent implements OnInit, OnDestroy { if (this.readOnlyCanvas) { this.setDragDescriptor(undefined); } else { - let metadata = cellview.model.attr('metadata'); + let metadata = cellview.model.get('metadata'); let props = cellview.model.attr('props'); let position = this.paper.snapToGrid({x: evt.clientX, y: evt.clientY}); @@ -1037,14 +1037,13 @@ export class EditorComponent implements OnInit, OnDestroy { handleNodeCreation(node: dia.Element) { node.on('change:size', this._resizeHandler); node.on('change:position', this._resizeHandler); - if (node.attr('metadata')) { + if (node.get('metadata')) { node.on('change:attrs', (cell: dia.Element, attrs: any, changeData: any) => { let propertyPath = changeData ? changeData.propertyPath : undefined; if (propertyPath) { let propAttr = propertyPath.substr(propertyPath.indexOf('/') + 1); - if (propAttr.indexOf('metadata') === 0 || - propAttr.indexOf('props') === 0 || + if (propAttr.indexOf('props') === 0 || (this.renderer && this.renderer.isSemanticProperty && this.renderer.isSemanticProperty(propAttr, node))) { this.performGraphToTextSyncing(); } @@ -1054,6 +1053,14 @@ export class EditorComponent implements OnInit, OnDestroy { } }); + + node.on('change:metadata', (cell: dia.Element, attrs: any, changeData: any) => { + let propertyPath = changeData ? changeData.propertyPath : undefined; + if (propertyPath && this.renderer && this.renderer.refreshVisuals) { + this.renderer.refreshVisuals(node, propertyPath, this.paper); + } + }); + } node.on('change:markers', () => { @@ -1101,8 +1108,7 @@ export class EditorComponent implements OnInit, OnDestroy { let propertyPath = changeData ? changeData.propertyPath : undefined; if (propertyPath) { let propAttr = propertyPath.substr(propertyPath.indexOf('/') + 1); - if (propAttr.indexOf('metadata') === 0 || - propAttr.indexOf('props') === 0 || + if (propAttr.indexOf('props') === 0 || (this.renderer && this.renderer.isSemanticProperty && this.renderer.isSemanticProperty(propAttr, link))) { let sourceId = link.get('source').id; let targetId = link.get('target').id; @@ -1114,6 +1120,13 @@ export class EditorComponent implements OnInit, OnDestroy { } }); + link.on('change:metadata', (cell: dia.Element, attrs: any, changeData: any) => { + let propertyPath = changeData ? changeData.propertyPath : undefined; + if (propertyPath && this.renderer && this.renderer.refreshVisuals) { + this.renderer.refreshVisuals(link, propertyPath, this.paper); + } + }); + this.paper.findViewByModel(link).on('link:options', () => this.handleLinkEvent('options', link)); if (this.readOnlyCanvas) { diff --git a/src/lib/palette/palette.component.ts b/src/lib/palette/palette.component.ts index 9721f51..413311c 100644 --- a/src/lib/palette/palette.component.ts +++ b/src/lib/palette/palette.component.ts @@ -301,7 +301,7 @@ export class Palette implements OnInit, OnDestroy { const presentGroups = new Set(); this.palette.model.getCells().forEach((cell: dia.Cell) => { - const metadata: Flo.ElementMetadata = cell.attr('metadata'); + const metadata: Flo.ElementMetadata = cell.get('metadata'); if (cell.get('header')) { paletteNodes.push(cell); } else if (metadata && metadata.group && metadata.name @@ -354,7 +354,7 @@ export class Palette implements OnInit, OnDestroy { let cellWidth = 0, cellHeight = 0; // Determine the size of the palette entry cell (width and height) paletteNodes.forEach(pnode => { - if (pnode.attr('metadata/name')) { + if (pnode.get('metadata')?.name) { const elementSize = this.palette.findViewByModel(pnode).getBBox(); let dimension: dia.Size = { width: elementSize.width, @@ -403,7 +403,7 @@ export class Palette implements OnInit, OnDestroy { pnode.set('position', { x: xpos + (cellWidth - dimension.width) / 2, y: ypos + (cellHeight - dimension.height) / 2}); } else { // Enough real estate to place entry in a row - adjust y position - if (prevNode && prevNode.attr('metadata/name')) { + if (prevNode && prevNode.get('metadata')?.name) { ypos -= cellHeight; } pnode.set('position', { x: xpos + (cellWidth - dimension.width) / 2, y: ypos + (cellHeight - dimension.height) / 2}); @@ -452,7 +452,7 @@ export class Palette implements OnInit, OnDestroy { // $('.node-tooltip').remove(); // TODO move metadata to the right place (not inside attrs I think) self.clickedElement = this.model; - if (self.clickedElement && self.clickedElement.attr('metadata')) { + if (self.clickedElement && self.clickedElement.get('metadata')) { $(self.document).on('mousemove', self.mouseMoveHanlder); } }, @@ -469,7 +469,7 @@ export class Palette implements OnInit, OnDestroy { // } // // var model = this.model; - // var metadata = model.attr('metadata'); + // var metadata = model.get('metadata'); // if (!metadata) { // return; // } @@ -487,7 +487,7 @@ export class Palette implements OnInit, OnDestroy { // showTooltip: function(x, y) { // var model = this.model; - // var metadata = model.attr('metadata'); + // var metadata = model.get('metadata'); // // TODO refactor to use tooltip module // var nodeTooltip = document.createElement('div'); // $(nodeTooltip).addClass('node-tooltip'); @@ -555,10 +555,10 @@ export class Palette implements OnInit, OnDestroy { // TODO offsetX/Y not on firefox // console.debug("tracking move: x="+event.pageX+",y="+event.pageY); // console.debug('Element = ' + (this.clickedElement ? this.clickedElement.attr('metadata/name'): 'null')); - if (this.clickedElement && this.clickedElement.attr('metadata')) { + if (this.clickedElement && this.clickedElement.get('metadata')) { if (!this.viewBeingDragged) { - let dataOfClickedElement: Flo.ElementMetadata = this.clickedElement.attr('metadata'); + let dataOfClickedElement: Flo.ElementMetadata = this.clickedElement.get('metadata'); // custom div if not already built. $('
', { id: 'palette-floater' diff --git a/src/lib/shared/flo-properties.ts b/src/lib/shared/flo-properties.ts index 40bddb6..1a1f7c8 100644 --- a/src/lib/shared/flo-properties.ts +++ b/src/lib/shared/flo-properties.ts @@ -247,7 +247,7 @@ export namespace Properties { } getProperties(): Promise> { - let metadata: Flo.ElementMetadata = this.cell.attr('metadata'); + let metadata: Flo.ElementMetadata = this.cell.get('metadata'); return Promise.resolve(metadata.properties().then(propsMetadata => Array.from(propsMetadata.values()).map(m => this.createProperty(m)))); } diff --git a/src/lib/shared/shapes.ts b/src/lib/shared/shapes.ts index b24e72b..ccaea0c 100644 --- a/src/lib/shared/shapes.ts +++ b/src/lib/shared/shapes.ts @@ -402,7 +402,7 @@ export function loadShapes() { // var mousey = y + 10; // // var nodeTooltip: HTMLElement; - // if (this.model instanceof joint.dia.Element && this.model.attr('metadata')) { + // if (this.model instanceof joint.dia.Element && this.model.get('metadata')) { // nodeTooltip = document.createElement('div'); // $(nodeTooltip).addClass('node-tooltip'); // @@ -428,7 +428,7 @@ export function loadShapes() { // } // } // - // model.attr('metadata').get('description').then(function(description: string) { + // model.get('metadata').get('description').then(function(description: string) { // $(nodeDescription).text(description); // }, function(error: any) { // if (error) { @@ -438,7 +438,7 @@ export function loadShapes() { // // // defaultValue // if (!model.attr('metadata/metadata/hide-tooltip-options')) { - // model.attr('metadata').get('properties').then(function(metaProps: any) { + // model.get('metadata')?.get('properties').then(function(metaProps: any) { // var props = model.attr('props'); // array of {'name':,'value':} // if (metaProps && props) { // Object.keys(props).sort().forEach(function(propertyName) { @@ -661,7 +661,7 @@ export namespace Shapes { if (props) { Array.from(props.keys()).forEach(key => node.attr(`props/${key}`, props!.get(key))); } - node.attr('metadata', metadata); + node.set('metadata', metadata); if (graph) { graph.addCell(node); } @@ -698,7 +698,7 @@ export namespace Shapes { } link.set('type', joint.shapes.flo.LINK_TYPE); if (metadata) { - link.attr('metadata', metadata); + link.set('metadata', metadata); } if (props) { Array.from(props.keys()).forEach(key => link.attr(`props/${key}`, props!.get(key)));