maxGraph/javascript/examples/grapheditor/www/js/Graph.js

1648 lines
43 KiB
JavaScript
Raw Normal View History

2012-05-21 20:32:26 +00:00
/**
2014-02-19 14:19:38 +00:00
* $Id: Graph.js,v 1.40 2014/02/17 13:46:29 gaudenz Exp $
2012-05-21 20:32:26 +00:00
* Copyright (c) 2006-2012, JGraph Ltd
*/
/**
* Constructs a new graph instance. Note that the constructor does not take a
* container because the graph instance is needed for creating the UI, which
* in turn will create the container for the graph. Hence, the container is
* assigned later in EditorUi.
*/
Graph = function(container, model, renderHint, stylesheet)
{
mxGraph.call(this, container, model, renderHint, stylesheet);
this.setConnectable(true);
this.setDropEnabled(true);
this.setPanning(true);
2013-06-28 19:07:06 +00:00
this.setTooltips(true);
2012-05-21 20:32:26 +00:00
this.setAllowLoops(true);
this.allowAutoPanning = true;
2013-05-23 16:14:48 +00:00
this.resetEdgesOnConnect = false;
this.constrainChildren = false;
2013-06-28 19:07:06 +00:00
2013-05-23 16:14:48 +00:00
// Enables cloning of connection sources by default
2012-05-21 20:32:26 +00:00
this.connectionHandler.setCreateTarget(true);
2012-12-18 13:09:38 +00:00
2014-05-12 09:58:11 +00:00
// Disables built-in connection starts except shift is pressed when hovering the cell
this.connectionHandler.isValidSource = function(cell, me)
2012-12-18 13:09:38 +00:00
{
2014-05-12 09:58:11 +00:00
return mxConnectionHandler.prototype.isValidSource.apply(this, arguments) &&
((urlParams['connect'] != '2' && urlParams['connect'] != null) ||
mxEvent.isShiftDown(me.getEvent()));
2012-12-18 13:09:38 +00:00
};
2012-05-21 20:32:26 +00:00
// Sets the style to be used when an elbow edge is double clicked
this.alternateEdgeStyle = 'vertical';
2012-06-01 10:53:50 +00:00
if (stylesheet == null)
{
this.loadStylesheet();
}
2012-05-21 20:32:26 +00:00
// Creates rubberband selection
var rubberband = new mxRubberband(this);
this.getRubberband = function()
{
return rubberband;
};
2014-05-05 08:30:00 +00:00
// Workaround for Firefox where first mouse down is received
// after tap and hold if scrollbars are visible, which means
// start rubberband immediately if no cell is under mouse.
var isForceRubberBandEvent = rubberband.isForceRubberbandEvent;
rubberband.isForceRubberbandEvent = function(me)
{
return isForceRubberBandEvent.apply(this, arguments) ||
(mxUtils.hasScrollbars(this.graph.container) && mxClient.IS_FF &&
mxClient.IS_WIN && me.getState() == null && mxEvent.isTouchEvent(me.getEvent()));
};
2012-07-31 14:06:36 +00:00
// Shows hand cursor while panning
this.panningHandler.addListener(mxEvent.PAN_START, mxUtils.bind(this, function()
{
2014-04-01 11:30:48 +00:00
this.container.style.cursor = 'move';
2012-07-31 14:06:36 +00:00
}));
2013-06-28 19:07:06 +00:00
2012-07-31 14:06:36 +00:00
this.panningHandler.addListener(mxEvent.PAN_END, mxUtils.bind(this, function()
{
this.container.style.cursor = 'default';
}));
2014-02-19 14:19:38 +00:00
2014-05-05 08:30:00 +00:00
// Forces panning for middle and right mouse buttons
2014-04-01 11:30:48 +00:00
var panningHandlerIsForcePanningEvent = this.panningHandler.isForcePanningEvent;
2014-02-19 14:19:38 +00:00
this.panningHandler.isForcePanningEvent = function(me)
{
2014-05-05 08:30:00 +00:00
return panningHandlerIsForcePanningEvent.apply(this, arguments) ||
(mxEvent.isMouseEvent(me.getEvent()) && (mxEvent.isRightMouseButton(me.getEvent()) ||
mxEvent.isMiddleMouseButton(me.getEvent())));
2014-02-19 14:19:38 +00:00
};
2012-07-31 14:06:36 +00:00
2013-06-28 19:07:06 +00:00
this.popupMenuHandler.autoExpand = true;
this.popupMenuHandler.isSelectOnPopup = function(me)
{
return mxEvent.isMouseEvent(me.getEvent());
};
2012-05-21 20:32:26 +00:00
// Adds support for HTML labels via style. Note: Currently, only the Java
// backend supports HTML labels but CSS support is limited to the following:
// http://docs.oracle.com/javase/6/docs/api/index.html?javax/swing/text/html/CSS.html
this.isHtmlLabel = function(cell)
{
var state = this.view.getState(cell);
var style = (state != null) ? state.style : this.getCellStyle(cell);
2014-05-15 19:58:36 +00:00
return style['html'] == '1' || style['whiteSpace'] == 'wrap';
2013-05-23 16:14:48 +00:00
};
// HTML entities are displayed as plain text in wrapped plain text labels
this.cellRenderer.getLabelValue = function(state)
{
var result = mxCellRenderer.prototype.getLabelValue.apply(this, arguments);
2013-12-20 16:51:26 +00:00
if (state.view.graph.isHtmlLabel(state.cell))
2013-05-23 16:14:48 +00:00
{
2013-12-20 16:51:26 +00:00
if (state.style['html'] != 1)
{
result = mxUtils.htmlEntities(result, false);
}
2014-05-15 19:58:36 +00:00
}
return result;
};
2013-12-20 16:51:26 +00:00
2014-05-15 19:58:36 +00:00
// Enables links if graph is "disabled" (ie. read-only)
var click = this.click;
this.click = function(me)
{
if (!this.isEnabled())
{
var cell = me.getCell();
2013-12-20 16:51:26 +00:00
2014-05-15 19:58:36 +00:00
if (cell != null)
2013-12-20 16:51:26 +00:00
{
2014-05-15 19:58:36 +00:00
var link = this.getLinkForCell(cell);
if (link != null)
{
window.open(link);
}
2013-12-20 16:51:26 +00:00
}
2013-05-23 16:14:48 +00:00
}
2014-05-15 19:58:36 +00:00
else
{
return click.apply(this, arguments);
}
};
var getCursorForCell = this.getCursorForCell;
this.getCursorForCell = function(cell)
{
if (!this.isEnabled())
{
var link = this.getLinkForCell(cell);
if (link != null)
{
return 'pointer';
}
}
else
{
return getCursorForCell.apply(this, arguments);
}
};
// Allows all events through
this.isEventSourceIgnored2 = function(evtName, me)
{
return false;
2012-05-21 20:32:26 +00:00
};
// Unlocks all cells
this.isCellLocked = function(cell)
{
return false;
};
2013-06-28 19:07:06 +00:00
// Tap and hold on background starts rubberband for multiple selected
// cells the cell associated with the event is deselected
this.addListener(mxEvent.TAP_AND_HOLD, mxUtils.bind(this, function(sender, evt)
2012-05-21 20:32:26 +00:00
{
2014-05-12 09:58:11 +00:00
if (!mxEvent.isMultiTouchEvent(evt))
2012-05-21 20:32:26 +00:00
{
2014-05-12 09:58:11 +00:00
var me = evt.getProperty('event');
var cell = evt.getProperty('cell');
if (cell == null)
{
var pt = mxUtils.convertPoint(this.container,
mxEvent.getClientX(me), mxEvent.getClientY(me));
rubberband.start(pt.x, pt.y);
}
else if (this.getSelectionCount() > 1 && this.isCellSelected(cell))
{
this.removeSelectionCell(cell);
}
// Blocks further processing of the event
evt.consume();
2012-05-21 20:32:26 +00:00
}
2013-06-28 19:07:06 +00:00
}));
2012-05-21 20:32:26 +00:00
2013-05-23 16:14:48 +00:00
// On connect the target is selected and we clone the cell of the preview edge for insert
this.connectionHandler.selectCells = function(edge, target)
{
this.graph.setSelectionCell(target || edge);
};
// Shows connection points only if cell not selected
this.connectionHandler.constraintHandler.isStateIgnored = function(state, source)
{
return source && state.view.graph.isCellSelected(state.cell);
};
// Updates constraint handler if the selection changes
this.selectionModel.addListener(mxEvent.CHANGE, mxUtils.bind(this, function()
{
var ch = this.connectionHandler.constraintHandler;
if (ch.currentFocus != null && ch.isStateIgnored(ch.currentFocus, true))
{
ch.currentFocus = null;
ch.constraints = null;
ch.destroyIcons();
}
ch.destroyFocusHighlight();
}));
2012-05-21 20:32:26 +00:00
if (touchStyle)
{
this.initTouch();
}
};
// Graph inherits from mxGraph
mxUtils.extend(Graph, mxGraph);
2012-07-02 11:07:11 +00:00
/**
* Allows to all values in fit.
*/
Graph.prototype.minFitScale = null;
/**
* Allows to all values in fit.
*/
Graph.prototype.maxFitScale = null;
2012-05-21 20:32:26 +00:00
/**
* Loads the stylesheet for this graph.
*/
Graph.prototype.loadStylesheet = function()
{
var node = mxUtils.load(STYLE_PATH + '/default.xml').getDocumentElement();
var dec = new mxCodec(node.ownerDocument);
dec.decode(node, this.getStylesheet());
};
/**
* Inverts the elbow edge style without removing existing styles.
*/
Graph.prototype.flipEdge = function(edge)
{
if (edge != null)
{
var state = this.view.getState(edge);
var style = (state != null) ? state.style : this.getCellStyle(edge);
if (style != null)
{
var elbow = mxUtils.getValue(style, mxConstants.STYLE_ELBOW,
mxConstants.ELBOW_HORIZONTAL);
var value = (elbow == mxConstants.ELBOW_HORIZONTAL) ?
mxConstants.ELBOW_VERTICAL : mxConstants.ELBOW_HORIZONTAL;
this.setCellStyles(mxConstants.STYLE_ELBOW, value, [edge]);
}
}
};
2013-05-23 16:14:48 +00:00
/**
* Sets the default edge for future connections.
*/
Graph.prototype.setDefaultEdge = function(cell)
{
if (cell != null && this.getModel().isEdge(cell))
{
// Take a snapshot of the cell at the moment of calling
var proto = this.getModel().cloneCell(cell);
// Delete existing points
if (proto.geometry != null)
{
proto.geometry.points = null;
}
// Delete entry-/exitXY styles
var style = proto.getStyle();
style = mxUtils.setStyle(style, mxConstants.STYLE_ENTRY_X, null);
style = mxUtils.setStyle(style, mxConstants.STYLE_ENTRY_Y, null);
style = mxUtils.setStyle(style, mxConstants.STYLE_EXIT_X, null);
style = mxUtils.setStyle(style, mxConstants.STYLE_EXIT_Y, null);
proto.setStyle(style);
// Uses edge template for connect preview
this.connectionHandler.createEdgeState = function(me)
{
return this.graph.view.createState(proto);
};
// Creates new connections from edge template
this.connectionHandler.factoryMethod = function()
{
return this.graph.cloneCells([proto])[0];
};
}
};
2012-05-21 20:32:26 +00:00
/**
* Disables folding for non-swimlanes.
*/
Graph.prototype.isCellFoldable = function(cell)
{
2013-11-18 15:18:56 +00:00
var state = this.view.getState(cell);
var style = (state != null) ? state.style : this.getCellStyle(cell);
return this.foldingEnabled && this.isContainer(cell) && style['collapsible'] != '0';
2012-05-21 20:32:26 +00:00
};
/**
* Disables drill-down for non-swimlanes.
*/
Graph.prototype.isValidRoot = function(cell)
{
2013-09-19 07:24:45 +00:00
return this.isContainer(cell);
};
/**
* Disables drill-down for non-swimlanes.
*/
Graph.prototype.isValidDropTarget = function(cell)
{
return this.isContainer(cell) || mxGraph.prototype.isValidDropTarget.apply(this, arguments);
};
/**
* Disables drill-down for non-swimlanes.
*/
Graph.prototype.isContainer = function(cell)
{
if (this.isSwimlane(cell))
{
return true;
}
else
{
var state = this.view.getState(cell);
var style = (state != null) ? state.style : this.getCellStyle(cell);
return style['container'] == '1';
}
2012-05-21 20:32:26 +00:00
};
/**
* Overrides createGroupCell to set the group style for new groups to 'group'.
*/
Graph.prototype.createGroupCell = function()
{
var group = mxGraph.prototype.createGroupCell.apply(this, arguments);
group.setStyle('group');
return group;
};
/**
2014-05-12 09:58:11 +00:00
* Overrides tooltips to show custom tooltip or metadata.
2012-05-21 20:32:26 +00:00
*/
Graph.prototype.getTooltipForCell = function(cell)
{
var tip = '';
2014-05-12 09:58:11 +00:00
if (mxUtils.isNode(cell.value))
2012-05-21 20:32:26 +00:00
{
2014-05-12 09:58:11 +00:00
var tmp = cell.value.getAttribute('tooltip');
2012-05-21 20:32:26 +00:00
2014-05-12 09:58:11 +00:00
if (tmp != null)
2012-05-21 20:32:26 +00:00
{
2014-05-12 09:58:11 +00:00
tip = tmp;
}
else
2012-05-21 20:32:26 +00:00
{
2014-05-15 19:58:36 +00:00
var ignored = ['label', 'tooltip'];
2014-05-12 09:58:11 +00:00
var attrs = cell.value.attributes;
2014-05-15 19:58:36 +00:00
// Hides links in edit mode
if (this.isEnabled())
{
ignored.push('link');
}
2014-05-12 09:58:11 +00:00
for (var i = 0; i < attrs.length; i++)
2012-05-21 20:32:26 +00:00
{
2014-05-12 09:58:11 +00:00
if (mxUtils.indexOf(ignored, attrs[i].nodeName) < 0 && attrs[i].nodeValue.length > 0)
{
var key = attrs[i].nodeName.substring(0, 1).toUpperCase() + attrs[i].nodeName.substring(1);
tip += key + ': ' + attrs[i].nodeValue + '\n';
}
2012-05-21 20:32:26 +00:00
}
2014-05-12 09:58:11 +00:00
if (tip.length > 0)
2013-07-12 07:09:46 +00:00
{
2014-05-12 09:58:11 +00:00
tip = tip.substring(0, tip.length - 1);
2013-07-12 07:09:46 +00:00
}
}
}
2012-05-21 20:32:26 +00:00
return tip;
};
2012-07-31 14:06:36 +00:00
/**
* Returns the label for the given cell.
*/
Graph.prototype.convertValueToString = function(cell)
{
2012-08-26 10:10:08 +00:00
if (cell.value != null && typeof(cell.value) == 'object')
2012-07-31 14:06:36 +00:00
{
return cell.value.getAttribute('label');
}
return mxGraph.prototype.convertValueToString.apply(this, arguments);
};
2014-01-31 14:27:56 +00:00
/**
* Removes all illegal control characters with ASCII code <32 except TAB, LF
* and CR.
*/
Graph.prototype.zapGremlins = function(text)
{
var checked = [];
for (var i = 0; i < text.length; i++)
{
var code = text.charCodeAt(i);
// Removes all control chars except TAB, LF and CR
if (code >= 32 || code == 9 || code == 10 || code == 13)
{
checked.push(text.charAt(i));
}
}
return checked.join('');
};
2012-07-31 14:06:36 +00:00
/**
* Handles label changes for XML user objects.
*/
Graph.prototype.cellLabelChanged = function(cell, value, autoSize)
{
2014-01-31 14:27:56 +00:00
// Removes all illegal control characters in user input
value = this.zapGremlins(value);
2012-08-26 10:10:08 +00:00
if (cell.value != null && typeof(cell.value) == 'object')
2012-07-31 14:06:36 +00:00
{
var tmp = cell.value.cloneNode(true);
tmp.setAttribute('label', value);
value = tmp;
}
mxGraph.prototype.cellLabelChanged.apply(this, arguments);
};
/**
* Sets the link for the given cell.
*/
Graph.prototype.setLinkForCell = function(cell, link)
2014-05-12 09:58:11 +00:00
{
this.setAttributeForCell(cell, 'link', link);
};
/**
* Sets the link for the given cell.
*/
Graph.prototype.setTooltipForCell = function(cell, link)
{
this.setAttributeForCell(cell, 'tooltip', link);
};
/**
* Sets the link for the given cell.
*/
Graph.prototype.setAttributeForCell = function(cell, attributeName, attributeValue)
2012-07-31 14:06:36 +00:00
{
var value = null;
2012-08-26 10:10:08 +00:00
if (cell.value != null && typeof(cell.value) == 'object')
2012-07-31 14:06:36 +00:00
{
value = cell.value.cloneNode(true);
}
else
{
var doc = mxUtils.createXmlDocument();
value = doc.createElement('UserObject');
value.setAttribute('label', cell.value);
}
2014-05-12 09:58:11 +00:00
if (attributeValue != null && attributeValue.length > 0)
2012-07-31 14:06:36 +00:00
{
2014-05-12 09:58:11 +00:00
value.setAttribute(attributeName, attributeValue);
2012-07-31 14:06:36 +00:00
}
else
{
2014-05-12 09:58:11 +00:00
value.removeAttribute(attributeName);
2012-07-31 14:06:36 +00:00
}
this.model.setValue(cell, value);
};
/**
* Returns the link for the given cell.
*/
Graph.prototype.getLinkForCell = function(cell)
{
2012-08-26 10:10:08 +00:00
if (cell.value != null && typeof(cell.value) == 'object')
2012-07-31 14:06:36 +00:00
{
return cell.value.getAttribute('link');
}
return null;
};
2014-04-01 11:30:48 +00:00
/**
* Function: alignCells
*
* Aligns the given cells vertically or horizontally according to the given
* alignment using the optional parameter as the coordinate.
*
* Parameters:
*
* horizontal - Boolean that specifies the direction of the distribution.
* cells - Optional array of <mxCells> to be distributed. Edges are ignored.
*/
Graph.prototype.distributeCells = function(horizontal, cells)
{
if (cells == null)
{
cells = this.getSelectionCells();
}
if (cells != null && cells.length > 1)
{
var vertices = [];
var total = 0;
for (var i = 0; i < cells.length; i++)
{
if (this.getModel().isVertex(cells[i]))
{
var geo = this.getCellGeometry(cells[i]);
if (geo != null)
{
total += (horizontal) ? geo.width : geo.height;
vertices.push(cells[i]);
}
}
}
if (vertices.length > 0)
{
var bounds = this.getBoundingBoxFromGeometry(vertices);
var dt = Math.max(0, (((horizontal) ? bounds.width : bounds.height) - total) /
(vertices.length - 1));
var v0 = (horizontal) ? bounds.x : bounds.y;
this.getModel().beginUpdate();
try
{
for (var i = 0; i < vertices.length; i++)
{
var geo = this.getCellGeometry(vertices[i]);
if (geo != null)
{
geo = geo.clone();
if (horizontal)
{
geo.x = v0;
v0 += geo.width + dt;
}
else
{
geo.y = v0;
v0 += geo.height + dt;
}
this.getModel().setGeometry(vertices[i], geo);
}
}
cells = vertices;
}
finally
{
this.getModel().endUpdate();
}
}
}
return cells;
};
2012-05-21 20:32:26 +00:00
/**
* Customized graph for touch devices.
*/
Graph.prototype.initTouch = function()
{
// Disables new connections via "hotspot"
this.connectionHandler.marker.isEnabled = function()
{
return this.graph.connectionHandler.first != null;
};
// Hides menu when editing starts
this.addListener(mxEvent.START_EDITING, function(sender, evt)
{
2013-06-28 19:07:06 +00:00
this.popupMenuHandler.hideMenu();
2012-05-21 20:32:26 +00:00
});
2013-06-28 19:07:06 +00:00
// Adds custom hit detection if native hit detection found no cell
2012-05-21 20:32:26 +00:00
this.updateMouseEvent = function(me)
{
2013-06-28 19:07:06 +00:00
var me = mxGraph.prototype.updateMouseEvent.apply(this, arguments);
2012-05-21 20:32:26 +00:00
if (me.getState() == null)
{
var cell = this.getCellAt(me.graphX, me.graphY);
2013-06-28 19:07:06 +00:00
if (cell != null && this.isSwimlane(cell) && this.hitsSwimlaneContent(cell, me.graphX, me.graphY))
{
cell = null;
}
else
2012-05-21 20:32:26 +00:00
{
me.state = this.view.getState(cell);
if (me.state != null && me.state.shape != null)
{
this.container.style.cursor = me.state.shape.node.style.cursor;
}
}
}
if (me.getState() == null)
{
this.container.style.cursor = 'default';
}
2013-06-28 19:07:06 +00:00
return me;
2012-05-21 20:32:26 +00:00
};
2013-06-28 19:07:06 +00:00
// Context menu trigger implementation depending on current selection state
// combined with support for normal popup trigger.
var cellSelected = false;
var selectionEmpty = false;
var menuShowing = false;
2012-05-21 20:32:26 +00:00
this.fireMouseEvent = function(evtName, me, sender)
{
if (evtName == mxEvent.MOUSE_DOWN)
{
2013-06-28 19:07:06 +00:00
// For hit detection on edges
me = this.updateMouseEvent(me);
2012-05-21 20:32:26 +00:00
2013-06-28 19:07:06 +00:00
cellSelected = this.isCellSelected(me.getCell());
selectionEmpty = this.isSelectionEmpty();
menuShowing = this.popupMenuHandler.isMenuShowing();
2012-05-21 20:32:26 +00:00
}
2013-06-28 19:07:06 +00:00
2012-05-21 20:32:26 +00:00
mxGraph.prototype.fireMouseEvent.apply(this, arguments);
};
2013-06-28 19:07:06 +00:00
// Shows popup menu if cell was selected or selection was empty and background was clicked
// FIXME: Conflicts with mxPopupMenuHandler.prototype.getCellForPopupEvent in Editor.js by
// selecting parent for selected children in groups before this check can be made.
this.popupMenuHandler.mouseUp = mxUtils.bind(this, function(sender, me)
{
this.popupMenuHandler.popupTrigger = !this.isEditing() && (this.popupMenuHandler.popupTrigger ||
(!menuShowing && !mxEvent.isMouseEvent(me.getEvent()) &&
((selectionEmpty && me.getCell() == null && this.isSelectionEmpty()) ||
(cellSelected && this.isCellSelected(me.getCell())))));
mxPopupMenuHandler.prototype.mouseUp.apply(this.popupMenuHandler, arguments);
});
2012-05-21 20:32:26 +00:00
};
(function()
{
2014-01-08 16:23:20 +00:00
/**
* HTML in-place editor
*/
mxCellEditor.prototype.isContentEditing = function()
{
return this.text2 != null && this.text2.style.display != 'none';
};
2013-06-28 19:07:06 +00:00
2014-01-08 16:23:20 +00:00
/**
* HTML in-place editor
*/
mxCellEditor.prototype.toggleViewMode = function()
{
if (this.text2 != null)
{
var tmp = this.saveSelection();
if (this.textarea.style.display == 'none')
{
var content = this.text2.innerHTML.replace(/\n/g, '');
if (this.textarea.value != content)
{
this.textarea.value = content;
this.setModified(true);
}
this.textarea.style.display = 'block';
this.text2.style.display = 'none';
this.textarea.focus();
}
else
{
var content = this.textarea.value.replace(/\n/g, '<br/>');
if (this.text2.innerHTML != content)
{
this.text2.innerHTML = content;
this.setModified(true);
}
this.text2.style.display = '';
this.textarea.style.display = 'none';
this.text2.focus();
}
if (this.switchSelectionState != null)
{
this.restoreSelection(this.switchSelectionState);
}
this.switchSelectionState = tmp;
}
};
2013-06-28 19:07:06 +00:00
2014-05-15 19:58:36 +00:00
var mxConstraintHandlerUpdate = mxConstraintHandler.prototype.update;
mxConstraintHandler.prototype.update = function(me, source)
{
if (!mxEvent.isMetaDown(me.getEvent()) && !mxEvent.isShiftDown(me.getEvent()) && !mxEvent.isControlDown(me.getEvent()))
{
mxConstraintHandlerUpdate.apply(this, arguments);
}
else
{
this.reset();
}
};
2014-01-08 16:23:20 +00:00
/**
* Creates the keyboard event handler for the current graph and history.
*/
mxCellEditor.prototype.saveSelection = function()
{
if (window.getSelection)
{
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount)
{
var ranges = [];
for (var i = 0, len = sel.rangeCount; i < len; ++i)
{
ranges.push(sel.getRangeAt(i));
}
return ranges;
}
}
else if (document.selection && document.selection.createRange)
{
return document.selection.createRange();
}
return null;
};
/**
* Creates the keyboard event handler for the current graph and history.
*/
mxCellEditor.prototype.restoreSelection = function(savedSel)
{
if (savedSel)
{
if (window.getSelection)
{
sel = window.getSelection();
sel.removeAllRanges();
for (var i = 0, len = savedSel.length; i < len; ++i)
{
sel.addRange(savedSel[i]);
}
}
else if (document.selection && savedSel.select)
{
savedSel.select();
}
}
};
if ('contentEditable' in document.documentElement)
{
2014-05-15 19:58:36 +00:00
/**
* Keypress starts immediate editing on selection cell
*/
var editorUiInit = EditorUi.prototype.init;
EditorUi.prototype.init = function()
{
editorUiInit.apply(this, arguments);
mxEvent.addListener(this.editor.graph.container, 'keypress', mxUtils.bind(this, function(evt)
{
if (!this.editor.graph.isEditing() && !this.editor.graph.isSelectionEmpty() && evt.which !== 0 &&
!mxEvent.isAltDown(evt) && !mxEvent.isControlDown(evt) && !mxEvent.isMetaDown(evt))
{
this.editor.graph.escape();
this.editor.graph.startEditing();
if (mxClient.IS_FF)
{
var ce = this.editor.graph.cellEditor;
// Initial keystroke is lost in FF
if (ce.textarea.style.display != 'none')
{
ce.textarea.value = String.fromCharCode(evt.which);
}
else if (ce.text2 != null)
{
ce.text2.innerHTML = String.fromCharCode(evt.which);
var range = document.createRange();
range.selectNodeContents(ce.text2);
range.collapse(false);
var selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
}
}
}
}));
};
2014-01-08 16:23:20 +00:00
/**
* HTML in-place editor
*/
var mxCellEditorStartEditing = mxCellEditor.prototype.startEditing;
mxCellEditor.prototype.startEditing = function(cell, trigger)
{
this.switchSelectionState = null;
// First run cannot set display before supercall because textarea is lazy created
// Lazy instantiates textarea to save memory in IE
if (this.textarea == null)
{
this.init();
}
var state = this.graph.view.getState(cell);
if (state != null && state.style['html'] == 1)
{
this.textarea.style.display = 'none';
}
else
{
this.textarea.style.display = 'block';
}
mxCellEditorStartEditing.apply(this, arguments);
2013-05-23 16:14:48 +00:00
2014-01-08 16:23:20 +00:00
if (this.textarea.style.display == 'none')
2014-05-12 09:58:11 +00:00
{
2014-01-08 16:23:20 +00:00
this.text2 = document.createElement('div');
2014-01-13 16:13:21 +00:00
this.text2.className = 'geContentEditable';
2014-01-08 16:23:20 +00:00
this.text2.innerHTML = this.textarea.value.replace(/\n/g, '<br/>');
var style = this.text2.style;
// Required to catch all events on the background in IE
style.backgroundImage = 'url(\'' + mxClient.imageBasePath + '/transparent.gif\')';
style.cursor = 'text';
style.outline = 'none';
style.position = 'absolute';
style.width = parseInt(this.textarea.style.width) + 'px';
style.height = (parseInt(this.textarea.style.height) - 4) + 'px';
style.left = parseInt(this.textarea.style.left) + 'px';
style.top = parseInt(this.textarea.style.top) + 'px';
style.fontFamily = this.textarea.style.fontFamily;
style.fontWeight = this.textarea.style.fontWeight;
2014-02-10 12:26:10 +00:00
style.textAlign = this.textarea.style.textAlign;
style.fontSize = this.textarea.style.fontSize;
2014-01-08 16:23:20 +00:00
style.color = this.textarea.style.color;
2014-02-10 12:26:10 +00:00
// Matches line height correctionFactor in embedded HTML output
2014-02-19 14:19:38 +00:00
if (state.text != null && state.text.node != null && state.text.node.ownerSVGElement != null)
2014-02-10 12:26:10 +00:00
{
var lh = (mxConstants.ABSOLUTE_LINE_HEIGHT) ? Math.round(parseInt(this.textarea.style.fontSize) * mxConstants.LINE_HEIGHT) + 'px' :
(mxConstants.LINE_HEIGHT * mxSvgCanvas2D.prototype.lineHeightCorrection);
style.lineHeight = lh;
}
else
{
style.lineHeight = this.textarea.style.lineHeight;
}
2014-01-08 16:23:20 +00:00
this.graph.container.appendChild(this.text2);
this.text2.contentEditable = true;
this.text2.focus();
2014-05-05 08:30:00 +00:00
if (this.isSelectText() && this.text2.innerHTML.length > 0)
2014-04-13 06:49:20 +00:00
{
2014-05-05 08:30:00 +00:00
document.execCommand('selectAll');
2014-04-13 06:49:20 +00:00
}
2014-01-08 16:23:20 +00:00
}
};
var mxCellEditorStopEditing = mxCellEditor.prototype.stopEditing;
mxCellEditor.prototype.stopEditing = function(cancel)
{
if (this.text2 != null)
{
var content = this.text2.innerHTML;
// Modified state also updated in code view action
if (this.text2.style.display != 'none' && this.textarea.value != content)
{
2014-02-10 12:26:10 +00:00
this.textarea.value = content.replace(/\r\n/g, '').replace(/\n/g, '');
2014-01-08 16:23:20 +00:00
this.setModified(true);
}
this.text2.parentNode.removeChild(this.text2);
this.text2 = null;
}
mxCellEditorStopEditing.apply(this, arguments);
};
// Workaround for focusLost calls stopEditing when in HTML view
var mxCellEditorFocusLost = mxCellEditor.prototype.focusLost;
mxCellEditor.prototype.focusLost = function(evt)
{
if (this.text2 == null)
{
mxCellEditorFocusLost.apply(this, arguments);
}
};
}
2013-05-23 16:14:48 +00:00
2014-05-12 09:58:11 +00:00
function createHint()
{
var hint = document.createElement('div');
hint.className = 'geHint';
hint.style.whiteSpace = 'nowrap';
hint.style.position = 'absolute';
return hint;
};
/**
* Updates the hint for the current operation.
*/
mxGraphHandler.prototype.updateHint = function(me)
{
if (this.shape != null)
{
if (this.hint == null)
{
this.hint = createHint();
this.graph.container.appendChild(this.hint);
}
var t = this.graph.view.translate;
var s = this.graph.view.scale;
var x = this.roundLength((this.bounds.x + this.currentDx) / s - t.x);
var y = this.roundLength((this.bounds.y + this.currentDy) / s - t.y);
2014-05-15 19:58:36 +00:00
this.hint.innerHTML = x + ', ' + y;
2014-05-12 09:58:11 +00:00
2014-06-02 08:21:19 +00:00
this.hint.style.left = (this.shape.bounds.x + Math.round((this.shape.bounds.width - this.hint.clientWidth) / 2)) + 'px';
2014-05-15 19:58:36 +00:00
this.hint.style.top = (this.shape.bounds.y + this.shape.bounds.height + 12) + 'px';
2014-05-12 09:58:11 +00:00
}
};
/**
* Updates the hint for the current operation.
*/
mxGraphHandler.prototype.removeHint = function()
{
if (this.hint != null)
{
this.hint.parentNode.removeChild(this.hint);
this.hint = null;
}
};
2014-04-13 06:49:20 +00:00
/**
* Enables recursive resize for groups.
*/
mxVertexHandler.prototype.isRecursiveResize = function(state, me)
{
return !this.graph.isSwimlane(state.cell) && this.graph.model.getChildCount(state.cell) > 0 && !mxEvent.isControlDown(me.getEvent());
};
2014-05-12 09:58:11 +00:00
/**
* Updates the hint for the current operation.
*/
mxVertexHandler.prototype.updateHint = function(me)
{
if (this.index != mxEvent.LABEL_HANDLE)
{
if (this.hint == null)
{
this.hint = createHint();
this.state.view.graph.container.appendChild(this.hint);
}
if (this.index == mxEvent.ROTATION_HANDLE)
{
this.hint.innerHTML = this.currentAlpha + '&deg;';
}
else
{
var s = this.state.view.scale;
2014-05-15 19:58:36 +00:00
this.hint.innerHTML = this.roundLength(this.bounds.width / s) + ' x ' + this.roundLength(this.bounds.height / s);
}
var rot = (this.currentAlpha != null) ? this.currentAlpha : this.state.style[mxConstants.STYLE_ROTATION] || '0';
var bb = mxUtils.getBoundingBox(this.bounds, rot);
if (bb == null)
{
bb = this.bounds;
2014-05-12 09:58:11 +00:00
}
2014-05-15 19:58:36 +00:00
this.hint.style.left = bb.x + Math.round((bb.width - this.hint.clientWidth) / 2) + 'px';
this.hint.style.top = (bb.y + bb.height + 12) + 'px';
2014-05-12 09:58:11 +00:00
}
};
/**
* Updates the hint for the current operation.
*/
mxVertexHandler.prototype.removeHint = mxGraphHandler.prototype.removeHint;
/**
* Updates the hint for the current operation.
*/
mxEdgeHandler.prototype.updateHint = function(me, point)
{
if (this.hint == null)
{
this.hint = createHint();
this.state.view.graph.container.appendChild(this.hint);
}
var t = this.graph.view.translate;
var s = this.graph.view.scale;
var x = this.roundLength(point.x / s - t.x);
var y = this.roundLength(point.y / s - t.y);
2014-05-15 19:58:36 +00:00
this.hint.innerHTML = x + ', ' + y;
2014-05-12 09:58:11 +00:00
this.hint.style.left = Math.round(me.getGraphX() - this.hint.clientWidth / 2) + 'px';
2014-05-15 19:58:36 +00:00
this.hint.style.top = (me.getGraphY() + 12) + 'px';
2014-05-12 09:58:11 +00:00
};
/**
* Updates the hint for the current operation.
*/
mxEdgeHandler.prototype.removeHint = mxGraphHandler.prototype.removeHint;
2014-01-08 16:23:20 +00:00
/**
2014-05-15 19:58:36 +00:00
* Defines the handles for the UI.
2014-01-08 16:23:20 +00:00
*/
2014-05-15 19:58:36 +00:00
var connectHandle = new mxImage(IMAGE_PATH + '/handle-connect.png', 26, 26);
var mainHandle = new mxImage(IMAGE_PATH + '/handle-main.png', 17, 17);
var secondaryHandle = new mxImage(IMAGE_PATH + '/handle-secondary.png', 17, 17);
var rotationHandle = new mxImage(IMAGE_PATH + '/handle-rotate.png', 19, 21);
var edgeHandle = new mxImage(IMAGE_PATH + '/handle-main.png', 17, 17);
mxConstants.HANDLE_SIZE = 17;
mxConstants.LABEL_HANDLE_SIZE = 7;
mxVertexHandler.prototype.rotationHandleVSpacing = -20;
mxConnectionHandler.prototype.connectImage = connectHandle;
mxVertexHandler.prototype.handleImage = mainHandle;
mxVertexHandler.prototype.secondaryHandleImage = secondaryHandle;
mxEdgeHandler.prototype.handleImage = edgeHandle;
mxOutline.prototype.sizerImage = mainHandle;
// Pre-fetches images
new Image().src = connectHandle.src;
new Image().src = mainHandle.src;
new Image().src = secondaryHandle.src;
new Image().src = rotationHandle.src;
var vertexHandlerCreateSizerShape = mxVertexHandler.prototype.createSizerShape;
mxVertexHandler.prototype.createSizerShape = function(bounds, index, fillColor)
2012-05-21 20:32:26 +00:00
{
2014-05-15 19:58:36 +00:00
this.handleImage = (index == mxEvent.ROTATION_HANDLE) ? rotationHandle : mxVertexHandler.prototype.handleImage;
return vertexHandlerCreateSizerShape.apply(this, arguments);
};
// Requires callback to editorUi in edit link so override editorUi.init
var editorUiInit3 = EditorUi.prototype.init;
EditorUi.prototype.init = function()
{
editorUiInit3.apply(this, arguments);
2012-05-21 20:32:26 +00:00
2014-05-15 19:58:36 +00:00
// Required for calling edit link action below
var ui = this;
/**
* Implements touch style
*/
if (touchStyle)
2013-06-28 19:07:06 +00:00
{
2014-05-15 19:58:36 +00:00
// Larger tolerance and grid for real touch devices
if (mxClient.IS_TOUCH || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0)
{
mxShape.prototype.svgStrokeTolerance = 18;
mxVertexHandler.prototype.tolerance = 12;
mxEdgeHandler.prototype.tolerance = 12;
Graph.prototype.tolerance = 12;
mxVertexHandler.prototype.rotationHandleVSpacing = -24;
}
// One finger pans (no rubberband selection) must start regardless of mouse button
mxPanningHandler.prototype.isPanningTrigger = function(me)
{
var evt = me.getEvent();
return (me.getState() == null && !mxEvent.isMouseEvent(evt)) ||
(mxEvent.isPopupTrigger(evt) && (me.getState() == null ||
mxEvent.isControlDown(evt) || mxEvent.isShiftDown(evt)));
};
2013-06-28 19:07:06 +00:00
2014-05-15 19:58:36 +00:00
// Don't clear selection if multiple cells selected
var graphHandlerMouseDown = mxGraphHandler.prototype.mouseDown;
mxGraphHandler.prototype.mouseDown = function(sender, me)
{
graphHandlerMouseDown.apply(this, arguments);
if (this.graph.isCellSelected(me.getCell()) && this.graph.getSelectionCount() > 1)
{
this.delayedSelection = false;
}
};
// Installs locked and connect handles
// Problem is condition for source and target in segment handler before creating bends array
/*var edgeHandlerCreateHandleShape = mxEdgeHandler.prototype.createHandleShape;
mxEdgeHandler.prototype.createHandleShape = function(index)
{
if (index == 0 || index == this.abspoints.length - 1)
{
this.handleImage = connectHandle;
}
else
{
this.handleImage = touchHandle;
}
return edgeHandlerCreateHandleShape.apply(this, arguments);
};*/
}
2012-05-21 20:32:26 +00:00
2014-05-15 19:58:36 +00:00
var vertexHandlerMouseMove = mxVertexHandler.prototype.mouseMove;
mxVertexHandler.prototype.mouseMove = function()
2012-05-21 20:32:26 +00:00
{
2014-05-15 19:58:36 +00:00
vertexHandlerMouseMove.apply(this, arguments);
if (this.graph.graphHandler.first != null)
2012-05-21 20:32:26 +00:00
{
2014-05-15 19:58:36 +00:00
if (this.linkHint != null)
{
this.linkHint.style.display = 'none';
}
if (this.connectorImg != null)
{
this.connectorImg.style.display = 'none';
}
if (this.rotationShape != null && this.rotationShape.node != null)
{
this.rotationShape.node.style.display = 'none';
}
2012-05-21 20:32:26 +00:00
}
};
2013-06-28 19:07:06 +00:00
2014-05-15 19:58:36 +00:00
var vertexHandlerMouseUp = mxVertexHandler.prototype.mouseUp;
mxVertexHandler.prototype.mouseUp = function()
2013-06-28 19:07:06 +00:00
{
2014-05-15 19:58:36 +00:00
vertexHandlerMouseUp.apply(this, arguments);
if (this.connectorImg != null)
2013-06-28 19:07:06 +00:00
{
2014-05-15 19:58:36 +00:00
this.connectorImg.style.display = (this.graph.getSelectionCount() == 1) ? '' : 'none';
2013-06-28 19:07:06 +00:00
}
2014-05-15 19:58:36 +00:00
if (this.linkHint != null)
2013-06-28 19:07:06 +00:00
{
2014-05-15 19:58:36 +00:00
this.linkHint.style.display = (this.graph.getSelectionCount() == 1) ? '' : 'none';
2013-06-28 19:07:06 +00:00
}
2014-05-15 19:58:36 +00:00
// Shows rotation handle only if one vertex is selected
if (this.rotationShape != null && this.rotationShape.node != null)
{
this.rotationShape.node.style.display = (this.graph.getSelectionCount() == 1) ? '' : 'none';
}
};
2012-05-21 20:32:26 +00:00
var vertexHandlerInit = mxVertexHandler.prototype.init;
mxVertexHandler.prototype.init = function()
{
vertexHandlerInit.apply(this, arguments);
2014-05-15 19:58:36 +00:00
var redraw = false;
2014-06-02 08:21:19 +00:00
var update = mxUtils.bind(this, function()
2012-05-21 20:32:26 +00:00
{
2014-05-15 19:58:36 +00:00
if (this.connectorImg != null)
{
this.connectorImg.style.display = (this.graph.getSelectionCount() == 1) ? '' : 'none';
}
2012-05-21 20:32:26 +00:00
2014-05-15 19:58:36 +00:00
if (this.linkHint != null)
2012-05-21 20:32:26 +00:00
{
2014-05-15 19:58:36 +00:00
this.linkHint.style.display = (this.graph.getSelectionCount() == 1) ? '' : 'none';
2012-05-21 20:32:26 +00:00
}
2014-05-15 19:58:36 +00:00
// Shows rotation handle only if one vertex is selected
if (this.rotationShape != null && this.rotationShape.node != null)
{
this.rotationShape.node.style.display = (this.graph.getSelectionCount() == 1) ? '' : 'none';
}
this.redrawHandles();
});
2014-06-02 08:21:19 +00:00
this.selectionHandler = mxUtils.bind(this, function(sender, evt)
{
update();
});
2014-05-15 19:58:36 +00:00
this.graph.getSelectionModel().addListener(mxEvent.CHANGE, this.selectionHandler);
this.changeHandler = mxUtils.bind(this, function(sender, evt)
2012-12-18 13:09:38 +00:00
{
2014-05-15 19:58:36 +00:00
this.updateLinkHint(this.graph.getLinkForCell(this.state.cell));
2014-06-02 08:21:19 +00:00
update();
2014-05-15 19:58:36 +00:00
});
this.graph.getModel().addListener(mxEvent.CHANGE, this.changeHandler);
2013-05-23 16:14:48 +00:00
2014-05-15 19:58:36 +00:00
if (touchStyle || urlParams['connect'] == null || urlParams['connect'] == '2')
{
2012-12-18 13:09:38 +00:00
// Only show connector image on one cell and do not show on containers
if (showConnectorImg && this.graph.connectionHandler.isEnabled() &&
this.graph.isCellConnectable(this.state.cell) &&
2014-05-15 19:58:36 +00:00
!this.graph.isValidRoot(this.state.cell))
2012-12-18 13:09:38 +00:00
{
2013-05-23 16:14:48 +00:00
// Workaround for event redirection via image tag in quirks and IE8
if (mxClient.IS_IE && !mxClient.IS_SVG)
{
2014-05-15 19:58:36 +00:00
// Workaround for PNG images in IE6
if (mxClient.IS_IE6 && document.compatMode != 'CSS1Compat')
{
this.connectorImg = document.createElement(mxClient.VML_PREFIX + ':image');
this.connectorImg.setAttribute('src', connectHandle.src);
this.connectorImg.style.borderStyle = 'none';
}
else
{
this.connectorImg = document.createElement('div');
this.connectorImg.style.backgroundImage = 'url(' + connectHandle.src + ')';
this.connectorImg.style.backgroundPosition = 'center';
this.connectorImg.style.backgroundRepeat = 'no-repeat';
}
this.connectorImg.style.width = (connectHandle.width + 4) + 'px';
this.connectorImg.style.height = (connectHandle.height + 4) + 'px';
2013-05-23 16:14:48 +00:00
this.connectorImg.style.display = (mxClient.IS_QUIRKS) ? 'inline' : 'inline-block';
}
else
{
2014-05-15 19:58:36 +00:00
this.connectorImg = mxUtils.createImage(connectHandle.src);
if (touchStyle)
{
this.connectorImg.style.width = '29px';
this.connectorImg.style.height = '29px';
}
else
{
this.connectorImg.style.width = connectHandle.width + 'px';
this.connectorImg.style.height = connectHandle.height + 'px';
}
2013-05-23 16:14:48 +00:00
}
2014-05-15 19:58:36 +00:00
this.connectorImg.style.cursor = 'crosshair';
2012-12-18 13:09:38 +00:00
this.connectorImg.style.position = 'absolute';
this.connectorImg.setAttribute('title', mxResources.get('connect'));
2013-05-23 16:14:48 +00:00
2014-05-15 19:58:36 +00:00
if (!(mxClient.IS_TOUCH || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0))
{
mxEvent.redirectMouseEvents(this.connectorImg, this.graph, this.state);
}
2013-06-28 19:07:06 +00:00
// Starts connecting on touch/mouse down
mxEvent.addGestureListeners(this.connectorImg,
2012-12-18 13:09:38 +00:00
mxUtils.bind(this, function(evt)
{
2013-06-28 19:07:06 +00:00
this.graph.popupMenuHandler.hideMenu();
this.graph.stopEditing(false);
2012-12-18 13:09:38 +00:00
var pt = mxUtils.convertPoint(this.graph.container,
mxEvent.getClientX(evt), mxEvent.getClientY(evt));
this.graph.connectionHandler.start(this.state, pt.x, pt.y);
2013-06-28 19:07:06 +00:00
this.graph.isMouseTrigger = mxEvent.isMouseEvent(evt);
2012-12-18 13:09:38 +00:00
this.graph.isMouseDown = true;
mxEvent.consume(evt);
})
);
this.graph.container.appendChild(this.connectorImg);
2014-05-15 19:58:36 +00:00
redraw = true;
}
}
var link = this.graph.getLinkForCell(this.state.cell);
if (link != null)
{
var label = link;
var max = 60;
var head = 36;
var tail = 20;
if (label.length > max)
{
label = label.substring(0, head) + '...' + label.substring(label.length - tail);
}
this.linkHint = createHint();
this.linkHint.style.padding = '4px 10px 6px 10px';
this.linkHint.style.fontSize = '90%';
this.linkHint.style.opacity = '1';
this.linkHint.style.filter = '';
this.updateLinkHint(link);
this.graph.container.appendChild(this.linkHint);
redraw = true;
}
if (redraw)
{
this.redrawHandles();
}
};
mxVertexHandler.prototype.updateLinkHint = function(link)
{
if (this.linkHint != null)
{
var label = link;
var max = 60;
var head = 36;
var tail = 20;
if (label.length > max)
{
label = label.substring(0, head) + '...' + label.substring(label.length - tail);
2012-12-18 13:09:38 +00:00
}
2014-05-15 19:58:36 +00:00
this.linkHint.innerHTML = '<a href="' + link + '" title="' + link + '" target="_blank">' + label + '</a>';
var changeLink = document.createElement('img');
changeLink.setAttribute('src', IMAGE_PATH + '/edit.gif');
changeLink.setAttribute('title', mxResources.get('editLink'));
changeLink.style.marginLeft = '10px';
changeLink.style.marginBottom = '-1px';
changeLink.style.cursor = 'pointer';
this.linkHint.appendChild(changeLink);
mxEvent.addListener(changeLink, 'click', mxUtils.bind(this, function(evt)
{
this.graph.setSelectionCell(this.state.cell);
ui.actions.get('editLink').funct();
mxEvent.consume(evt);
}));
}
};
mxEdgeHandler.prototype.updateLinkHint = mxVertexHandler.prototype.updateLinkHint;
var edgeHandlerInit = mxEdgeHandler.prototype.init;
mxEdgeHandler.prototype.init = function()
{
edgeHandlerInit.apply(this, arguments);
2014-06-02 08:21:19 +00:00
var update = mxUtils.bind(this, function()
2014-05-15 19:58:36 +00:00
{
if (this.linkHint != null)
{
this.linkHint.style.display = (this.graph.getSelectionCount() == 1) ? '' : 'none';
}
});
2014-06-02 08:21:19 +00:00
this.selectionHandler = mxUtils.bind(this, function(sender, evt)
{
update();
});
2014-05-15 19:58:36 +00:00
this.graph.getSelectionModel().addListener(mxEvent.CHANGE, this.selectionHandler);
this.changeHandler = mxUtils.bind(this, function(sender, evt)
{
this.updateLinkHint(this.graph.getLinkForCell(this.state.cell));
2014-06-02 08:21:19 +00:00
update();
2014-05-15 19:58:36 +00:00
this.redrawHandles();
});
this.graph.getModel().addListener(mxEvent.CHANGE, this.changeHandler);
var link = this.graph.getLinkForCell(this.state.cell);
if (link != null)
{
this.linkHint = createHint();
this.linkHint.style.padding = '4px 10px 6px 10px';
this.linkHint.style.fontSize = '90%';
this.linkHint.style.opacity = '1';
this.linkHint.style.filter = '';
this.updateLinkHint(link);
this.graph.container.appendChild(this.linkHint);
this.redrawHandles();
}
};
};
2013-06-28 19:07:06 +00:00
var vertexHandlerRedrawHandles = mxVertexHandler.prototype.redrawHandles;
mxVertexHandler.prototype.redrawHandles = function()
{
vertexHandlerRedrawHandles.apply(this);
if (this.state != null && this.connectorImg != null)
{
var pt = new mxPoint();
var s = this.state;
2012-12-18 13:09:38 +00:00
2013-06-28 19:07:06 +00:00
// Top right for single-sizer
if (mxVertexHandler.prototype.singleSizer)
2012-12-18 13:09:38 +00:00
{
2013-06-28 19:07:06 +00:00
pt.x = s.x + s.width - this.connectorImg.offsetWidth / 2;
pt.y = s.y - this.connectorImg.offsetHeight / 2;
}
else
2012-12-18 13:09:38 +00:00
{
2014-05-15 19:58:36 +00:00
pt.x = s.x + s.width + (mxConstants.HANDLE_SIZE + this.horizontalOffset + this.tolerance + this.connectorImg.offsetWidth) / 2;
2013-06-28 19:07:06 +00:00
pt.y = s.y + s.height / 2;
}
var alpha = mxUtils.toRadians(mxUtils.getValue(s.style, mxConstants.STYLE_ROTATION, 0));
2012-12-18 13:09:38 +00:00
2013-06-28 19:07:06 +00:00
if (alpha != 0)
2012-12-18 13:09:38 +00:00
{
2013-06-28 19:07:06 +00:00
var cos = Math.cos(alpha);
var sin = Math.sin(alpha);
var ct = new mxPoint(s.getCenterX(), s.getCenterY());
pt = mxUtils.getRotatedPoint(pt, cos, sin, ct);
}
2014-05-15 19:58:36 +00:00
this.connectorImg.style.left = Math.round(pt.x - this.connectorImg.offsetWidth / 2) + 'px';
this.connectorImg.style.top = Math.round(pt.y - this.connectorImg.offsetHeight / 2) + 'px';
}
if (this.state != null && this.linkHint != null)
{
var c = new mxPoint(this.state.getCenterX(), this.state.getCenterY());
var tmp = new mxRectangle(this.state.x, this.state.y - 22, this.state.width + 24, this.state.height + 22);
var bb = mxUtils.getBoundingBox(tmp, this.state.style[mxConstants.STYLE_ROTATION] || '0', c);
var rs = (bb != null) ? mxUtils.getBoundingBox(this.state, this.state.style[mxConstants.STYLE_ROTATION] || '0') : this.state;
if (bb == null)
{
bb = this.state;
}
this.linkHint.style.left = Math.round(rs.x + (rs.width - this.linkHint.clientWidth) / 2) + 'px';
this.linkHint.style.top = Math.round(bb.y + bb.height + this.verticalOffset / 2 +
6 + this.state.view.graph.tolerance) + 'px';
2013-06-28 19:07:06 +00:00
}
};
2012-12-18 13:09:38 +00:00
2013-06-28 19:07:06 +00:00
var vertexHandlerHideSizers = mxVertexHandler.prototype.hideSizers;
mxVertexHandler.prototype.hideSizers = function()
{
vertexHandlerHideSizers.apply(this, arguments);
if (this.connectorImg != null)
{
this.connectorImg.style.visibility = 'hidden';
2012-12-18 13:09:38 +00:00
}
2014-05-15 19:58:36 +00:00
if (this.linkHint != null)
{
this.linkHint.style.visibility = 'hidden';
}
2013-06-28 19:07:06 +00:00
};
var vertexHandlerReset = mxVertexHandler.prototype.reset;
mxVertexHandler.prototype.reset = function()
{
vertexHandlerReset.apply(this, arguments);
if (this.connectorImg != null)
{
this.connectorImg.style.visibility = '';
}
2014-05-15 19:58:36 +00:00
if (this.linkHint != null)
{
this.linkHint.style.visibility = '';
}
2013-06-28 19:07:06 +00:00
};
var vertexHandlerDestroy = mxVertexHandler.prototype.destroy;
mxVertexHandler.prototype.destroy = function(sender, me)
{
vertexHandlerDestroy.apply(this, arguments);
2014-05-15 19:58:36 +00:00
if (this.linkHint != null)
{
this.linkHint.parentNode.removeChild(this.linkHint);
this.linkHint = null;
}
2013-06-28 19:07:06 +00:00
if (this.connectorImg != null)
{
this.connectorImg.parentNode.removeChild(this.connectorImg);
this.connectorImg = null;
}
2014-05-15 19:58:36 +00:00
if (this.selectionHandler != null)
{
this.graph.getSelectionModel().removeListener(this.selectionHandler);
this.selectionHandler = null;
}
if (this.changeHandler != null)
{
this.graph.getModel().removeListener(this.cahngeHandler);
this.changeHandler = null;
}
};
var edgeHandlerRedrawHandles = mxEdgeHandler.prototype.redrawHandles;
mxEdgeHandler.prototype.redrawHandles = function()
{
// Workaround for special case where handler
// is reset before this which leads to a NPE
if (this.marker != null)
{
edgeHandlerRedrawHandles.apply(this);
if (this.state != null && this.linkHint != null)
{
var b = this.state;
if (this.state.text != null && this.state.text.bounds != null)
{
b = new mxRectangle(b.x, b.y, b.width, b.height);
b.add(this.state.text.bounds);
}
this.linkHint.style.left = Math.round(b.x + (b.width - this.linkHint.clientWidth) / 2) + 'px';
this.linkHint.style.top = Math.round(b.y + b.height + 6 + this.state.view.graph.tolerance) + 'px';
}
}
};
var edgeHandlerHideSizers = mxEdgeHandler.prototype.hideSizers;
mxEdgeHandler.prototype.hideSizers = function()
{
edgeHandlerHideSizers.apply(this, arguments);
if (this.linkHint != null)
{
this.linkHint.style.visibility = 'hidden';
}
};
var edgeHandlerReset = mxEdgeHandler.prototype.reset;
mxEdgeHandler.prototype.reset = function()
{
edgeHandlerReset.apply(this, arguments);
if (this.linkHint != null)
{
this.linkHint.style.visibility = '';
}
};
var edgeHandlerDestroy = mxEdgeHandler.prototype.destroy;
mxEdgeHandler.prototype.destroy = function(sender, me)
{
edgeHandlerDestroy.apply(this, arguments);
if (this.linkHint != null)
{
this.linkHint.parentNode.removeChild(this.linkHint);
this.linkHint = null;
}
if (this.selectionHandler != null)
{
this.graph.getSelectionModel().removeListener(this.selectionHandler);
this.selectionHandler = null;
}
if (this.changeHandler != null)
{
this.graph.getModel().removeListener(this.cahngeHandler);
this.changeHandler = null;
}
2013-06-28 19:07:06 +00:00
};
2012-05-31 09:57:33 +00:00
})();