diff --git a/.changeset/quiet-tools-hide.md b/.changeset/quiet-tools-hide.md new file mode 100644 index 0000000000..c67eacb42c --- /dev/null +++ b/.changeset/quiet-tools-hide.md @@ -0,0 +1,5 @@ +--- +"@joint/core": patch +--- + +dia.ToolsView - fix a tool hidden with `hide()` right after `addTools()` reappearing when the update is deferred (e.g. `async: true`) diff --git a/packages/joint-core/src/dia/ToolView.mjs b/packages/joint-core/src/dia/ToolView.mjs index 580454c65a..c9345b85af 100644 --- a/packages/joint-core/src/dia/ToolView.mjs +++ b/packages/joint-core/src/dia/ToolView.mjs @@ -20,6 +20,11 @@ export const ToolView = mvc.View.extend({ this.simulateRelatedView(this.el); // Delegate events in case the ToolView was removed from the DOM and reused. this.delegateEvents(); + // Reset the explicit visibility in case the ToolView was hidden by + // `focusTool()` and removed before `blurTool()` was called (e.g. during + // an arrowhead drag). This must happen synchronously, so that `hide()` + // called right after `addTools()` is not overridden by a deferred update. + this._visibleExplicit = true; return this; }, diff --git a/packages/joint-core/src/dia/ToolsView.mjs b/packages/joint-core/src/dia/ToolsView.mjs index 8f14299a62..288f948e0d 100644 --- a/packages/joint-core/src/dia/ToolsView.mjs +++ b/packages/joint-core/src/dia/ToolsView.mjs @@ -47,7 +47,6 @@ export const ToolsView = mvc.View.extend({ const tools = this.tools; if (!tools) return this; const n = tools.length; - const wasRendered = this.isRendered; for (let i = 0; i < n; i++) { const tool = tools[i]; tool.updateVisibility(); @@ -64,10 +63,6 @@ export const ToolsView = mvc.View.extend({ if (!this.isMounted()) { this.mount(); } - if (!wasRendered) { - // Make sure tools are visible (if they were hidden and the tool removed) - this.blurTool(); - } return this; }, diff --git a/packages/joint-core/test/jointjs/dia/linkTools.js b/packages/joint-core/test/jointjs/dia/linkTools.js index 0ba816e566..a96b0b76f1 100644 --- a/packages/joint-core/test/jointjs/dia/linkTools.js +++ b/packages/joint-core/test/jointjs/dia/linkTools.js @@ -198,6 +198,86 @@ QUnit.module('linkTools', function(hooks) { }); + QUnit.test('a tool hidden right after addTools() stays hidden when the update is deferred', function(assert) { + // https://github.com/clientIO/joint/issues/1445 + paper.freeze(); + const button = new joint.linkTools.Button(); + const remove = new joint.linkTools.Remove(); + const toolsView = new joint.dia.ToolsView({ tools: [button, remove] }); + linkView.addTools(toolsView); + remove.hide(); + paper.unfreeze(); + assert.ok(toolsView.isMounted()); + assert.notEqual(getComputedStyle(button.el).display, 'none'); + assert.ok(button.isVisible()); + assert.equal(getComputedStyle(remove.el).display, 'none'); + assert.notOk(remove.isVisible()); + assert.notOk(remove.isExplicitlyVisible()); + }); + + QUnit.test('a tool hidden right after addTools() stays hidden in an async paper', function(assert) { + // https://github.com/clientIO/joint/issues/1445 + const done = assert.async(); + const asyncPaperEl = document.createElement('div'); + paperEl.parentNode.appendChild(asyncPaperEl); + const asyncPaper = new joint.dia.Paper({ + el: asyncPaperEl, + model: graph, + cellViewNamespace: joint.shapes, + async: true + }); + asyncPaper.once('render:done', () => { + const asyncLinkView = link.findView(asyncPaper); + const button = new joint.linkTools.Button(); + const remove = new joint.linkTools.Remove(); + const toolsView = new joint.dia.ToolsView({ tools: [button, remove] }); + asyncLinkView.addTools(toolsView); + remove.hide(); + asyncPaper.once('render:done', () => { + assert.ok(toolsView.isMounted()); + assert.notEqual(getComputedStyle(button.el).display, 'none'); + assert.equal(getComputedStyle(remove.el).display, 'none'); + assert.notOk(remove.isVisible()); + asyncPaper.remove(); + done(); + }); + }); + }); + + QUnit.test('tools hidden by focusTool() are visible again when the tools view is re-added', function(assert) { + // https://github.com/clientIO/joint/pull/1410 + // e.g. an arrowhead is dragged and the tools are removed on `link:mouseleave` + // before the drag ends (so `blurTool()` is never called) + const arrowhead = new joint.linkTools.TargetArrowhead(); + const remove = new joint.linkTools.Remove(); + const toolsView = new joint.dia.ToolsView({ tools: [arrowhead, remove] }); + linkView.addTools(toolsView); + toolsView.focusTool(arrowhead); + assert.equal(getComputedStyle(remove.el).display, 'none'); + linkView.removeTools(); + linkView.addTools(toolsView); + assert.notEqual(getComputedStyle(arrowhead.el).display, 'none'); + assert.notEqual(getComputedStyle(remove.el).display, 'none'); + assert.ok(remove.isVisible()); + assert.ok(remove.isExplicitlyVisible()); + }); + + QUnit.test('tools hidden by focusTool() are visible again when the tools view is re-added (deferred update)', function(assert) { + // https://github.com/clientIO/joint/pull/1410 + const arrowhead = new joint.linkTools.TargetArrowhead(); + const remove = new joint.linkTools.Remove(); + const toolsView = new joint.dia.ToolsView({ tools: [arrowhead, remove] }); + linkView.addTools(toolsView); + toolsView.focusTool(arrowhead); + linkView.removeTools(); + paper.freeze(); + linkView.addTools(toolsView); + paper.unfreeze(); + assert.notEqual(getComputedStyle(arrowhead.el).display, 'none'); + assert.notEqual(getComputedStyle(remove.el).display, 'none'); + assert.ok(remove.isVisible()); + }); + QUnit.test('show()', function(assert) { paper.freeze(); const remove = new joint.linkTools.Vertices();