parent
4a1cc29a4d
commit
d30574f5dd
|
@ -3,30 +3,37 @@
|
|||
}
|
||||
|
||||
.bjs-breadcrumbs {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 100px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
font-family: var(--bjs-font-family);
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.bjs-breadcrumbs li {
|
||||
display: inline-block;
|
||||
display: inline-flex;
|
||||
color: var(--blue-base-65);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.bjs-breadcrumbs .bjs-drilldown {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.bjs-breadcrumbs li:last-of-type {
|
||||
color: inherit;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.bjs-breadcrumbs li:not(:first-child)::before {
|
||||
.bjs-breadcrumbs li:not(:first-of-type)::before {
|
||||
content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="17" height="17" viewBox="0 0 24 24"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z" /><path d="M0 0h24v24H0z" fill="none" /></svg>');
|
||||
height: 16px;
|
||||
padding: 0 8px;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.bjs-breadcrumbs .bpmnjs-crumb {
|
||||
.bjs-breadcrumbs .bjs-crumb {
|
||||
display: inline-block;
|
||||
max-width: 200px;
|
||||
overflow: hidden;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
var defaultPosition = { x: 100, y: 50 };
|
||||
|
||||
export default function SubprocessCentering(eventBus, canvas) {
|
||||
var currentPlane = 'base';
|
||||
var positionMap = {};
|
||||
|
@ -12,7 +14,25 @@ export default function SubprocessCentering(eventBus, canvas) {
|
|||
};
|
||||
|
||||
var planeId = event.plane.name;
|
||||
var storedViewbox = positionMap[planeId] || { x: 0, y: 0, zoom: 1 };
|
||||
var storedViewbox = positionMap[planeId];
|
||||
|
||||
if (!storedViewbox) {
|
||||
if (!event.plane.rootElement.isImplicit) {
|
||||
storedViewbox = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
zoom: 1
|
||||
};
|
||||
}
|
||||
else {
|
||||
var currentBoundingBox = canvas.getActiveLayer().getBBox();
|
||||
storedViewbox = {
|
||||
x: currentBoundingBox.x - defaultPosition.x,
|
||||
y: currentBoundingBox.y - defaultPosition.y,
|
||||
zoom: 1
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var dx = (currentViewbox.x - storedViewbox.x) * currentViewbox.scale,
|
||||
dy = (currentViewbox.y - storedViewbox.y) * currentViewbox.scale;
|
||||
|
|
|
@ -4,19 +4,25 @@ import { escapeHTML } from 'diagram-js/lib/util/EscapeUtil';
|
|||
import { getBusinessObject, is } from '../../util/ModelUtil';
|
||||
|
||||
var ARROW_DOWN_SVG = '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M4.81801948,3.50735931 L10.4996894,9.1896894 L10.5,4 L12,4 L12,12 L4,12 L4,10.5 L9.6896894,10.4996894 L3.75735931,4.56801948 C3.46446609,4.27512627 3.46446609,3.80025253 3.75735931,3.50735931 C4.05025253,3.21446609 4.52512627,3.21446609 4.81801948,3.50735931 Z"/></svg>';
|
||||
var ARROW_UP_SVG = '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M11.1819805,12.4926407 L5.5003106,6.8103106 L5.5,12 L4,12 L4,4 L12,4 L12,5.5 L6.3103106,5.5003106 L12.2426407,11.4319805 C12.5355339,11.7248737 12.5355339,12.1997475 12.2426407,12.4926407 C11.9497475,12.7855339 11.4748737,12.7855339 11.1819805,12.4926407 Z"/></svg>';
|
||||
|
||||
export default function SubprocessOverlays(eventBus, elementRegistry, overlays, canvas) {
|
||||
var breadcrumbs = domify('<ul class="bjs-breadcrumbs djs-element-hidden"></ul>');
|
||||
var container = canvas.getContainer();
|
||||
container.appendChild(breadcrumbs);
|
||||
|
||||
function updateBreadcrumbs(plane) {
|
||||
var subProcess = elementRegistry.get(plane.name);
|
||||
function createBreadcrumbs(subProcess) {
|
||||
var breadcrumbs = domify('<ul class="bjs-breadcrumbs"></ul>');
|
||||
var drillUp = domify('<button class="bjs-drilldown">' + ARROW_UP_SVG + '</button>');
|
||||
drillUp.addEventListener('click', function() {
|
||||
var plane = canvas.findPlane(getBusinessObject(subProcess).id);
|
||||
canvas.setActivePlane(plane);
|
||||
});
|
||||
|
||||
breadcrumbs.appendChild(drillUp);
|
||||
|
||||
var parents = getParentChain(subProcess);
|
||||
|
||||
var path = parents.map(function(el) {
|
||||
var title = escapeHTML(el.name) || el.id;
|
||||
var link = domify('<li><span class="bpmnjs-crumb"><a title="' + title + '">' + title + '</a></span></li>');
|
||||
var link = domify('<li><span class="bjs-crumb"><a title="' + title + '">' + title + '</a></span></li>');
|
||||
|
||||
link.addEventListener('click', function() {
|
||||
if (canvas.getPlane(el.id)) {
|
||||
|
@ -30,26 +36,20 @@ export default function SubprocessOverlays(eventBus, elementRegistry, overlays,
|
|||
return link;
|
||||
});
|
||||
|
||||
breadcrumbs.innerHTML = '';
|
||||
|
||||
if (path.length > 1) {
|
||||
breadcrumbs.classList.remove('djs-element-hidden');
|
||||
} else {
|
||||
breadcrumbs.classList.add('djs-element-hidden');
|
||||
}
|
||||
|
||||
path.forEach(function(el) {
|
||||
breadcrumbs.appendChild(el);
|
||||
});
|
||||
|
||||
overlays.add(subProcess, {
|
||||
position: {
|
||||
top: -30,
|
||||
left: -10
|
||||
},
|
||||
html: breadcrumbs
|
||||
});
|
||||
}
|
||||
|
||||
eventBus.on('plane.set', function(event) {
|
||||
var plane = event.plane;
|
||||
|
||||
updateBreadcrumbs(plane);
|
||||
});
|
||||
|
||||
var createOverlay = function(element) {
|
||||
var createDrilldown = function(element) {
|
||||
var html = domify('<button class="bjs-drilldown">' + ARROW_DOWN_SVG + '</button>');
|
||||
|
||||
html.addEventListener('click', function() {
|
||||
|
@ -70,7 +70,11 @@ export default function SubprocessOverlays(eventBus, elementRegistry, overlays,
|
|||
if (is(element, 'bpmn:SubProcess')
|
||||
&& element.collapsed
|
||||
&& canvas.getPlane(element.id)) {
|
||||
createOverlay(element);
|
||||
createDrilldown(element);
|
||||
}
|
||||
|
||||
if (is(element, 'bpmn:SubProcess') && element.isSecondary) {
|
||||
createBreadcrumbs(element);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
|
@ -10,6 +10,8 @@ import {
|
|||
} from '../util/LabelUtil';
|
||||
|
||||
import {
|
||||
asBounds,
|
||||
asTRBL,
|
||||
getMid
|
||||
} from 'diagram-js/lib/layout/LayoutUtil';
|
||||
|
||||
|
@ -48,6 +50,32 @@ function getWaypoints(di, source, target) {
|
|||
});
|
||||
}
|
||||
|
||||
var PLANE_PADDING = 50;
|
||||
|
||||
function getPlaneBounds(plane) {
|
||||
var planeTrbl = {
|
||||
top: Infinity,
|
||||
right: -Infinity,
|
||||
bottom: -Infinity,
|
||||
left: Infinity
|
||||
};
|
||||
|
||||
plane.planeElement.forEach(function(element) {
|
||||
if (!element.bounds) {
|
||||
return;
|
||||
}
|
||||
|
||||
var trbl = asTRBL(element.bounds);
|
||||
|
||||
planeTrbl.top = Math.min(trbl.top, planeTrbl.top);
|
||||
planeTrbl.left = Math.min(trbl.left, planeTrbl.left);
|
||||
planeTrbl.right = Math.max(trbl.right, planeTrbl.right);
|
||||
planeTrbl.bottom = Math.max(trbl.bottom, planeTrbl.bottom);
|
||||
});
|
||||
|
||||
return asBounds(planeTrbl);
|
||||
}
|
||||
|
||||
function notYetDrawn(translate, semantic, refSemantic, property) {
|
||||
return new Error(translate('element {element} referenced by {referenced}#{property} not yet drawn', {
|
||||
element: elementToString(refSemantic),
|
||||
|
@ -105,14 +133,36 @@ BpmnImporter.prototype.add = function(semantic, di, parentElement) {
|
|||
// invisible root element (process or collaboration)
|
||||
if (is(di, 'bpmndi:BPMNPlane')) {
|
||||
|
||||
// add a virtual element (not being drawn)
|
||||
element = this._elementFactory.createRoot(elementData(semantic, di));
|
||||
|
||||
if (is(semantic, 'bpmn:SubProcess')) {
|
||||
element.id = element.id + '_plane';
|
||||
}
|
||||
var plane = this._canvas.createPlane(semantic.id, element);
|
||||
|
||||
this._canvas.createPlane(semantic.id, element);
|
||||
// Get size of expanded element
|
||||
var bounds = getPlaneBounds(di);
|
||||
|
||||
var primary = this._elementRegistry.get(semantic.id);
|
||||
element = this._elementFactory.createShape(elementData(semantic, di, {
|
||||
collapsed: false,
|
||||
hidden: false,
|
||||
x: bounds.x - PLANE_PADDING,
|
||||
y: bounds.y - PLANE_PADDING,
|
||||
width: bounds.width + PLANE_PADDING * 2,
|
||||
height: bounds.height + PLANE_PADDING * 2,
|
||||
isFrame: true
|
||||
}));
|
||||
|
||||
element.id = element.id + '_secondary';
|
||||
element.isSecondary = true;
|
||||
element.primaryShape = primary;
|
||||
|
||||
this._canvas.addShape(element, plane.rootElement);
|
||||
}
|
||||
else {
|
||||
|
||||
// add a virtual element (not being drawn)
|
||||
element = this._elementFactory.createRoot(elementData(semantic, di));
|
||||
|
||||
this._canvas.createPlane(semantic.id, element);
|
||||
}
|
||||
}
|
||||
|
||||
// SHAPE
|
||||
|
@ -123,7 +173,7 @@ BpmnImporter.prototype.add = function(semantic, di, parentElement) {
|
|||
|
||||
hidden = parentElement && (parentElement.hidden || parentElement.collapsed);
|
||||
|
||||
var bounds = di.bounds;
|
||||
bounds = di.bounds;
|
||||
|
||||
element = this._elementFactory.createShape(elementData(semantic, di, {
|
||||
collapsed: collapsed,
|
||||
|
|
|
@ -256,7 +256,12 @@ export function createViewer(container, viewerInstance, xml, diagramId) {
|
|||
|
||||
clearBpmnJS();
|
||||
|
||||
var viewer = new viewerInstance({ container: container });
|
||||
var viewer = new viewerInstance({
|
||||
container: container,
|
||||
canvas: {
|
||||
deferUpdate: false
|
||||
}
|
||||
});
|
||||
|
||||
setBpmnJS(viewer);
|
||||
|
||||
|
|
|
@ -40,6 +40,9 @@ describe('Modeler', function() {
|
|||
container: container,
|
||||
keyboard: {
|
||||
bindTo: document
|
||||
},
|
||||
canvas: {
|
||||
deferUpdate: false
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -715,18 +718,18 @@ describe('Modeler', function() {
|
|||
|
||||
return createModeler(xml).then(function() {
|
||||
var drilldown = container.querySelector('.bjs-drilldown');
|
||||
var breadcrumbs = container.querySelector('.bjs-breadcrumbs');
|
||||
var visibleBreadcrumbs = container.querySelector('.djs-overlay:not([style*="display: none"]) .bjs-breadcrumbs');
|
||||
|
||||
// assume
|
||||
expect(drilldown).to.exist;
|
||||
expect(breadcrumbs).to.exist;
|
||||
expect(breadcrumbs.classList.contains('djs-element-hidden')).to.be.true;
|
||||
expect(visibleBreadcrumbs).to.not.exist;
|
||||
|
||||
// when
|
||||
drilldown.click();
|
||||
|
||||
// then
|
||||
expect(breadcrumbs.classList.contains('djs-element-hidden')).to.be.false;
|
||||
visibleBreadcrumbs = container.querySelector('.djs-overlay:not([style*="display: none"]) .bjs-breadcrumbs');
|
||||
expect(visibleBreadcrumbs).to.exist;
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -378,18 +378,18 @@ describe('Viewer', function() {
|
|||
|
||||
return createViewer(container, Viewer, xml).then(function() {
|
||||
var drilldown = container.querySelector('.bjs-drilldown');
|
||||
var breadcrumbs = container.querySelector('.bjs-breadcrumbs');
|
||||
var visibleBreadcrumbs = container.querySelector('.djs-overlay:not([style*="display: none"]) .bjs-breadcrumbs');
|
||||
|
||||
// assume
|
||||
expect(drilldown).to.exist;
|
||||
expect(breadcrumbs).to.exist;
|
||||
expect(breadcrumbs.classList.contains('djs-element-hidden')).to.be.true;
|
||||
expect(visibleBreadcrumbs).to.not.exist;
|
||||
|
||||
// when
|
||||
drilldown.click();
|
||||
|
||||
// then
|
||||
expect(breadcrumbs.classList.contains('djs-element-hidden')).to.be.false;
|
||||
visibleBreadcrumbs = container.querySelector('.djs-overlay:not([style*="display: none"]) .bjs-breadcrumbs');
|
||||
expect(visibleBreadcrumbs).to.exist;
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -64,64 +64,69 @@ describe('features - subprocess-navigation', function() {
|
|||
it('should not show breadcrumbs in root view', inject(function(canvas) {
|
||||
|
||||
// given
|
||||
var breadcrumbs = canvas.getContainer().querySelector('.bjs-breadcrumbs');
|
||||
var breadcrumbs = getBreadcrumbs(canvas);
|
||||
|
||||
// then
|
||||
expect(breadcrumbs.classList.contains('djs-element-hidden')).to.be.true;
|
||||
expect(breadcrumbs).to.not.exist;
|
||||
}));
|
||||
|
||||
|
||||
it('should show breadcrumbs in subprocess view', inject(function(canvas) {
|
||||
|
||||
// given
|
||||
var breadcrumbs = canvas.getContainer().querySelector('.bjs-breadcrumbs');
|
||||
|
||||
// when
|
||||
canvas.setActivePlane('collapsedProcess');
|
||||
|
||||
// then
|
||||
expect(breadcrumbs.classList.contains('djs-element-hidden')).to.be.false;
|
||||
expect(getBreadcrumbs(canvas)).to.exist;
|
||||
}));
|
||||
|
||||
|
||||
it('should show execution tree', inject(function(canvas) {
|
||||
|
||||
// given
|
||||
var breadcrumbs = canvas.getContainer().querySelector('.bjs-breadcrumbs');
|
||||
|
||||
// when
|
||||
canvas.setActivePlane('collapsedProcess_2');
|
||||
|
||||
// then
|
||||
expectBreadcrumbs(breadcrumbs, ['Root', 'Collapsed Process', 'Expanded Process', 'Collapsed Process 2']);
|
||||
expectBreadcrumbs(getBreadcrumbs(canvas), ['Root', 'Collapsed Process', 'Expanded Process', 'Collapsed Process 2']);
|
||||
}));
|
||||
|
||||
|
||||
it('should switch to process plane on click', inject(function(canvas) {
|
||||
|
||||
// given
|
||||
var breadcrumbs = canvas.getContainer().querySelector('.bjs-breadcrumbs');
|
||||
canvas.setActivePlane('collapsedProcess_2');
|
||||
|
||||
// when
|
||||
breadcrumbs.children[1].click();
|
||||
getBreadcrumbs(canvas).children[2].click();
|
||||
|
||||
// then
|
||||
expectBreadcrumbs(breadcrumbs, ['Root', 'Collapsed Process']);
|
||||
expectBreadcrumbs(getBreadcrumbs(canvas), ['Root', 'Collapsed Process']);
|
||||
}));
|
||||
|
||||
|
||||
it('should switch to containing process plane on embedded click', inject(function(canvas) {
|
||||
|
||||
// given
|
||||
var breadcrumbs = canvas.getContainer().querySelector('.bjs-breadcrumbs');
|
||||
canvas.setActivePlane('collapsedProcess_2');
|
||||
|
||||
// when
|
||||
breadcrumbs.children[2].click();
|
||||
getBreadcrumbs(canvas).children[3].click();
|
||||
|
||||
// then
|
||||
expectBreadcrumbs(breadcrumbs, ['Root', 'Collapsed Process']);
|
||||
expectBreadcrumbs(getBreadcrumbs(canvas), ['Root', 'Collapsed Process']);
|
||||
}));
|
||||
|
||||
|
||||
it('should switch to containing process plane on drillup icon', inject(function(canvas) {
|
||||
|
||||
// given
|
||||
canvas.setActivePlane('collapsedProcess_2');
|
||||
|
||||
// when
|
||||
getBreadcrumbs(canvas).querySelector('.bjs-drilldown').click();
|
||||
|
||||
// then
|
||||
expectBreadcrumbs(getBreadcrumbs(canvas), ['Root', 'Collapsed Process']);
|
||||
}));
|
||||
|
||||
});
|
||||
|
@ -201,10 +206,19 @@ describe('features - subprocess-navigation', function() {
|
|||
|
||||
// helpers
|
||||
|
||||
function getBreadcrumbs(canvas) {
|
||||
return canvas.getContainer().querySelector('.djs-overlay:not([style*="display: none"]) .bjs-breadcrumbs');
|
||||
}
|
||||
|
||||
function expectBreadcrumbs(breadcrumbs, expected) {
|
||||
var crumbs = Array.from(breadcrumbs.children).map(function(element) {
|
||||
return element.innerText;
|
||||
});
|
||||
var crumbs = Array.from(breadcrumbs.children)
|
||||
.filter(function(child) {
|
||||
return !!child.querySelector('.bjs-crumb');
|
||||
})
|
||||
.map(function(element) {
|
||||
return element.innerText;
|
||||
});
|
||||
|
||||
expect(crumbs).to.eql(expected);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -724,7 +724,7 @@ describe('import - Importer', function() {
|
|||
expect(warnings).to.have.length(0);
|
||||
|
||||
expect(diagram.get('elementRegistry').get('Subprocess')).to.exist;
|
||||
expect(diagram.get('elementRegistry').get('Subprocess_plane')).to.exist;
|
||||
expect(diagram.get('elementRegistry').get('Subprocess_secondary')).to.exist;
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue