diff --git a/addon/components/fd-uml-diagram-editor.js b/addon/components/fd-uml-diagram-editor.js index 7b96d9e5f..f20bd4903 100644 --- a/addon/components/fd-uml-diagram-editor.js +++ b/addon/components/fd-uml-diagram-editor.js @@ -345,7 +345,9 @@ FdActionsForUcdPrimitivesMixin, { let type = this.get('type'); if (type === 'Link') { let newLink = this.get('newLink'); - if (newLink.vertices().length === 0) { + if (isNone(newLink)) { + this.clearData(); + } else if (newLink.vertices().length === 0) { let primitives = this.get('model.primitives'); let linkPrimitive = primitives.findBy('id', newLink.get('id')); primitives.removeObject(linkPrimitive); @@ -383,16 +385,14 @@ FdActionsForUcdPrimitivesMixin, { this.paper.fDDEditMode = buttonName; switch (buttonName) { case 'pointerClick': - this._enableEditLinks(); - break; case 'addNoteConnector': - this._enableWrapLinks(); + this.enableEditLinks(); break; case 'addInheritance': - this._enableWrapBaseLinks(); + this.enableWrapBaseLinks(); break; default: - this._disableEditLinks(); + this.disableEditLinks(); } this.send(buttonName, e); } @@ -452,7 +452,8 @@ FdActionsForUcdPrimitivesMixin, { clearData() { this._clearProperties(); this._resetCurrentTargetElement(); - this._enableEditLinks(); + this.enableEditLinks(); + this.paper.fDDEditMode = 'pointerClick'; }, /** @@ -469,21 +470,17 @@ FdActionsForUcdPrimitivesMixin, { this.set('newLink', undefined); }, - _enableEditLinks: function() { + enableEditLinks: function() { let paper = this.paper; let links = paper.model.getLinks(); for (let i = 0; i < links.length; i+=1) { let link = links[i]; let view = link.findView(paper); view.$el.removeClass('edit-disabled'); - view.$el.removeClass('linktools-disabled'); - if ('vertexAdd' in view.options.interactive) { - delete view.options.interactive.vertexAdd; - } } }, - _enableWrapBaseLinks: function() { + enableWrapBaseLinks: function() { let paper = this.paper; let links = paper.model.getLinks(); for (let i = 0; i < links.length; i+=1) { @@ -491,27 +488,13 @@ FdActionsForUcdPrimitivesMixin, { let view = link.findView(paper); if (link.get('type') == 'flexberry.uml.Generalization' && !link.connectedToLine()) { view.$el.removeClass('edit-disabled'); - view.$el.addClass('linktools-disabled'); - view.options.interactive.vertexAdd = false; } else { view.$el.addClass('edit-disabled'); } } }, - _enableWrapLinks: function() { - let paper = this.paper; - let links = paper.model.getLinks(); - for (let i = 0; i < links.length; i+=1) { - let link = links[i]; - let view = link.findView(paper); - view.$el.removeClass('edit-disabled'); - view.$el.addClass('linktools-disabled'); - view.options.interactive.vertexAdd = false; - } - }, - - _disableEditLinks: function() { + disableEditLinks: function() { let paper = this.paper; let links = paper.model.getLinks(); for (let i = 0; i < links.length; i+=1) { diff --git a/addon/components/fd-uml-diagram.js b/addon/components/fd-uml-diagram.js index 8ec6cca9e..9614b8d54 100644 --- a/addon/components/fd-uml-diagram.js +++ b/addon/components/fd-uml-diagram.js @@ -147,14 +147,10 @@ export default Component.extend({ paper.off('element:pointerup', this._ghostElementRemove, this); } else { $(paper.el).find('input,textarea').removeClass('click-disabled'); - paper.setInteractivity({ elementMove: false }); + paper.setInteractivity({ elementMove: false, vertexAdd: false }); paper.on('element:pointermove', this._ghostElementMove, this); paper.on('element:pointerup', this._ghostElementRemove, this); - let highlightedElement = this.get('highlightedElement'); - if (highlightedElement) { - highlightedElement.unhighlight(); - this.set('highlightedElement', null); - } + this._highlighted(null); } }), @@ -177,7 +173,6 @@ export default Component.extend({ graph.getLinks().map(link => { link.findView(paper).$el.removeClass('edit-disabled'); - link.findView(paper).$el.removeClass('linktools-disabled'); }, this); $(paper.el).find('input,textarea').removeClass('click-disabled'); @@ -187,16 +182,17 @@ export default Component.extend({ switch (this.paper.fDDEditMode) { case 'addNoteConnector': - this._enableWrapLinks(); + this.enableEditLinks(); break; case 'addInheritance': - this._enableWrapBaseLinks(); + this.enableWrapBaseLinks(); break; default: - this._disableEditLinks(); + this.disableEditLinks(); } $(paper.el).find('input,textarea').addClass('click-disabled'); + this._highlighted(null); } }), @@ -214,7 +210,7 @@ export default Component.extend({ el: this.get('element'), model: graph, gridSize: 10, - drawGrid: true, + drawGrid: { name: 'fixedDot', args: { color: '#cecece' }}, connectionStrategy: joint.connectionStrategies.toPointConnection, defaultConnectionPoint: joint.connectionPoints.toPointConnection, restrictTranslate: ({ paper }) => { @@ -238,7 +234,8 @@ export default Component.extend({ } }, interactive: { - elementMove: false + elementMove: false, + vertexAdd: false, }, cellNamespace: namespace, cellViewNamespace: namespace @@ -317,11 +314,7 @@ export default Component.extend({ _blankPointerClick(e) { let coordinates = forBlankEventPointerClickAndContextMenu(e); let options = { e: e, x: coordinates.x, y: coordinates.y }; - let highlightedElement = this.get('highlightedElement'); - if (highlightedElement) { - highlightedElement.unhighlight(); - this.set('highlightedElement', null); - } + this._highlighted(null); let newElement = this.get('blankPointerClick')(options); this._addNewElement(newElement); @@ -369,7 +362,8 @@ export default Component.extend({ for (let i = 0; i < links.length; i+=1) { let link = links[i]; let view = link.findView(paper); - view.$el.addClass('edit-disabled'); + view.$el.addClass('edit-disabled'); + $(paper.el).find('input,textarea').addClass('click-disabled'); } $(document).on({ 'mousemove.link': this._onDrag.bind(this) @@ -381,8 +375,9 @@ export default Component.extend({ break; } default: - if (isNone(this.get('draggedLink'))) { - return; + if (this.get('currentTargetElementIsPointer')) { + var linkView = element.model.findView(this.paper); + linkView.highlight(); } } } else { @@ -432,9 +427,6 @@ export default Component.extend({ let view = link.findView(paper); if (link.cid == newElement.cid) { view.$el.addClass('edit-disabled'); - } else { - view.$el.addClass('linktools-disabled'); - view.options.interactive.vertexAdd = false; } } @@ -523,9 +515,18 @@ export default Component.extend({ _highlighted(cellView) { let highlightedElement = this.get('highlightedElement'); if (highlightedElement && highlightedElement !== cellView) { + if (highlightedElement.model.isLink()) { + highlightedElement.$el.addClass('linktools-disabled'); + } + highlightedElement.unhighlight(); } + if (!isNone(cellView) && cellView.model.isLink() && !this.get('readonly')) { + cellView.$el.removeClass('linktools-disabled'); + cellView.updateArrowheadMarkers(); + } + this.set('highlightedElement', cellView); }, @@ -544,9 +545,6 @@ export default Component.extend({ graph.getLinks().map(link => { let view = link.findView(paper); view.$el.removeClass('edit-disabled'); - if ('vertexAdd' in view.options.interactive) { - delete view.options.interactive.vertexAdd; - } }, this); $(paper.el).find('input,textarea').removeClass('click-disabled'); @@ -557,6 +555,7 @@ export default Component.extend({ this.set('draggedLink', undefined); this.set('draggedLinkView', undefined); this.set('isLinkAdding', false); + this._highlighted(null); }, /** @@ -1185,58 +1184,6 @@ export default Component.extend({ this._incrementPropertyReferenceCount(newElement); }, - _enableEditLinks: function() { - let paper = this.paper; - let links = paper.model.getLinks(); - for (let i = 0; i < links.length; i+=1) { - let link = links[i]; - let view = link.findView(paper); - view.$el.removeClass('edit-disabled'); - view.$el.removeClass('linktools-disabled'); - if ('vertexAdd' in view.options.interactive) { - delete view.options.interactive.vertexAdd; - } - } - }, - - _enableWrapBaseLinks: function() { - let paper = this.paper; - let links = paper.model.getLinks(); - for (let i = 0; i < links.length; i+=1) { - let link = links[i]; - let view = link.findView(paper); - if (link.get('type') == 'flexberry.uml.Generalization' && !link.connectedToLine()) { - view.$el.removeClass('edit-disabled'); - view.$el.addClass('linktools-disabled'); - view.options.interactive.vertexAdd = false; - } else { - view.$el.addClass('edit-disabled'); - } - } - }, - - _enableWrapLinks: function() { - let paper = this.paper; - let links = paper.model.getLinks(); - for (let i = 0; i < links.length; i+=1) { - let link = links[i]; - let view = link.findView(paper); - view.$el.removeClass('edit-disabled'); - view.$el.addClass('linktools-disabled'); - view.options.interactive.vertexAdd = false; - } - }, - - _disableEditLinks: function() { - let paper = this.paper; - let links = paper.model.getLinks(); - for (let i = 0; i < links.length; i+=1) { - let link = links[i]; - let view = link.findView(paper); - view.$el.addClass('edit-disabled'); - } - }, - _haveNote: function() { let paper = this.paper; let elements = paper.model.getElements(); diff --git a/addon/objects/uml-primitives/fd-uml-primitive.js b/addon/objects/uml-primitives/fd-uml-primitive.js index 6306b1c4c..fa459138c 100644 --- a/addon/objects/uml-primitives/fd-uml-primitive.js +++ b/addon/objects/uml-primitives/fd-uml-primitive.js @@ -163,9 +163,7 @@ joint.highlighters.strokeAndButtons = { _buttons: {}, highlight: function(cellView, magnetEl, opt) { - //joint.highlighters.stroke.highlight(...arguments); let stroke = joint.highlighters.stroke; - let V = joint.Vectorizer; let id = stroke.getHighlighterId(magnetEl, opt); @@ -175,6 +173,56 @@ joint.highlighters.strokeAndButtons = { } let options = joint.util.defaults(opt || {}, stroke.defaultOptions); + + let highlightVel; + if (cellView.model.isLink()) { + highlightVel = this.linkHighlightVel(cellView, magnetEl, options); + } else { + highlightVel = this.elementHighlightVel(cellView, magnetEl, options); + } + + // joint.mvc.View will handle the theme class name and joint class name prefix. + let highlightView = stroke._views[id] = new joint.mvc.View({ + svgElement: true, + className: 'highlight-stroke', + el: highlightVel.node + }); + + // Remove the highlight view when the cell is removed from the graph. + let removeHandler = function() { + this.removeButtons(id); + stroke.removeHighlighter.bind(stroke, id); + }.bind(this); + + let cell = cellView.model; + highlightView.listenTo(cell, 'remove', removeHandler); + highlightView.listenTo(cell.graph, 'reset', removeHandler); + cellView.vel.append(highlightVel); + + if (cellView.getButtons instanceof Function) { + this.addButtons(cellView, id); + } + + if (cellView.getSizeChangers instanceof Function) { + this.addSizeChangers(cellView, id); + } + + cellView.update(); + + cellView.model.set('highlighted', true); + }, + + unhighlight: function(cellView, magnetEl, opt) { + joint.highlighters.stroke.unhighlight(...arguments); + let stroke = joint.highlighters.stroke; + let id = stroke.getHighlighterId(magnetEl, opt); + this.removeButtons(id); + + cellView.model.set('highlighted', false); + }, + + elementHighlightVel(cellView, magnetEl, options) { + let V = joint.Vectorizer; let magnetVel = V(magnetEl); let magnetBBox; let pathData; @@ -228,44 +276,19 @@ joint.highlighters.strokeAndButtons = { highlightVel.transform(highlightMatrix); - // joint.mvc.View will handle the theme class name and joint class name prefix. - let highlightView = stroke._views[id] = new joint.mvc.View({ - svgElement: true, - className: 'highlight-stroke', - el: highlightVel.node - }); - - // Remove the highlight view when the cell is removed from the graph. - let removeHandler = function() { - this.removeButtons(id); - stroke.removeHighlighter.bind(stroke, id); - }.bind(this); - - let cell = cellView.model; - highlightView.listenTo(cell, 'remove', removeHandler); - highlightView.listenTo(cell.graph, 'reset', removeHandler); - - cellView.vel.append(highlightVel); - if (cellView.getButtons instanceof Function) { - this.addButtons(cellView, id); - } - - if (cellView.getSizeChangers instanceof Function) { - this.addSizeChangers(cellView, id); - } - - cellView.update(); - - cellView.model.set('highlighted', true); + return highlightVel; }, - unhighlight: function(cellView, magnetEl, opt) { - joint.highlighters.stroke.unhighlight(...arguments); - let stroke = joint.highlighters.stroke; - let id = stroke.getHighlighterId(magnetEl, opt); - this.removeButtons(id); + linkHighlightVel(cellView, magnetEl, options) { + let V = joint.Vectorizer; + let highlightVel = V('path').attr({ + 'd': cellView.metrics.data, + 'pointer-events': 'none', + 'vector-effect': 'non-scaling-stroke', + 'fill': 'none' + }).attr(options.attrs); - cellView.model.set('highlighted', false); + return highlightVel; }, addSizeChangers(cellView, id) { diff --git a/addon/objects/uml-primitives/links-view/fd-empty-view.js b/addon/objects/uml-primitives/links-view/fd-empty-view.js index b8485efca..e03c74b0b 100644 --- a/addon/objects/uml-primitives/links-view/fd-empty-view.js +++ b/addon/objects/uml-primitives/links-view/fd-empty-view.js @@ -1,6 +1,6 @@ import { isNone } from '@ember/utils'; import { computed, get } from '@ember/object'; -import { isArray } from '@ember/array'; +import { A, isArray } from '@ember/array'; import { schedule } from '@ember/runloop'; import joint from 'npm:jointjs'; import $ from 'jquery'; @@ -16,6 +16,7 @@ export let EmptyView = joint.dia.LinkView.extend({ this.$box = $(this.template); this.model.inputElements = this.$box; + this.$el.addClass('linktools-disabled') this.setColors(); @@ -26,6 +27,7 @@ export let EmptyView = joint.dia.LinkView.extend({ this.$box.css('visibility', 'visible'); schedule('afterRender', this, function() { this.updateBox(); + this.highlight(); }); objectModel.set('source', newSource); @@ -33,6 +35,7 @@ export let EmptyView = joint.dia.LinkView.extend({ this.paper.trigger('checkexistelements', objectModel, this, true); } else { this.$box.css('visibility', 'hidden'); + this.unhighlight(); } } }, this); @@ -44,12 +47,14 @@ export let EmptyView = joint.dia.LinkView.extend({ this.$box.css('visibility', 'visible'); schedule('afterRender', this, function() { this.updateBox(); + this.highlight(); }); objectModel.set('target', newTarget); objectModel.set('endPoint', this.targetPoint); this.paper.trigger('checkexistelements', objectModel, this, false); } else { this.$box.css('visibility', 'hidden'); + this.unhighlight(); } } }, this); @@ -58,13 +63,19 @@ export let EmptyView = joint.dia.LinkView.extend({ if (!this.verticesChanging) { this.verticesChanging = true; this.$box.css('visibility', 'hidden'); - this.paper.once('link:pointerup', function() { + this.unhighlight(); + if (!this.$el.hasClass('edit-disabled')) { + this.paper.once('link:pointerup', function() { + this.verticesChanging = false; + this.$box.css('visibility', 'visible'); + schedule('afterRender', this, function() { + this.updateBox(); + this.highlight(); + }); + }, this) + } else { this.verticesChanging = false; - this.$box.css('visibility', 'visible'); - schedule('afterRender', this, function() { - this.updateBox(); - }); - }, this) + } } }, this); }, @@ -135,6 +146,39 @@ export let EmptyView = joint.dia.LinkView.extend({ } }, + pointerdblclick: function(evt, x, y) { + let readonly = this.paper.options.interactive; + if (!isNone(readonly) && typeof readonly === 'object') { + this.addVertex(x, y); + this.unhighlight(); + this.highlight(); + this.verticesChanging = false + } + }, + + getButtons() { + let readonly = this.paper.options.interactive; + if (!readonly && typeof readonly !== 'object') { + return A([]); + } + + return A([{ + name: 'remove-button', + text: '', + handler: this.removeLink.bind(this), + attrs: { + 'element': { atConnectionRatio: .2 }, + 'circle': { r: 6, fill: '#007aff', stroke: '#007aff', 'stroke-width': 1, 'cursor': 'pointer' }, + 'text': { fill: '#ffffff','font-size': 10, 'text-anchor': 'middle', x: 0, y: 3, 'font-family': 'Icons', visibility: 'visible', 'cursor': 'pointer' }, + } + }]); + }, + + removeLink(e) { + e.stopPropagation(); + this.model.remove(); + }, + /** Update coordinates for FF. */ diff --git a/addon/objects/uml-primitives/links-view/fd-normalized-description-view.js b/addon/objects/uml-primitives/links-view/fd-normalized-description-view.js index 58529a664..f85ac6215 100644 --- a/addon/objects/uml-primitives/links-view/fd-normalized-description-view.js +++ b/addon/objects/uml-primitives/links-view/fd-normalized-description-view.js @@ -40,7 +40,7 @@ export let NormalizedDescriptionView = DescriptionView.extend({ this.model.on('remove', this.removeBox, this); }, - normalizeDescription(description) { + normalizeDescription(description) { let beforeChar = String.fromCharCode(91); let afterChar = String.fromCharCode(93); let normalizedDescription = description.replace(new RegExp(`${'\\'+beforeChar}|${'\\'+afterChar}`, 'g'), ''); @@ -57,7 +57,7 @@ export let NormalizedDescriptionView = DescriptionView.extend({ return normalizedDescription; }, - showNormalizedDescriptionOnInput(element) { + showNormalizedDescriptionOnInput(element) { let descriptionText = element.val(); let description = this.normalizeDescription(descriptionText); element.val(description); diff --git a/addon/styles/components/fd-uml-diagram.less b/addon/styles/components/fd-uml-diagram.less index 86f144baf..0af5b3598 100644 --- a/addon/styles/components/fd-uml-diagram.less +++ b/addon/styles/components/fd-uml-diagram.less @@ -176,7 +176,7 @@ bottom: 0; display: inline-table; font-size: 0; - padding: 5px; + padding: 5px; position: absolute; margin-right: -50%; max-width: 90%; @@ -297,4 +297,30 @@ } } } -} \ No newline at end of file +} + +.joint-link .marker-vertices, +.joint-link .marker-arrowheads, +.joint-link .link-tools { + opacity: 1; +} + +.joint-link.joint-theme-default { + .connection-wrap { + cursor: default; + &:hover { + opacity: 0; + stroke-opacity: 0; + } + } + .tool-remove { + display: none; + } + .marker-vertex, + .marker-arrowhead { + fill: @blue; + &:hover { + fill: @blue; + } + } +} diff --git a/addon/templates/components/fd-uml-diagram-editor.hbs b/addon/templates/components/fd-uml-diagram-editor.hbs index 87cf33f88..babe23c0b 100644 --- a/addon/templates/components/fd-uml-diagram-editor.hbs +++ b/addon/templates/components/fd-uml-diagram-editor.hbs @@ -12,6 +12,9 @@ openEditFormAction=openEditFormAction currentTargetElementIsPointer=currentTargetElementIsPointer readonly=readonly + enableWrapBaseLinks=enableWrapBaseLinks + enableEditLinks=enableEditLinks + disableEditLinks=disableEditLinks }} {{#animated-if (not readonly) use=transition}} diff --git a/tests/integration/components/fd-uml-diagram-test.js b/tests/integration/components/fd-uml-diagram-test.js index 1433a4a95..6d40a7298 100644 --- a/tests/integration/components/fd-uml-diagram-test.js +++ b/tests/integration/components/fd-uml-diagram-test.js @@ -9,7 +9,14 @@ test('it renders', function(assert) { // Set any properties with this.set('myProperty', 'value'); // Handle any actions with this.on('myAction', function(val) { ... }); - this.render(hbs`{{fd-uml-diagram}}`); + + this.set('mockLinkFunction', function() {}); + + this.render(hbs`{{fd-uml-diagram + enableEditLinks = mockLinkFunction + enableWrapBaseLinks = mockLinkFunction + disableEditLinks = mockLinkFunction + }}`); assert.equal(this.$().text().trim(), ''); });