1133 lines
27 KiB
JavaScript
1133 lines
27 KiB
JavaScript
/**
|
|
* Copyright (c) 2006-2015, JGraph Ltd
|
|
* Copyright (c) 2006-2015, Gaudenz Alder
|
|
*/
|
|
/**
|
|
* Class: mxWindow
|
|
*
|
|
* Basic window inside a document.
|
|
*
|
|
* Examples:
|
|
*
|
|
* Creating a simple window.
|
|
*
|
|
* (code)
|
|
* var tb = document.createElement('div');
|
|
* var wnd = new mxWindow('Title', tb, 100, 100, 200, 200, true, true);
|
|
* wnd.setVisible(true);
|
|
* (end)
|
|
*
|
|
* Creating a window that contains an iframe.
|
|
*
|
|
* (code)
|
|
* var frame = document.createElement('iframe');
|
|
* frame.setAttribute('width', '192px');
|
|
* frame.setAttribute('height', '172px');
|
|
* frame.setAttribute('src', 'http://www.example.com/');
|
|
* frame.style.backgroundColor = 'white';
|
|
*
|
|
* var w = document.body.clientWidth;
|
|
* var h = (document.body.clientHeight || document.documentElement.clientHeight);
|
|
* var wnd = new mxWindow('Title', frame, (w-200)/2, (h-200)/3, 200, 200);
|
|
* wnd.setVisible(true);
|
|
* (end)
|
|
*
|
|
* To limit the movement of a window, eg. to keep it from being moved beyond
|
|
* the top, left corner the following method can be overridden (recommended):
|
|
*
|
|
* (code)
|
|
* wnd.setLocation = function(x, y)
|
|
* {
|
|
* x = Math.max(0, x);
|
|
* y = Math.max(0, y);
|
|
* mxWindow.prototype.setLocation.apply(this, arguments);
|
|
* };
|
|
* (end)
|
|
*
|
|
* Or the following event handler can be used:
|
|
*
|
|
* (code)
|
|
* wnd.addListener(mxEvent.MOVE, function(e)
|
|
* {
|
|
* wnd.setLocation(Math.max(0, wnd.getX()), Math.max(0, wnd.getY()));
|
|
* });
|
|
* (end)
|
|
*
|
|
* To keep a window inside the current window:
|
|
*
|
|
* (code)
|
|
* mxEvent.addListener(window, 'resize', mxUtils.bind(this, function()
|
|
* {
|
|
* var iw = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
|
|
* var ih = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
|
|
*
|
|
* var x = this.window.getX();
|
|
* var y = this.window.getY();
|
|
*
|
|
* if (x + this.window.table.clientWidth > iw)
|
|
* {
|
|
* x = Math.max(0, iw - this.window.table.clientWidth);
|
|
* }
|
|
*
|
|
* if (y + this.window.table.clientHeight > ih)
|
|
* {
|
|
* y = Math.max(0, ih - this.window.table.clientHeight);
|
|
* }
|
|
*
|
|
* if (this.window.getX() != x || this.window.getY() != y)
|
|
* {
|
|
* this.window.setLocation(x, y);
|
|
* }
|
|
* }));
|
|
* (end)
|
|
*
|
|
* Event: mxEvent.MOVE_START
|
|
*
|
|
* Fires before the window is moved. The <code>event</code> property contains
|
|
* the corresponding mouse event.
|
|
*
|
|
* Event: mxEvent.MOVE
|
|
*
|
|
* Fires while the window is being moved. The <code>event</code> property
|
|
* contains the corresponding mouse event.
|
|
*
|
|
* Event: mxEvent.MOVE_END
|
|
*
|
|
* Fires after the window is moved. The <code>event</code> property contains
|
|
* the corresponding mouse event.
|
|
*
|
|
* Event: mxEvent.RESIZE_START
|
|
*
|
|
* Fires before the window is resized. The <code>event</code> property contains
|
|
* the corresponding mouse event.
|
|
*
|
|
* Event: mxEvent.RESIZE
|
|
*
|
|
* Fires while the window is being resized. The <code>event</code> property
|
|
* contains the corresponding mouse event.
|
|
*
|
|
* Event: mxEvent.RESIZE_END
|
|
*
|
|
* Fires after the window is resized. The <code>event</code> property contains
|
|
* the corresponding mouse event.
|
|
*
|
|
* Event: mxEvent.MAXIMIZE
|
|
*
|
|
* Fires after the window is maximized. The <code>event</code> property
|
|
* contains the corresponding mouse event.
|
|
*
|
|
* Event: mxEvent.MINIMIZE
|
|
*
|
|
* Fires after the window is minimized. The <code>event</code> property
|
|
* contains the corresponding mouse event.
|
|
*
|
|
* Event: mxEvent.NORMALIZE
|
|
*
|
|
* Fires after the window is normalized, that is, it returned from
|
|
* maximized or minimized state. The <code>event</code> property contains the
|
|
* corresponding mouse event.
|
|
*
|
|
* Event: mxEvent.ACTIVATE
|
|
*
|
|
* Fires after a window is activated. The <code>previousWindow</code> property
|
|
* contains the previous window. The event sender is the active window.
|
|
*
|
|
* Event: mxEvent.SHOW
|
|
*
|
|
* Fires after the window is shown. This event has no properties.
|
|
*
|
|
* Event: mxEvent.HIDE
|
|
*
|
|
* Fires after the window is hidden. This event has no properties.
|
|
*
|
|
* Event: mxEvent.CLOSE
|
|
*
|
|
* Fires before the window is closed. The <code>event</code> property contains
|
|
* the corresponding mouse event.
|
|
*
|
|
* Event: mxEvent.DESTROY
|
|
*
|
|
* Fires before the window is destroyed. This event has no properties.
|
|
*
|
|
* Constructor: mxWindow
|
|
*
|
|
* Constructs a new window with the given dimension and title to display
|
|
* the specified content. The window elements use the given style as a
|
|
* prefix for the classnames of the respective window elements, namely,
|
|
* the window title and window pane. The respective postfixes are appended
|
|
* to the given stylename as follows:
|
|
*
|
|
* style - Base style for the window.
|
|
* style+Title - Style for the window title.
|
|
* style+Pane - Style for the window pane.
|
|
*
|
|
* The default value for style is mxWindow, resulting in the following
|
|
* classnames for the window elements: mxWindow, mxWindowTitle and
|
|
* mxWindowPane.
|
|
*
|
|
* If replaceNode is given then the window replaces the given DOM node in
|
|
* the document.
|
|
*
|
|
* Parameters:
|
|
*
|
|
* title - String that represents the title of the new window.
|
|
* content - DOM node that is used as the window content.
|
|
* x - X-coordinate of the window location.
|
|
* y - Y-coordinate of the window location.
|
|
* width - Width of the window.
|
|
* height - Optional height of the window. Default is to match the height
|
|
* of the content at the specified width.
|
|
* minimizable - Optional boolean indicating if the window is minimizable.
|
|
* Default is true.
|
|
* movable - Optional boolean indicating if the window is movable. Default
|
|
* is true.
|
|
* replaceNode - Optional DOM node that the window should replace.
|
|
* style - Optional base classname for the window elements. Default is
|
|
* mxWindow.
|
|
*/
|
|
function mxWindow(title, content, x, y, width, height, minimizable, movable, replaceNode, style)
|
|
{
|
|
if (content != null)
|
|
{
|
|
minimizable = (minimizable != null) ? minimizable : true;
|
|
this.content = content;
|
|
this.init(x, y, width, height, style);
|
|
|
|
this.installMaximizeHandler();
|
|
this.installMinimizeHandler();
|
|
this.installCloseHandler();
|
|
this.setMinimizable(minimizable);
|
|
this.setTitle(title);
|
|
|
|
if (movable == null || movable)
|
|
{
|
|
this.installMoveHandler();
|
|
}
|
|
|
|
if (replaceNode != null && replaceNode.parentNode != null)
|
|
{
|
|
replaceNode.parentNode.replaceChild(this.div, replaceNode);
|
|
}
|
|
else
|
|
{
|
|
document.body.appendChild(this.div);
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Extends mxEventSource.
|
|
*/
|
|
mxWindow.prototype = new mxEventSource();
|
|
mxWindow.prototype.constructor = mxWindow;
|
|
|
|
/**
|
|
* Variable: closeImage
|
|
*
|
|
* URL of the image to be used for the close icon in the titlebar.
|
|
*/
|
|
mxWindow.prototype.closeImage = mxClient.imageBasePath + '/close.gif';
|
|
|
|
/**
|
|
* Variable: minimizeImage
|
|
*
|
|
* URL of the image to be used for the minimize icon in the titlebar.
|
|
*/
|
|
mxWindow.prototype.minimizeImage = mxClient.imageBasePath + '/minimize.gif';
|
|
|
|
/**
|
|
* Variable: normalizeImage
|
|
*
|
|
* URL of the image to be used for the normalize icon in the titlebar.
|
|
*/
|
|
mxWindow.prototype.normalizeImage = mxClient.imageBasePath + '/normalize.gif';
|
|
|
|
/**
|
|
* Variable: maximizeImage
|
|
*
|
|
* URL of the image to be used for the maximize icon in the titlebar.
|
|
*/
|
|
mxWindow.prototype.maximizeImage = mxClient.imageBasePath + '/maximize.gif';
|
|
|
|
/**
|
|
* Variable: resizeImage
|
|
*
|
|
* URL of the image to be used for the resize icon.
|
|
*/
|
|
mxWindow.prototype.resizeImage = mxClient.imageBasePath + '/resize.gif';
|
|
|
|
/**
|
|
* Variable: visible
|
|
*
|
|
* Boolean flag that represents the visible state of the window.
|
|
*/
|
|
mxWindow.prototype.visible = false;
|
|
|
|
/**
|
|
* Variable: minimumSize
|
|
*
|
|
* <mxRectangle> that specifies the minimum width and height of the window.
|
|
* Default is (50, 40).
|
|
*/
|
|
mxWindow.prototype.minimumSize = new mxRectangle(0, 0, 50, 40);
|
|
|
|
/**
|
|
* Variable: destroyOnClose
|
|
*
|
|
* Specifies if the window should be destroyed when it is closed. If this
|
|
* is false then the window is hidden using <setVisible>. Default is true.
|
|
*/
|
|
mxWindow.prototype.destroyOnClose = true;
|
|
|
|
/**
|
|
* Variable: contentHeightCorrection
|
|
*
|
|
* Defines the correction factor for computing the height of the contentWrapper.
|
|
* Default is 6 for IE 7/8 standards mode and 2 for all other browsers and modes.
|
|
*/
|
|
mxWindow.prototype.contentHeightCorrection = (document.documentMode == 8 || document.documentMode == 7) ? 6 : 2;
|
|
|
|
/**
|
|
* Variable: title
|
|
*
|
|
* Reference to the DOM node (TD) that contains the title.
|
|
*/
|
|
mxWindow.prototype.title = null;
|
|
|
|
/**
|
|
* Variable: content
|
|
*
|
|
* Reference to the DOM node that represents the window content.
|
|
*/
|
|
mxWindow.prototype.content = null;
|
|
|
|
/**
|
|
* Function: init
|
|
*
|
|
* Initializes the DOM tree that represents the window.
|
|
*/
|
|
mxWindow.prototype.init = function(x, y, width, height, style)
|
|
{
|
|
style = (style != null) ? style : 'mxWindow';
|
|
|
|
this.div = document.createElement('div');
|
|
this.div.className = style;
|
|
|
|
this.div.style.left = x + 'px';
|
|
this.div.style.top = y + 'px';
|
|
this.table = document.createElement('table');
|
|
this.table.className = style;
|
|
|
|
// Disables built-in pan and zoom in IE10 and later
|
|
if (mxClient.IS_POINTER)
|
|
{
|
|
this.div.style.touchAction = 'none';
|
|
}
|
|
|
|
// Workaround for table size problems in FF
|
|
if (width != null)
|
|
{
|
|
if (!mxClient.IS_QUIRKS)
|
|
{
|
|
this.div.style.width = width + 'px';
|
|
}
|
|
|
|
this.table.style.width = width + 'px';
|
|
}
|
|
|
|
if (height != null)
|
|
{
|
|
if (!mxClient.IS_QUIRKS)
|
|
{
|
|
this.div.style.height = height + 'px';
|
|
}
|
|
|
|
this.table.style.height = height + 'px';
|
|
}
|
|
|
|
// Creates title row
|
|
var tbody = document.createElement('tbody');
|
|
var tr = document.createElement('tr');
|
|
|
|
this.title = document.createElement('td');
|
|
this.title.className = style + 'Title';
|
|
|
|
this.buttons = document.createElement('div');
|
|
this.buttons.style.position = 'absolute';
|
|
this.buttons.style.display = 'inline-block';
|
|
this.buttons.style.right = '4px';
|
|
this.buttons.style.top = '5px';
|
|
this.title.appendChild(this.buttons);
|
|
|
|
tr.appendChild(this.title);
|
|
tbody.appendChild(tr);
|
|
|
|
// Creates content row and table cell
|
|
tr = document.createElement('tr');
|
|
this.td = document.createElement('td');
|
|
this.td.className = style + 'Pane';
|
|
|
|
if (document.documentMode == 7)
|
|
{
|
|
this.td.style.height = '100%';
|
|
}
|
|
|
|
this.contentWrapper = document.createElement('div');
|
|
this.contentWrapper.className = style + 'Pane';
|
|
this.contentWrapper.style.width = '100%';
|
|
this.contentWrapper.appendChild(this.content);
|
|
|
|
// Workaround for div around div restricts height
|
|
// of inner div if outerdiv has hidden overflow
|
|
if (mxClient.IS_QUIRKS || this.content.nodeName.toUpperCase() != 'DIV')
|
|
{
|
|
this.contentWrapper.style.height = '100%';
|
|
}
|
|
|
|
// Puts all content into the DOM
|
|
this.td.appendChild(this.contentWrapper);
|
|
tr.appendChild(this.td);
|
|
tbody.appendChild(tr);
|
|
this.table.appendChild(tbody);
|
|
this.div.appendChild(this.table);
|
|
|
|
// Puts the window on top of other windows when clicked
|
|
var activator = mxUtils.bind(this, function(evt)
|
|
{
|
|
this.activate();
|
|
});
|
|
|
|
mxEvent.addGestureListeners(this.title, activator);
|
|
mxEvent.addGestureListeners(this.table, activator);
|
|
|
|
this.hide();
|
|
};
|
|
|
|
/**
|
|
* Function: setTitle
|
|
*
|
|
* Sets the window title to the given string. HTML markup inside the title
|
|
* will be escaped.
|
|
*/
|
|
mxWindow.prototype.setTitle = function(title)
|
|
{
|
|
// Removes all text content nodes (normally just one)
|
|
var child = this.title.firstChild;
|
|
|
|
while (child != null)
|
|
{
|
|
var next = child.nextSibling;
|
|
|
|
if (child.nodeType == mxConstants.NODETYPE_TEXT)
|
|
{
|
|
child.parentNode.removeChild(child);
|
|
}
|
|
|
|
child = next;
|
|
}
|
|
|
|
mxUtils.write(this.title, title || '');
|
|
this.title.appendChild(this.buttons);
|
|
};
|
|
|
|
/**
|
|
* Function: setScrollable
|
|
*
|
|
* Sets if the window contents should be scrollable.
|
|
*/
|
|
mxWindow.prototype.setScrollable = function(scrollable)
|
|
{
|
|
// Workaround for hang in Presto 2.5.22 (Opera 10.5)
|
|
if (navigator.userAgent == null ||
|
|
navigator.userAgent.indexOf('Presto/2.5') < 0)
|
|
{
|
|
if (scrollable)
|
|
{
|
|
this.contentWrapper.style.overflow = 'auto';
|
|
}
|
|
else
|
|
{
|
|
this.contentWrapper.style.overflow = 'hidden';
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Function: activate
|
|
*
|
|
* Puts the window on top of all other windows.
|
|
*/
|
|
mxWindow.prototype.activate = function()
|
|
{
|
|
if (mxWindow.activeWindow != this)
|
|
{
|
|
var style = mxUtils.getCurrentStyle(this.getElement());
|
|
var index = (style != null) ? style.zIndex : 3;
|
|
|
|
if (mxWindow.activeWindow)
|
|
{
|
|
var elt = mxWindow.activeWindow.getElement();
|
|
|
|
if (elt != null && elt.style != null)
|
|
{
|
|
elt.style.zIndex = index;
|
|
}
|
|
}
|
|
|
|
var previousWindow = mxWindow.activeWindow;
|
|
this.getElement().style.zIndex = parseInt(index) + 1;
|
|
mxWindow.activeWindow = this;
|
|
|
|
this.fireEvent(new mxEventObject(mxEvent.ACTIVATE, 'previousWindow', previousWindow));
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Function: getElement
|
|
*
|
|
* Returuns the outermost DOM node that makes up the window.
|
|
*/
|
|
mxWindow.prototype.getElement = function()
|
|
{
|
|
return this.div;
|
|
};
|
|
|
|
/**
|
|
* Function: fit
|
|
*
|
|
* Makes sure the window is inside the client area of the window.
|
|
*/
|
|
mxWindow.prototype.fit = function()
|
|
{
|
|
mxUtils.fit(this.div);
|
|
};
|
|
|
|
/**
|
|
* Function: isResizable
|
|
*
|
|
* Returns true if the window is resizable.
|
|
*/
|
|
mxWindow.prototype.isResizable = function()
|
|
{
|
|
if (this.resize != null)
|
|
{
|
|
return this.resize.style.display != 'none';
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
/**
|
|
* Function: setResizable
|
|
*
|
|
* Sets if the window should be resizable. To avoid interference with some
|
|
* built-in features of IE10 and later, the use of the following code is
|
|
* recommended if there are resizable <mxWindow>s in the page:
|
|
*
|
|
* (code)
|
|
* if (mxClient.IS_POINTER)
|
|
* {
|
|
* document.body.style.msTouchAction = 'none';
|
|
* }
|
|
* (end)
|
|
*/
|
|
mxWindow.prototype.setResizable = function(resizable)
|
|
{
|
|
if (resizable)
|
|
{
|
|
if (this.resize == null)
|
|
{
|
|
this.resize = document.createElement('img');
|
|
this.resize.style.position = 'absolute';
|
|
this.resize.style.bottom = '2px';
|
|
this.resize.style.right = '2px';
|
|
|
|
this.resize.setAttribute('src', this.resizeImage);
|
|
this.resize.style.cursor = 'nw-resize';
|
|
|
|
var startX = null;
|
|
var startY = null;
|
|
var width = null;
|
|
var height = null;
|
|
|
|
var start = mxUtils.bind(this, function(evt)
|
|
{
|
|
// LATER: pointerdown starting on border of resize does start
|
|
// the drag operation but does not fire consecutive events via
|
|
// one of the listeners below (does pan instead).
|
|
// Workaround: document.body.style.msTouchAction = 'none'
|
|
this.activate();
|
|
startX = mxEvent.getClientX(evt);
|
|
startY = mxEvent.getClientY(evt);
|
|
width = this.div.offsetWidth;
|
|
height = this.div.offsetHeight;
|
|
|
|
mxEvent.addGestureListeners(document, null, dragHandler, dropHandler);
|
|
this.fireEvent(new mxEventObject(mxEvent.RESIZE_START, 'event', evt));
|
|
mxEvent.consume(evt);
|
|
});
|
|
|
|
// Adds a temporary pair of listeners to intercept
|
|
// the gesture event in the document
|
|
var dragHandler = mxUtils.bind(this, function(evt)
|
|
{
|
|
if (startX != null && startY != null)
|
|
{
|
|
var dx = mxEvent.getClientX(evt) - startX;
|
|
var dy = mxEvent.getClientY(evt) - startY;
|
|
|
|
this.setSize(width + dx, height + dy);
|
|
|
|
this.fireEvent(new mxEventObject(mxEvent.RESIZE, 'event', evt));
|
|
mxEvent.consume(evt);
|
|
}
|
|
});
|
|
|
|
var dropHandler = mxUtils.bind(this, function(evt)
|
|
{
|
|
if (startX != null && startY != null)
|
|
{
|
|
startX = null;
|
|
startY = null;
|
|
mxEvent.removeGestureListeners(document, null, dragHandler, dropHandler);
|
|
this.fireEvent(new mxEventObject(mxEvent.RESIZE_END, 'event', evt));
|
|
mxEvent.consume(evt);
|
|
}
|
|
});
|
|
|
|
mxEvent.addGestureListeners(this.resize, start, dragHandler, dropHandler);
|
|
this.div.appendChild(this.resize);
|
|
}
|
|
else
|
|
{
|
|
this.resize.style.display = 'inline';
|
|
}
|
|
}
|
|
else if (this.resize != null)
|
|
{
|
|
this.resize.style.display = 'none';
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Function: setSize
|
|
*
|
|
* Sets the size of the window.
|
|
*/
|
|
mxWindow.prototype.setSize = function(width, height)
|
|
{
|
|
width = Math.max(this.minimumSize.width, width);
|
|
height = Math.max(this.minimumSize.height, height);
|
|
|
|
// Workaround for table size problems in FF
|
|
if (!mxClient.IS_QUIRKS)
|
|
{
|
|
this.div.style.width = width + 'px';
|
|
this.div.style.height = height + 'px';
|
|
}
|
|
|
|
this.table.style.width = width + 'px';
|
|
this.table.style.height = height + 'px';
|
|
|
|
if (!mxClient.IS_QUIRKS)
|
|
{
|
|
this.contentWrapper.style.height = (this.div.offsetHeight -
|
|
this.title.offsetHeight - this.contentHeightCorrection) + 'px';
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Function: setMinimizable
|
|
*
|
|
* Sets if the window is minimizable.
|
|
*/
|
|
mxWindow.prototype.setMinimizable = function(minimizable)
|
|
{
|
|
this.minimize.style.display = (minimizable) ? '' : 'none';
|
|
};
|
|
|
|
/**
|
|
* Function: getMinimumSize
|
|
*
|
|
* Returns an <mxRectangle> that specifies the size for the minimized window.
|
|
* A width or height of 0 means keep the existing width or height. This
|
|
* implementation returns the height of the window title and keeps the width.
|
|
*/
|
|
mxWindow.prototype.getMinimumSize = function()
|
|
{
|
|
return new mxRectangle(0, 0, 0, this.title.offsetHeight);
|
|
};
|
|
|
|
/**
|
|
* Function: installMinimizeHandler
|
|
*
|
|
* Installs the event listeners required for minimizing the window.
|
|
*/
|
|
mxWindow.prototype.installMinimizeHandler = function()
|
|
{
|
|
this.minimize = document.createElement('img');
|
|
|
|
this.minimize.setAttribute('src', this.minimizeImage);
|
|
this.minimize.setAttribute('title', 'Minimize');
|
|
this.minimize.style.cursor = 'pointer';
|
|
this.minimize.style.marginLeft = '2px';
|
|
this.minimize.style.display = 'none';
|
|
|
|
this.buttons.appendChild(this.minimize);
|
|
|
|
var minimized = false;
|
|
var maxDisplay = null;
|
|
var height = null;
|
|
|
|
var funct = mxUtils.bind(this, function(evt)
|
|
{
|
|
this.activate();
|
|
|
|
if (!minimized)
|
|
{
|
|
minimized = true;
|
|
|
|
this.minimize.setAttribute('src', this.normalizeImage);
|
|
this.minimize.setAttribute('title', 'Normalize');
|
|
this.contentWrapper.style.display = 'none';
|
|
maxDisplay = this.maximize.style.display;
|
|
|
|
this.maximize.style.display = 'none';
|
|
height = this.table.style.height;
|
|
|
|
var minSize = this.getMinimumSize();
|
|
|
|
if (minSize.height > 0)
|
|
{
|
|
if (!mxClient.IS_QUIRKS)
|
|
{
|
|
this.div.style.height = minSize.height + 'px';
|
|
}
|
|
|
|
this.table.style.height = minSize.height + 'px';
|
|
}
|
|
|
|
if (minSize.width > 0)
|
|
{
|
|
if (!mxClient.IS_QUIRKS)
|
|
{
|
|
this.div.style.width = minSize.width + 'px';
|
|
}
|
|
|
|
this.table.style.width = minSize.width + 'px';
|
|
}
|
|
|
|
if (this.resize != null)
|
|
{
|
|
this.resize.style.visibility = 'hidden';
|
|
}
|
|
|
|
this.fireEvent(new mxEventObject(mxEvent.MINIMIZE, 'event', evt));
|
|
}
|
|
else
|
|
{
|
|
minimized = false;
|
|
|
|
this.minimize.setAttribute('src', this.minimizeImage);
|
|
this.minimize.setAttribute('title', 'Minimize');
|
|
this.contentWrapper.style.display = ''; // default
|
|
this.maximize.style.display = maxDisplay;
|
|
|
|
if (!mxClient.IS_QUIRKS)
|
|
{
|
|
this.div.style.height = height;
|
|
}
|
|
|
|
this.table.style.height = height;
|
|
|
|
if (this.resize != null)
|
|
{
|
|
this.resize.style.visibility = '';
|
|
}
|
|
|
|
this.fireEvent(new mxEventObject(mxEvent.NORMALIZE, 'event', evt));
|
|
}
|
|
|
|
mxEvent.consume(evt);
|
|
});
|
|
|
|
mxEvent.addGestureListeners(this.minimize, funct);
|
|
};
|
|
|
|
/**
|
|
* Function: setMaximizable
|
|
*
|
|
* Sets if the window is maximizable.
|
|
*/
|
|
mxWindow.prototype.setMaximizable = function(maximizable)
|
|
{
|
|
this.maximize.style.display = (maximizable) ? '' : 'none';
|
|
};
|
|
|
|
/**
|
|
* Function: installMaximizeHandler
|
|
*
|
|
* Installs the event listeners required for maximizing the window.
|
|
*/
|
|
mxWindow.prototype.installMaximizeHandler = function()
|
|
{
|
|
this.maximize = document.createElement('img');
|
|
|
|
this.maximize.setAttribute('src', this.maximizeImage);
|
|
this.maximize.setAttribute('title', 'Maximize');
|
|
this.maximize.style.cursor = 'default';
|
|
this.maximize.style.marginLeft = '2px';
|
|
this.maximize.style.cursor = 'pointer';
|
|
this.maximize.style.display = 'none';
|
|
|
|
this.buttons.appendChild(this.maximize);
|
|
|
|
var maximized = false;
|
|
var x = null;
|
|
var y = null;
|
|
var height = null;
|
|
var width = null;
|
|
var minDisplay = null;
|
|
|
|
var funct = mxUtils.bind(this, function(evt)
|
|
{
|
|
this.activate();
|
|
|
|
if (this.maximize.style.display != 'none')
|
|
{
|
|
if (!maximized)
|
|
{
|
|
maximized = true;
|
|
|
|
this.maximize.setAttribute('src', this.normalizeImage);
|
|
this.maximize.setAttribute('title', 'Normalize');
|
|
this.contentWrapper.style.display = '';
|
|
minDisplay = this.minimize.style.display;
|
|
this.minimize.style.display = 'none';
|
|
|
|
// Saves window state
|
|
x = parseInt(this.div.style.left);
|
|
y = parseInt(this.div.style.top);
|
|
height = this.table.style.height;
|
|
width = this.table.style.width;
|
|
|
|
this.div.style.left = '0px';
|
|
this.div.style.top = '0px';
|
|
var docHeight = Math.max(document.body.clientHeight || 0, document.documentElement.clientHeight || 0);
|
|
|
|
if (!mxClient.IS_QUIRKS)
|
|
{
|
|
this.div.style.width = (document.body.clientWidth - 2) + 'px';
|
|
this.div.style.height = (docHeight - 2) + 'px';
|
|
}
|
|
|
|
this.table.style.width = (document.body.clientWidth - 2) + 'px';
|
|
this.table.style.height = (docHeight - 2) + 'px';
|
|
|
|
if (this.resize != null)
|
|
{
|
|
this.resize.style.visibility = 'hidden';
|
|
}
|
|
|
|
if (!mxClient.IS_QUIRKS)
|
|
{
|
|
var style = mxUtils.getCurrentStyle(this.contentWrapper);
|
|
|
|
if (style.overflow == 'auto' || this.resize != null)
|
|
{
|
|
this.contentWrapper.style.height = (this.div.offsetHeight -
|
|
this.title.offsetHeight - this.contentHeightCorrection) + 'px';
|
|
}
|
|
}
|
|
|
|
this.fireEvent(new mxEventObject(mxEvent.MAXIMIZE, 'event', evt));
|
|
}
|
|
else
|
|
{
|
|
maximized = false;
|
|
|
|
this.maximize.setAttribute('src', this.maximizeImage);
|
|
this.maximize.setAttribute('title', 'Maximize');
|
|
this.contentWrapper.style.display = '';
|
|
this.minimize.style.display = minDisplay;
|
|
|
|
// Restores window state
|
|
this.div.style.left = x+'px';
|
|
this.div.style.top = y+'px';
|
|
|
|
if (!mxClient.IS_QUIRKS)
|
|
{
|
|
this.div.style.height = height;
|
|
this.div.style.width = width;
|
|
|
|
var style = mxUtils.getCurrentStyle(this.contentWrapper);
|
|
|
|
if (style.overflow == 'auto' || this.resize != null)
|
|
{
|
|
this.contentWrapper.style.height = (this.div.offsetHeight -
|
|
this.title.offsetHeight - this.contentHeightCorrection) + 'px';
|
|
}
|
|
}
|
|
|
|
this.table.style.height = height;
|
|
this.table.style.width = width;
|
|
|
|
if (this.resize != null)
|
|
{
|
|
this.resize.style.visibility = '';
|
|
}
|
|
|
|
this.fireEvent(new mxEventObject(mxEvent.NORMALIZE, 'event', evt));
|
|
}
|
|
|
|
mxEvent.consume(evt);
|
|
}
|
|
});
|
|
|
|
mxEvent.addGestureListeners(this.maximize, funct);
|
|
mxEvent.addListener(this.title, 'dblclick', funct);
|
|
};
|
|
|
|
/**
|
|
* Function: installMoveHandler
|
|
*
|
|
* Installs the event listeners required for moving the window.
|
|
*/
|
|
mxWindow.prototype.installMoveHandler = function()
|
|
{
|
|
this.title.style.cursor = 'move';
|
|
|
|
mxEvent.addGestureListeners(this.title,
|
|
mxUtils.bind(this, function(evt)
|
|
{
|
|
var startX = mxEvent.getClientX(evt);
|
|
var startY = mxEvent.getClientY(evt);
|
|
var x = this.getX();
|
|
var y = this.getY();
|
|
|
|
// Adds a temporary pair of listeners to intercept
|
|
// the gesture event in the document
|
|
var dragHandler = mxUtils.bind(this, function(evt)
|
|
{
|
|
var dx = mxEvent.getClientX(evt) - startX;
|
|
var dy = mxEvent.getClientY(evt) - startY;
|
|
this.setLocation(x + dx, y + dy);
|
|
this.fireEvent(new mxEventObject(mxEvent.MOVE, 'event', evt));
|
|
mxEvent.consume(evt);
|
|
});
|
|
|
|
var dropHandler = mxUtils.bind(this, function(evt)
|
|
{
|
|
mxEvent.removeGestureListeners(document, null, dragHandler, dropHandler);
|
|
this.fireEvent(new mxEventObject(mxEvent.MOVE_END, 'event', evt));
|
|
mxEvent.consume(evt);
|
|
});
|
|
|
|
mxEvent.addGestureListeners(document, null, dragHandler, dropHandler);
|
|
this.fireEvent(new mxEventObject(mxEvent.MOVE_START, 'event', evt));
|
|
mxEvent.consume(evt);
|
|
}));
|
|
|
|
// Disables built-in pan and zoom in IE10 and later
|
|
if (mxClient.IS_POINTER)
|
|
{
|
|
this.title.style.touchAction = 'none';
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Function: setLocation
|
|
*
|
|
* Sets the upper, left corner of the window.
|
|
*/
|
|
mxWindow.prototype.setLocation = function(x, y)
|
|
{
|
|
this.div.style.left = x + 'px';
|
|
this.div.style.top = y + 'px';
|
|
};
|
|
|
|
/**
|
|
* Function: getX
|
|
*
|
|
* Returns the current position on the x-axis.
|
|
*/
|
|
mxWindow.prototype.getX = function()
|
|
{
|
|
return parseInt(this.div.style.left);
|
|
};
|
|
|
|
/**
|
|
* Function: getY
|
|
*
|
|
* Returns the current position on the y-axis.
|
|
*/
|
|
mxWindow.prototype.getY = function()
|
|
{
|
|
return parseInt(this.div.style.top);
|
|
};
|
|
|
|
/**
|
|
* Function: installCloseHandler
|
|
*
|
|
* Adds the <closeImage> as a new image node in <closeImg> and installs the
|
|
* <close> event.
|
|
*/
|
|
mxWindow.prototype.installCloseHandler = function()
|
|
{
|
|
this.closeImg = document.createElement('img');
|
|
|
|
this.closeImg.setAttribute('src', this.closeImage);
|
|
this.closeImg.setAttribute('title', 'Close');
|
|
this.closeImg.style.marginLeft = '2px';
|
|
this.closeImg.style.cursor = 'pointer';
|
|
this.closeImg.style.display = 'none';
|
|
|
|
this.buttons.appendChild(this.closeImg);
|
|
|
|
mxEvent.addGestureListeners(this.closeImg,
|
|
mxUtils.bind(this, function(evt)
|
|
{
|
|
this.fireEvent(new mxEventObject(mxEvent.CLOSE, 'event', evt));
|
|
|
|
if (this.destroyOnClose)
|
|
{
|
|
this.destroy();
|
|
}
|
|
else
|
|
{
|
|
this.setVisible(false);
|
|
}
|
|
|
|
mxEvent.consume(evt);
|
|
}));
|
|
};
|
|
|
|
/**
|
|
* Function: setImage
|
|
*
|
|
* Sets the image associated with the window.
|
|
*
|
|
* Parameters:
|
|
*
|
|
* image - URL of the image to be used.
|
|
*/
|
|
mxWindow.prototype.setImage = function(image)
|
|
{
|
|
this.image = document.createElement('img');
|
|
this.image.setAttribute('src', image);
|
|
this.image.setAttribute('align', 'left');
|
|
this.image.style.marginRight = '4px';
|
|
this.image.style.marginLeft = '0px';
|
|
this.image.style.marginTop = '-2px';
|
|
|
|
this.title.insertBefore(this.image, this.title.firstChild);
|
|
};
|
|
|
|
/**
|
|
* Function: setClosable
|
|
*
|
|
* Sets the image associated with the window.
|
|
*
|
|
* Parameters:
|
|
*
|
|
* closable - Boolean specifying if the window should be closable.
|
|
*/
|
|
mxWindow.prototype.setClosable = function(closable)
|
|
{
|
|
this.closeImg.style.display = (closable) ? '' : 'none';
|
|
};
|
|
|
|
/**
|
|
* Function: isVisible
|
|
*
|
|
* Returns true if the window is visible.
|
|
*/
|
|
mxWindow.prototype.isVisible = function()
|
|
{
|
|
if (this.div != null)
|
|
{
|
|
return this.div.style.display != 'none';
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
/**
|
|
* Function: setVisible
|
|
*
|
|
* Shows or hides the window depending on the given flag.
|
|
*
|
|
* Parameters:
|
|
*
|
|
* visible - Boolean indicating if the window should be made visible.
|
|
*/
|
|
mxWindow.prototype.setVisible = function(visible)
|
|
{
|
|
if (this.div != null && this.isVisible() != visible)
|
|
{
|
|
if (visible)
|
|
{
|
|
this.show();
|
|
}
|
|
else
|
|
{
|
|
this.hide();
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Function: show
|
|
*
|
|
* Shows the window.
|
|
*/
|
|
mxWindow.prototype.show = function()
|
|
{
|
|
this.div.style.display = '';
|
|
this.activate();
|
|
|
|
var style = mxUtils.getCurrentStyle(this.contentWrapper);
|
|
|
|
if (!mxClient.IS_QUIRKS && (style.overflow == 'auto' || this.resize != null) &&
|
|
this.contentWrapper.style.display != 'none')
|
|
{
|
|
this.contentWrapper.style.height = (this.div.offsetHeight -
|
|
this.title.offsetHeight - this.contentHeightCorrection) + 'px';
|
|
}
|
|
|
|
this.fireEvent(new mxEventObject(mxEvent.SHOW));
|
|
};
|
|
|
|
/**
|
|
* Function: hide
|
|
*
|
|
* Hides the window.
|
|
*/
|
|
mxWindow.prototype.hide = function()
|
|
{
|
|
this.div.style.display = 'none';
|
|
this.fireEvent(new mxEventObject(mxEvent.HIDE));
|
|
};
|
|
|
|
/**
|
|
* Function: destroy
|
|
*
|
|
* Destroys the window and removes all associated resources. Fires a
|
|
* <destroy> event prior to destroying the window.
|
|
*/
|
|
mxWindow.prototype.destroy = function()
|
|
{
|
|
this.fireEvent(new mxEventObject(mxEvent.DESTROY));
|
|
|
|
if (this.div != null)
|
|
{
|
|
mxEvent.release(this.div);
|
|
this.div.parentNode.removeChild(this.div);
|
|
this.div = null;
|
|
}
|
|
|
|
this.title = null;
|
|
this.content = null;
|
|
this.contentWrapper = null;
|
|
};
|