mxWindow.js 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132
  1. /**
  2. * Copyright (c) 2006-2015, JGraph Ltd
  3. * Copyright (c) 2006-2015, Gaudenz Alder
  4. */
  5. /**
  6. * Class: mxWindow
  7. *
  8. * Basic window inside a document.
  9. *
  10. * Examples:
  11. *
  12. * Creating a simple window.
  13. *
  14. * (code)
  15. * var tb = document.createElement('div');
  16. * var wnd = new mxWindow('Title', tb, 100, 100, 200, 200, true, true);
  17. * wnd.setVisible(true);
  18. * (end)
  19. *
  20. * Creating a window that contains an iframe.
  21. *
  22. * (code)
  23. * var frame = document.createElement('iframe');
  24. * frame.setAttribute('width', '192px');
  25. * frame.setAttribute('height', '172px');
  26. * frame.setAttribute('src', 'http://www.example.com/');
  27. * frame.style.backgroundColor = 'white';
  28. *
  29. * var w = document.body.clientWidth;
  30. * var h = (document.body.clientHeight || document.documentElement.clientHeight);
  31. * var wnd = new mxWindow('Title', frame, (w-200)/2, (h-200)/3, 200, 200);
  32. * wnd.setVisible(true);
  33. * (end)
  34. *
  35. * To limit the movement of a window, eg. to keep it from being moved beyond
  36. * the top, left corner the following method can be overridden (recommended):
  37. *
  38. * (code)
  39. * wnd.setLocation = function(x, y)
  40. * {
  41. * x = Math.max(0, x);
  42. * y = Math.max(0, y);
  43. * mxWindow.prototype.setLocation.apply(this, arguments);
  44. * };
  45. * (end)
  46. *
  47. * Or the following event handler can be used:
  48. *
  49. * (code)
  50. * wnd.addListener(mxEvent.MOVE, function(e)
  51. * {
  52. * wnd.setLocation(Math.max(0, wnd.getX()), Math.max(0, wnd.getY()));
  53. * });
  54. * (end)
  55. *
  56. * To keep a window inside the current window:
  57. *
  58. * (code)
  59. * mxEvent.addListener(window, 'resize', mxUtils.bind(this, function()
  60. * {
  61. * var iw = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
  62. * var ih = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
  63. *
  64. * var x = this.window.getX();
  65. * var y = this.window.getY();
  66. *
  67. * if (x + this.window.table.clientWidth > iw)
  68. * {
  69. * x = Math.max(0, iw - this.window.table.clientWidth);
  70. * }
  71. *
  72. * if (y + this.window.table.clientHeight > ih)
  73. * {
  74. * y = Math.max(0, ih - this.window.table.clientHeight);
  75. * }
  76. *
  77. * if (this.window.getX() != x || this.window.getY() != y)
  78. * {
  79. * this.window.setLocation(x, y);
  80. * }
  81. * }));
  82. * (end)
  83. *
  84. * Event: mxEvent.MOVE_START
  85. *
  86. * Fires before the window is moved. The <code>event</code> property contains
  87. * the corresponding mouse event.
  88. *
  89. * Event: mxEvent.MOVE
  90. *
  91. * Fires while the window is being moved. The <code>event</code> property
  92. * contains the corresponding mouse event.
  93. *
  94. * Event: mxEvent.MOVE_END
  95. *
  96. * Fires after the window is moved. The <code>event</code> property contains
  97. * the corresponding mouse event.
  98. *
  99. * Event: mxEvent.RESIZE_START
  100. *
  101. * Fires before the window is resized. The <code>event</code> property contains
  102. * the corresponding mouse event.
  103. *
  104. * Event: mxEvent.RESIZE
  105. *
  106. * Fires while the window is being resized. The <code>event</code> property
  107. * contains the corresponding mouse event.
  108. *
  109. * Event: mxEvent.RESIZE_END
  110. *
  111. * Fires after the window is resized. The <code>event</code> property contains
  112. * the corresponding mouse event.
  113. *
  114. * Event: mxEvent.MAXIMIZE
  115. *
  116. * Fires after the window is maximized. The <code>event</code> property
  117. * contains the corresponding mouse event.
  118. *
  119. * Event: mxEvent.MINIMIZE
  120. *
  121. * Fires after the window is minimized. The <code>event</code> property
  122. * contains the corresponding mouse event.
  123. *
  124. * Event: mxEvent.NORMALIZE
  125. *
  126. * Fires after the window is normalized, that is, it returned from
  127. * maximized or minimized state. The <code>event</code> property contains the
  128. * corresponding mouse event.
  129. *
  130. * Event: mxEvent.ACTIVATE
  131. *
  132. * Fires after a window is activated. The <code>previousWindow</code> property
  133. * contains the previous window. The event sender is the active window.
  134. *
  135. * Event: mxEvent.SHOW
  136. *
  137. * Fires after the window is shown. This event has no properties.
  138. *
  139. * Event: mxEvent.HIDE
  140. *
  141. * Fires after the window is hidden. This event has no properties.
  142. *
  143. * Event: mxEvent.CLOSE
  144. *
  145. * Fires before the window is closed. The <code>event</code> property contains
  146. * the corresponding mouse event.
  147. *
  148. * Event: mxEvent.DESTROY
  149. *
  150. * Fires before the window is destroyed. This event has no properties.
  151. *
  152. * Constructor: mxWindow
  153. *
  154. * Constructs a new window with the given dimension and title to display
  155. * the specified content. The window elements use the given style as a
  156. * prefix for the classnames of the respective window elements, namely,
  157. * the window title and window pane. The respective postfixes are appended
  158. * to the given stylename as follows:
  159. *
  160. * style - Base style for the window.
  161. * style+Title - Style for the window title.
  162. * style+Pane - Style for the window pane.
  163. *
  164. * The default value for style is mxWindow, resulting in the following
  165. * classnames for the window elements: mxWindow, mxWindowTitle and
  166. * mxWindowPane.
  167. *
  168. * If replaceNode is given then the window replaces the given DOM node in
  169. * the document.
  170. *
  171. * Parameters:
  172. *
  173. * title - String that represents the title of the new window.
  174. * content - DOM node that is used as the window content.
  175. * x - X-coordinate of the window location.
  176. * y - Y-coordinate of the window location.
  177. * width - Width of the window.
  178. * height - Optional height of the window. Default is to match the height
  179. * of the content at the specified width.
  180. * minimizable - Optional boolean indicating if the window is minimizable.
  181. * Default is true.
  182. * movable - Optional boolean indicating if the window is movable. Default
  183. * is true.
  184. * replaceNode - Optional DOM node that the window should replace.
  185. * style - Optional base classname for the window elements. Default is
  186. * mxWindow.
  187. */
  188. function mxWindow(title, content, x, y, width, height, minimizable, movable, replaceNode, style)
  189. {
  190. if (content != null)
  191. {
  192. minimizable = (minimizable != null) ? minimizable : true;
  193. this.content = content;
  194. this.init(x, y, width, height, style);
  195. this.installMaximizeHandler();
  196. this.installMinimizeHandler();
  197. this.installCloseHandler();
  198. this.setMinimizable(minimizable);
  199. this.setTitle(title);
  200. if (movable == null || movable)
  201. {
  202. this.installMoveHandler();
  203. }
  204. if (replaceNode != null && replaceNode.parentNode != null)
  205. {
  206. replaceNode.parentNode.replaceChild(this.div, replaceNode);
  207. }
  208. else
  209. {
  210. document.body.appendChild(this.div);
  211. }
  212. }
  213. };
  214. /**
  215. * Extends mxEventSource.
  216. */
  217. mxWindow.prototype = new mxEventSource();
  218. mxWindow.prototype.constructor = mxWindow;
  219. /**
  220. * Variable: closeImage
  221. *
  222. * URL of the image to be used for the close icon in the titlebar.
  223. */
  224. mxWindow.prototype.closeImage = mxClient.imageBasePath + '/close.gif';
  225. /**
  226. * Variable: minimizeImage
  227. *
  228. * URL of the image to be used for the minimize icon in the titlebar.
  229. */
  230. mxWindow.prototype.minimizeImage = mxClient.imageBasePath + '/minimize.gif';
  231. /**
  232. * Variable: normalizeImage
  233. *
  234. * URL of the image to be used for the normalize icon in the titlebar.
  235. */
  236. mxWindow.prototype.normalizeImage = mxClient.imageBasePath + '/normalize.gif';
  237. /**
  238. * Variable: maximizeImage
  239. *
  240. * URL of the image to be used for the maximize icon in the titlebar.
  241. */
  242. mxWindow.prototype.maximizeImage = mxClient.imageBasePath + '/maximize.gif';
  243. /**
  244. * Variable: resizeImage
  245. *
  246. * URL of the image to be used for the resize icon.
  247. */
  248. mxWindow.prototype.resizeImage = mxClient.imageBasePath + '/resize.gif';
  249. /**
  250. * Variable: visible
  251. *
  252. * Boolean flag that represents the visible state of the window.
  253. */
  254. mxWindow.prototype.visible = false;
  255. /**
  256. * Variable: minimumSize
  257. *
  258. * <mxRectangle> that specifies the minimum width and height of the window.
  259. * Default is (50, 40).
  260. */
  261. mxWindow.prototype.minimumSize = new mxRectangle(0, 0, 50, 40);
  262. /**
  263. * Variable: destroyOnClose
  264. *
  265. * Specifies if the window should be destroyed when it is closed. If this
  266. * is false then the window is hidden using <setVisible>. Default is true.
  267. */
  268. mxWindow.prototype.destroyOnClose = true;
  269. /**
  270. * Variable: contentHeightCorrection
  271. *
  272. * Defines the correction factor for computing the height of the contentWrapper.
  273. * Default is 6 for IE 7/8 standards mode and 2 for all other browsers and modes.
  274. */
  275. mxWindow.prototype.contentHeightCorrection = (document.documentMode == 8 || document.documentMode == 7) ? 6 : 2;
  276. /**
  277. * Variable: title
  278. *
  279. * Reference to the DOM node (TD) that contains the title.
  280. */
  281. mxWindow.prototype.title = null;
  282. /**
  283. * Variable: content
  284. *
  285. * Reference to the DOM node that represents the window content.
  286. */
  287. mxWindow.prototype.content = null;
  288. /**
  289. * Function: init
  290. *
  291. * Initializes the DOM tree that represents the window.
  292. */
  293. mxWindow.prototype.init = function(x, y, width, height, style)
  294. {
  295. style = (style != null) ? style : 'mxWindow';
  296. this.div = document.createElement('div');
  297. this.div.className = style;
  298. this.div.style.left = x + 'px';
  299. this.div.style.top = y + 'px';
  300. this.table = document.createElement('table');
  301. this.table.className = style;
  302. // Disables built-in pan and zoom in IE10 and later
  303. if (mxClient.IS_POINTER)
  304. {
  305. this.div.style.touchAction = 'none';
  306. }
  307. // Workaround for table size problems in FF
  308. if (width != null)
  309. {
  310. if (!mxClient.IS_QUIRKS)
  311. {
  312. this.div.style.width = width + 'px';
  313. }
  314. this.table.style.width = width + 'px';
  315. }
  316. if (height != null)
  317. {
  318. if (!mxClient.IS_QUIRKS)
  319. {
  320. this.div.style.height = height + 'px';
  321. }
  322. this.table.style.height = height + 'px';
  323. }
  324. // Creates title row
  325. var tbody = document.createElement('tbody');
  326. var tr = document.createElement('tr');
  327. this.title = document.createElement('td');
  328. this.title.className = style + 'Title';
  329. this.buttons = document.createElement('div');
  330. this.buttons.style.position = 'absolute';
  331. this.buttons.style.display = 'inline-block';
  332. this.buttons.style.right = '4px';
  333. this.buttons.style.top = '5px';
  334. this.title.appendChild(this.buttons);
  335. tr.appendChild(this.title);
  336. tbody.appendChild(tr);
  337. // Creates content row and table cell
  338. tr = document.createElement('tr');
  339. this.td = document.createElement('td');
  340. this.td.className = style + 'Pane';
  341. if (document.documentMode == 7)
  342. {
  343. this.td.style.height = '100%';
  344. }
  345. this.contentWrapper = document.createElement('div');
  346. this.contentWrapper.className = style + 'Pane';
  347. this.contentWrapper.style.width = '100%';
  348. this.contentWrapper.appendChild(this.content);
  349. // Workaround for div around div restricts height
  350. // of inner div if outerdiv has hidden overflow
  351. if (mxClient.IS_QUIRKS || this.content.nodeName.toUpperCase() != 'DIV')
  352. {
  353. this.contentWrapper.style.height = '100%';
  354. }
  355. // Puts all content into the DOM
  356. this.td.appendChild(this.contentWrapper);
  357. tr.appendChild(this.td);
  358. tbody.appendChild(tr);
  359. this.table.appendChild(tbody);
  360. this.div.appendChild(this.table);
  361. // Puts the window on top of other windows when clicked
  362. var activator = mxUtils.bind(this, function(evt)
  363. {
  364. this.activate();
  365. });
  366. mxEvent.addGestureListeners(this.title, activator);
  367. mxEvent.addGestureListeners(this.table, activator);
  368. this.hide();
  369. };
  370. /**
  371. * Function: setTitle
  372. *
  373. * Sets the window title to the given string. HTML markup inside the title
  374. * will be escaped.
  375. */
  376. mxWindow.prototype.setTitle = function(title)
  377. {
  378. // Removes all text content nodes (normally just one)
  379. var child = this.title.firstChild;
  380. while (child != null)
  381. {
  382. var next = child.nextSibling;
  383. if (child.nodeType == mxConstants.NODETYPE_TEXT)
  384. {
  385. child.parentNode.removeChild(child);
  386. }
  387. child = next;
  388. }
  389. mxUtils.write(this.title, title || '');
  390. this.title.appendChild(this.buttons);
  391. };
  392. /**
  393. * Function: setScrollable
  394. *
  395. * Sets if the window contents should be scrollable.
  396. */
  397. mxWindow.prototype.setScrollable = function(scrollable)
  398. {
  399. // Workaround for hang in Presto 2.5.22 (Opera 10.5)
  400. if (navigator.userAgent == null ||
  401. navigator.userAgent.indexOf('Presto/2.5') < 0)
  402. {
  403. if (scrollable)
  404. {
  405. this.contentWrapper.style.overflow = 'auto';
  406. }
  407. else
  408. {
  409. this.contentWrapper.style.overflow = 'hidden';
  410. }
  411. }
  412. };
  413. /**
  414. * Function: activate
  415. *
  416. * Puts the window on top of all other windows.
  417. */
  418. mxWindow.prototype.activate = function()
  419. {
  420. if (mxWindow.activeWindow != this)
  421. {
  422. var style = mxUtils.getCurrentStyle(this.getElement());
  423. var index = (style != null) ? style.zIndex : 3;
  424. if (mxWindow.activeWindow)
  425. {
  426. var elt = mxWindow.activeWindow.getElement();
  427. if (elt != null && elt.style != null)
  428. {
  429. elt.style.zIndex = index;
  430. }
  431. }
  432. var previousWindow = mxWindow.activeWindow;
  433. this.getElement().style.zIndex = parseInt(index) + 1;
  434. mxWindow.activeWindow = this;
  435. this.fireEvent(new mxEventObject(mxEvent.ACTIVATE, 'previousWindow', previousWindow));
  436. }
  437. };
  438. /**
  439. * Function: getElement
  440. *
  441. * Returuns the outermost DOM node that makes up the window.
  442. */
  443. mxWindow.prototype.getElement = function()
  444. {
  445. return this.div;
  446. };
  447. /**
  448. * Function: fit
  449. *
  450. * Makes sure the window is inside the client area of the window.
  451. */
  452. mxWindow.prototype.fit = function()
  453. {
  454. mxUtils.fit(this.div);
  455. };
  456. /**
  457. * Function: isResizable
  458. *
  459. * Returns true if the window is resizable.
  460. */
  461. mxWindow.prototype.isResizable = function()
  462. {
  463. if (this.resize != null)
  464. {
  465. return this.resize.style.display != 'none';
  466. }
  467. return false;
  468. };
  469. /**
  470. * Function: setResizable
  471. *
  472. * Sets if the window should be resizable. To avoid interference with some
  473. * built-in features of IE10 and later, the use of the following code is
  474. * recommended if there are resizable <mxWindow>s in the page:
  475. *
  476. * (code)
  477. * if (mxClient.IS_POINTER)
  478. * {
  479. * document.body.style.msTouchAction = 'none';
  480. * }
  481. * (end)
  482. */
  483. mxWindow.prototype.setResizable = function(resizable)
  484. {
  485. if (resizable)
  486. {
  487. if (this.resize == null)
  488. {
  489. this.resize = document.createElement('img');
  490. this.resize.style.position = 'absolute';
  491. this.resize.style.bottom = '2px';
  492. this.resize.style.right = '2px';
  493. this.resize.setAttribute('src', this.resizeImage);
  494. this.resize.style.cursor = 'nw-resize';
  495. var startX = null;
  496. var startY = null;
  497. var width = null;
  498. var height = null;
  499. var start = mxUtils.bind(this, function(evt)
  500. {
  501. // LATER: pointerdown starting on border of resize does start
  502. // the drag operation but does not fire consecutive events via
  503. // one of the listeners below (does pan instead).
  504. // Workaround: document.body.style.msTouchAction = 'none'
  505. this.activate();
  506. startX = mxEvent.getClientX(evt);
  507. startY = mxEvent.getClientY(evt);
  508. width = this.div.offsetWidth;
  509. height = this.div.offsetHeight;
  510. mxEvent.addGestureListeners(document, null, dragHandler, dropHandler);
  511. this.fireEvent(new mxEventObject(mxEvent.RESIZE_START, 'event', evt));
  512. mxEvent.consume(evt);
  513. });
  514. // Adds a temporary pair of listeners to intercept
  515. // the gesture event in the document
  516. var dragHandler = mxUtils.bind(this, function(evt)
  517. {
  518. if (startX != null && startY != null)
  519. {
  520. var dx = mxEvent.getClientX(evt) - startX;
  521. var dy = mxEvent.getClientY(evt) - startY;
  522. this.setSize(width + dx, height + dy);
  523. this.fireEvent(new mxEventObject(mxEvent.RESIZE, 'event', evt));
  524. mxEvent.consume(evt);
  525. }
  526. });
  527. var dropHandler = mxUtils.bind(this, function(evt)
  528. {
  529. if (startX != null && startY != null)
  530. {
  531. startX = null;
  532. startY = null;
  533. mxEvent.removeGestureListeners(document, null, dragHandler, dropHandler);
  534. this.fireEvent(new mxEventObject(mxEvent.RESIZE_END, 'event', evt));
  535. mxEvent.consume(evt);
  536. }
  537. });
  538. mxEvent.addGestureListeners(this.resize, start, dragHandler, dropHandler);
  539. this.div.appendChild(this.resize);
  540. }
  541. else
  542. {
  543. this.resize.style.display = 'inline';
  544. }
  545. }
  546. else if (this.resize != null)
  547. {
  548. this.resize.style.display = 'none';
  549. }
  550. };
  551. /**
  552. * Function: setSize
  553. *
  554. * Sets the size of the window.
  555. */
  556. mxWindow.prototype.setSize = function(width, height)
  557. {
  558. width = Math.max(this.minimumSize.width, width);
  559. height = Math.max(this.minimumSize.height, height);
  560. // Workaround for table size problems in FF
  561. if (!mxClient.IS_QUIRKS)
  562. {
  563. this.div.style.width = width + 'px';
  564. this.div.style.height = height + 'px';
  565. }
  566. this.table.style.width = width + 'px';
  567. this.table.style.height = height + 'px';
  568. if (!mxClient.IS_QUIRKS)
  569. {
  570. this.contentWrapper.style.height = (this.div.offsetHeight -
  571. this.title.offsetHeight - this.contentHeightCorrection) + 'px';
  572. }
  573. };
  574. /**
  575. * Function: setMinimizable
  576. *
  577. * Sets if the window is minimizable.
  578. */
  579. mxWindow.prototype.setMinimizable = function(minimizable)
  580. {
  581. this.minimize.style.display = (minimizable) ? '' : 'none';
  582. };
  583. /**
  584. * Function: getMinimumSize
  585. *
  586. * Returns an <mxRectangle> that specifies the size for the minimized window.
  587. * A width or height of 0 means keep the existing width or height. This
  588. * implementation returns the height of the window title and keeps the width.
  589. */
  590. mxWindow.prototype.getMinimumSize = function()
  591. {
  592. return new mxRectangle(0, 0, 0, this.title.offsetHeight);
  593. };
  594. /**
  595. * Function: installMinimizeHandler
  596. *
  597. * Installs the event listeners required for minimizing the window.
  598. */
  599. mxWindow.prototype.installMinimizeHandler = function()
  600. {
  601. this.minimize = document.createElement('img');
  602. this.minimize.setAttribute('src', this.minimizeImage);
  603. this.minimize.setAttribute('title', 'Minimize');
  604. this.minimize.style.cursor = 'pointer';
  605. this.minimize.style.marginLeft = '2px';
  606. this.minimize.style.display = 'none';
  607. this.buttons.appendChild(this.minimize);
  608. var minimized = false;
  609. var maxDisplay = null;
  610. var height = null;
  611. var funct = mxUtils.bind(this, function(evt)
  612. {
  613. this.activate();
  614. if (!minimized)
  615. {
  616. minimized = true;
  617. this.minimize.setAttribute('src', this.normalizeImage);
  618. this.minimize.setAttribute('title', 'Normalize');
  619. this.contentWrapper.style.display = 'none';
  620. maxDisplay = this.maximize.style.display;
  621. this.maximize.style.display = 'none';
  622. height = this.table.style.height;
  623. var minSize = this.getMinimumSize();
  624. if (minSize.height > 0)
  625. {
  626. if (!mxClient.IS_QUIRKS)
  627. {
  628. this.div.style.height = minSize.height + 'px';
  629. }
  630. this.table.style.height = minSize.height + 'px';
  631. }
  632. if (minSize.width > 0)
  633. {
  634. if (!mxClient.IS_QUIRKS)
  635. {
  636. this.div.style.width = minSize.width + 'px';
  637. }
  638. this.table.style.width = minSize.width + 'px';
  639. }
  640. if (this.resize != null)
  641. {
  642. this.resize.style.visibility = 'hidden';
  643. }
  644. this.fireEvent(new mxEventObject(mxEvent.MINIMIZE, 'event', evt));
  645. }
  646. else
  647. {
  648. minimized = false;
  649. this.minimize.setAttribute('src', this.minimizeImage);
  650. this.minimize.setAttribute('title', 'Minimize');
  651. this.contentWrapper.style.display = ''; // default
  652. this.maximize.style.display = maxDisplay;
  653. if (!mxClient.IS_QUIRKS)
  654. {
  655. this.div.style.height = height;
  656. }
  657. this.table.style.height = height;
  658. if (this.resize != null)
  659. {
  660. this.resize.style.visibility = '';
  661. }
  662. this.fireEvent(new mxEventObject(mxEvent.NORMALIZE, 'event', evt));
  663. }
  664. mxEvent.consume(evt);
  665. });
  666. mxEvent.addGestureListeners(this.minimize, funct);
  667. };
  668. /**
  669. * Function: setMaximizable
  670. *
  671. * Sets if the window is maximizable.
  672. */
  673. mxWindow.prototype.setMaximizable = function(maximizable)
  674. {
  675. this.maximize.style.display = (maximizable) ? '' : 'none';
  676. };
  677. /**
  678. * Function: installMaximizeHandler
  679. *
  680. * Installs the event listeners required for maximizing the window.
  681. */
  682. mxWindow.prototype.installMaximizeHandler = function()
  683. {
  684. this.maximize = document.createElement('img');
  685. this.maximize.setAttribute('src', this.maximizeImage);
  686. this.maximize.setAttribute('title', 'Maximize');
  687. this.maximize.style.cursor = 'default';
  688. this.maximize.style.marginLeft = '2px';
  689. this.maximize.style.cursor = 'pointer';
  690. this.maximize.style.display = 'none';
  691. this.buttons.appendChild(this.maximize);
  692. var maximized = false;
  693. var x = null;
  694. var y = null;
  695. var height = null;
  696. var width = null;
  697. var minDisplay = null;
  698. var funct = mxUtils.bind(this, function(evt)
  699. {
  700. this.activate();
  701. if (this.maximize.style.display != 'none')
  702. {
  703. if (!maximized)
  704. {
  705. maximized = true;
  706. this.maximize.setAttribute('src', this.normalizeImage);
  707. this.maximize.setAttribute('title', 'Normalize');
  708. this.contentWrapper.style.display = '';
  709. minDisplay = this.minimize.style.display;
  710. this.minimize.style.display = 'none';
  711. // Saves window state
  712. x = parseInt(this.div.style.left);
  713. y = parseInt(this.div.style.top);
  714. height = this.table.style.height;
  715. width = this.table.style.width;
  716. this.div.style.left = '0px';
  717. this.div.style.top = '0px';
  718. var docHeight = Math.max(document.body.clientHeight || 0, document.documentElement.clientHeight || 0);
  719. if (!mxClient.IS_QUIRKS)
  720. {
  721. this.div.style.width = (document.body.clientWidth - 2) + 'px';
  722. this.div.style.height = (docHeight - 2) + 'px';
  723. }
  724. this.table.style.width = (document.body.clientWidth - 2) + 'px';
  725. this.table.style.height = (docHeight - 2) + 'px';
  726. if (this.resize != null)
  727. {
  728. this.resize.style.visibility = 'hidden';
  729. }
  730. if (!mxClient.IS_QUIRKS)
  731. {
  732. var style = mxUtils.getCurrentStyle(this.contentWrapper);
  733. if (style.overflow == 'auto' || this.resize != null)
  734. {
  735. this.contentWrapper.style.height = (this.div.offsetHeight -
  736. this.title.offsetHeight - this.contentHeightCorrection) + 'px';
  737. }
  738. }
  739. this.fireEvent(new mxEventObject(mxEvent.MAXIMIZE, 'event', evt));
  740. }
  741. else
  742. {
  743. maximized = false;
  744. this.maximize.setAttribute('src', this.maximizeImage);
  745. this.maximize.setAttribute('title', 'Maximize');
  746. this.contentWrapper.style.display = '';
  747. this.minimize.style.display = minDisplay;
  748. // Restores window state
  749. this.div.style.left = x+'px';
  750. this.div.style.top = y+'px';
  751. if (!mxClient.IS_QUIRKS)
  752. {
  753. this.div.style.height = height;
  754. this.div.style.width = width;
  755. var style = mxUtils.getCurrentStyle(this.contentWrapper);
  756. if (style.overflow == 'auto' || this.resize != null)
  757. {
  758. this.contentWrapper.style.height = (this.div.offsetHeight -
  759. this.title.offsetHeight - this.contentHeightCorrection) + 'px';
  760. }
  761. }
  762. this.table.style.height = height;
  763. this.table.style.width = width;
  764. if (this.resize != null)
  765. {
  766. this.resize.style.visibility = '';
  767. }
  768. this.fireEvent(new mxEventObject(mxEvent.NORMALIZE, 'event', evt));
  769. }
  770. mxEvent.consume(evt);
  771. }
  772. });
  773. mxEvent.addGestureListeners(this.maximize, funct);
  774. mxEvent.addListener(this.title, 'dblclick', funct);
  775. };
  776. /**
  777. * Function: installMoveHandler
  778. *
  779. * Installs the event listeners required for moving the window.
  780. */
  781. mxWindow.prototype.installMoveHandler = function()
  782. {
  783. this.title.style.cursor = 'move';
  784. mxEvent.addGestureListeners(this.title,
  785. mxUtils.bind(this, function(evt)
  786. {
  787. var startX = mxEvent.getClientX(evt);
  788. var startY = mxEvent.getClientY(evt);
  789. var x = this.getX();
  790. var y = this.getY();
  791. // Adds a temporary pair of listeners to intercept
  792. // the gesture event in the document
  793. var dragHandler = mxUtils.bind(this, function(evt)
  794. {
  795. var dx = mxEvent.getClientX(evt) - startX;
  796. var dy = mxEvent.getClientY(evt) - startY;
  797. this.setLocation(x + dx, y + dy);
  798. this.fireEvent(new mxEventObject(mxEvent.MOVE, 'event', evt));
  799. mxEvent.consume(evt);
  800. });
  801. var dropHandler = mxUtils.bind(this, function(evt)
  802. {
  803. mxEvent.removeGestureListeners(document, null, dragHandler, dropHandler);
  804. this.fireEvent(new mxEventObject(mxEvent.MOVE_END, 'event', evt));
  805. mxEvent.consume(evt);
  806. });
  807. mxEvent.addGestureListeners(document, null, dragHandler, dropHandler);
  808. this.fireEvent(new mxEventObject(mxEvent.MOVE_START, 'event', evt));
  809. mxEvent.consume(evt);
  810. }));
  811. // Disables built-in pan and zoom in IE10 and later
  812. if (mxClient.IS_POINTER)
  813. {
  814. this.title.style.touchAction = 'none';
  815. }
  816. };
  817. /**
  818. * Function: setLocation
  819. *
  820. * Sets the upper, left corner of the window.
  821. */
  822. mxWindow.prototype.setLocation = function(x, y)
  823. {
  824. this.div.style.left = x + 'px';
  825. this.div.style.top = y + 'px';
  826. };
  827. /**
  828. * Function: getX
  829. *
  830. * Returns the current position on the x-axis.
  831. */
  832. mxWindow.prototype.getX = function()
  833. {
  834. return parseInt(this.div.style.left);
  835. };
  836. /**
  837. * Function: getY
  838. *
  839. * Returns the current position on the y-axis.
  840. */
  841. mxWindow.prototype.getY = function()
  842. {
  843. return parseInt(this.div.style.top);
  844. };
  845. /**
  846. * Function: installCloseHandler
  847. *
  848. * Adds the <closeImage> as a new image node in <closeImg> and installs the
  849. * <close> event.
  850. */
  851. mxWindow.prototype.installCloseHandler = function()
  852. {
  853. this.closeImg = document.createElement('img');
  854. this.closeImg.setAttribute('src', this.closeImage);
  855. this.closeImg.setAttribute('title', 'Close');
  856. this.closeImg.style.marginLeft = '2px';
  857. this.closeImg.style.cursor = 'pointer';
  858. this.closeImg.style.display = 'none';
  859. this.buttons.appendChild(this.closeImg);
  860. mxEvent.addGestureListeners(this.closeImg,
  861. mxUtils.bind(this, function(evt)
  862. {
  863. this.fireEvent(new mxEventObject(mxEvent.CLOSE, 'event', evt));
  864. if (this.destroyOnClose)
  865. {
  866. this.destroy();
  867. }
  868. else
  869. {
  870. this.setVisible(false);
  871. }
  872. mxEvent.consume(evt);
  873. }));
  874. };
  875. /**
  876. * Function: setImage
  877. *
  878. * Sets the image associated with the window.
  879. *
  880. * Parameters:
  881. *
  882. * image - URL of the image to be used.
  883. */
  884. mxWindow.prototype.setImage = function(image)
  885. {
  886. this.image = document.createElement('img');
  887. this.image.setAttribute('src', image);
  888. this.image.setAttribute('align', 'left');
  889. this.image.style.marginRight = '4px';
  890. this.image.style.marginLeft = '0px';
  891. this.image.style.marginTop = '-2px';
  892. this.title.insertBefore(this.image, this.title.firstChild);
  893. };
  894. /**
  895. * Function: setClosable
  896. *
  897. * Sets the image associated with the window.
  898. *
  899. * Parameters:
  900. *
  901. * closable - Boolean specifying if the window should be closable.
  902. */
  903. mxWindow.prototype.setClosable = function(closable)
  904. {
  905. this.closeImg.style.display = (closable) ? '' : 'none';
  906. };
  907. /**
  908. * Function: isVisible
  909. *
  910. * Returns true if the window is visible.
  911. */
  912. mxWindow.prototype.isVisible = function()
  913. {
  914. if (this.div != null)
  915. {
  916. return this.div.style.display != 'none';
  917. }
  918. return false;
  919. };
  920. /**
  921. * Function: setVisible
  922. *
  923. * Shows or hides the window depending on the given flag.
  924. *
  925. * Parameters:
  926. *
  927. * visible - Boolean indicating if the window should be made visible.
  928. */
  929. mxWindow.prototype.setVisible = function(visible)
  930. {
  931. if (this.div != null && this.isVisible() != visible)
  932. {
  933. if (visible)
  934. {
  935. this.show();
  936. }
  937. else
  938. {
  939. this.hide();
  940. }
  941. }
  942. };
  943. /**
  944. * Function: show
  945. *
  946. * Shows the window.
  947. */
  948. mxWindow.prototype.show = function()
  949. {
  950. this.div.style.display = '';
  951. this.activate();
  952. var style = mxUtils.getCurrentStyle(this.contentWrapper);
  953. if (!mxClient.IS_QUIRKS && (style.overflow == 'auto' || this.resize != null) &&
  954. this.contentWrapper.style.display != 'none')
  955. {
  956. this.contentWrapper.style.height = (this.div.offsetHeight -
  957. this.title.offsetHeight - this.contentHeightCorrection) + 'px';
  958. }
  959. this.fireEvent(new mxEventObject(mxEvent.SHOW));
  960. };
  961. /**
  962. * Function: hide
  963. *
  964. * Hides the window.
  965. */
  966. mxWindow.prototype.hide = function()
  967. {
  968. this.div.style.display = 'none';
  969. this.fireEvent(new mxEventObject(mxEvent.HIDE));
  970. };
  971. /**
  972. * Function: destroy
  973. *
  974. * Destroys the window and removes all associated resources. Fires a
  975. * <destroy> event prior to destroying the window.
  976. */
  977. mxWindow.prototype.destroy = function()
  978. {
  979. this.fireEvent(new mxEventObject(mxEvent.DESTROY));
  980. if (this.div != null)
  981. {
  982. mxEvent.release(this.div);
  983. this.div.parentNode.removeChild(this.div);
  984. this.div = null;
  985. }
  986. this.title = null;
  987. this.content = null;
  988. this.contentWrapper = null;
  989. };