mxReader.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827
  1. /**
  2. * A Draw.io diagram viewer component with configurable toolbar buttons for editing, deleting and zooming buttons.
  3. * Parameters :
  4. * diagramName - name of the diagram
  5. * attachmentId - ID of the diagram attachment
  6. * ceoId - page ID or issue key
  7. * readerOpts - JSON object with options :
  8. * loadUrl - url from which to load the diagram
  9. * editUrl - url of the editor
  10. * stylePath - url from which to load the css
  11. * stencilPath - url from which to load the stencils
  12. * imagePath - url from which to load the graph mages
  13. * resourcePath - path to the translations
  14. * viewerToolbar - show toolbar or not
  15. * autoSize - resizes the graph container to match the graph bounds
  16. * width - width of the container
  17. * height - height of the container
  18. * disableButtons - disables all buttons
  19. * center - should the diagram be horizontally centered or not
  20. * evaluation - evaluation mode
  21. * lightbox - boolean indicating if this viewer is a lightbox
  22. * graphDocument - optional document containing the XML data
  23. */
  24. function DrawioViewer(diagramName, attachmentId, ceoId, readerOpts, lightbox, graphDocument, connect)
  25. {
  26. this.id = attachmentId;
  27. this.diagramName = diagramName;
  28. this.ceoId = ceoId;
  29. this.options = readerOpts;
  30. this.lightbox = lightbox;
  31. this.graphDocument = graphDocument;
  32. this.connect = connect;
  33. this.paddingBottom = (connect) ? 0 : 30;
  34. // Overrides browser language with Confluence user language
  35. var lang = null;
  36. // Language is in the readOpts in Server and in the URL in Connect
  37. if (!connect && readerOpts.language != null)
  38. {
  39. lang = readerOpts.language
  40. }
  41. else if (connect != null && urlParams['loc'] != null)
  42. {
  43. lang = urlParams['loc'];
  44. var dash = lang.indexOf('-');
  45. if (dash >= 0)
  46. {
  47. lang = lang.substring(0, dash);
  48. }
  49. }
  50. // Only german and english supported currently. English is default.
  51. if (lang == 'de')
  52. {
  53. mxClient.language = 'de';
  54. }
  55. // Special extension used for the message bundle. For this bundle there is only a German
  56. // translation and the default English bundle so we temporarily override isLanguageSupported
  57. // to return true only if German is used and fallback to English for all other languages.
  58. var prevExtension = mxResources.extension;
  59. var prevIsLangSupported = mxResources.isLanguageSupported;
  60. mxResources.extension = '.txt';
  61. mxResources.isLanguageSupported = function(lan)
  62. {
  63. return lan == 'de';
  64. };
  65. mxResources.add(this.options.resourcePath);
  66. // Restores previous settings
  67. mxResources.extension = prevExtension;
  68. mxResources.isLanguageSupported = prevIsLangSupported;
  69. this.buttons = this.createButtons();
  70. this.transparentImage = Editor.prototype.transparentImage;
  71. this.extractGraphModel = Editor.prototype.extractGraphModel;
  72. this.setGraphXml = Editor.prototype.setGraphXml;
  73. this.readGraphState = Editor.prototype.readGraphState;
  74. this.resetGraph = Editor.prototype.resetGraph;
  75. this.decompress = Editor.prototype.decompress;
  76. this.updateGraphComponents = Editor.prototype.updateGraphComponents;
  77. this.fireEvent = Editor.prototype.fireEvent;
  78. this.addListener = Editor.prototype.addListener;
  79. this.originalNoForeignObject = Editor.prototype.originalNoForeignObject;
  80. this.gridImage = '';
  81. this.addListener('resetGraphView', this.resetGraphView);
  82. }
  83. DrawioViewer.prototype = new mxEventSource();
  84. DrawioViewer.prototype.graph = null;
  85. DrawioViewer.prototype.id = null;
  86. DrawioViewer.prototype.toolbar = null;
  87. DrawioViewer.prototype.options = null;
  88. DrawioViewer.prototype.originX = 0;
  89. DrawioViewer.prototype.originY = 0;
  90. DrawioViewer.prototype.popupWindow = null;
  91. DrawioViewer.prototype.buttons = {};
  92. DrawioViewer.prototype.graphXmlString = null;
  93. DrawioViewer.prototype.installToolbar = function()
  94. {
  95. this.toolbar = document.createElement('div');
  96. var toolbar = this.toolbar;
  97. var container = this.graph.container;
  98. toolbar.id = 'diagramly-reader-toolbar-' + this.id;
  99. toolbar.className = 'diagramly-reader-toolbar';
  100. toolbar.style.position = 'absolute';
  101. container.parentNode.appendChild(toolbar);
  102. toolbar.style.height = '30px';
  103. toolbar.style.width = this.countVisibleButtons() * 29 + 'px';
  104. // Makes sure the toolbar is always visible and
  105. // disables toolbar for all overflow content
  106. container.parentNode.style.overflow = 'visible';
  107. if (this.lightbox)
  108. {
  109. toolbar.style.bottom = '4px';
  110. toolbar.style.left = '50%';
  111. toolbar.style.width = this.countVisibleButtons() * 29 + 'px';
  112. toolbar.style.marginLeft = -Math.round(this.countVisibleButtons() * 29 / 2) + 'px'
  113. }
  114. else
  115. {
  116. container.parentNode.style.paddingBottom = this.paddingBottom + 'px';
  117. var bs = this.graph.getBorderSizes();
  118. toolbar.style.bottom = (container.offsetTop + bs.y + 4) + 'px';
  119. toolbar.style.left = (container.offsetLeft + bs.x) + 'px';
  120. if (!mxClient.IS_TOUCH)
  121. {
  122. toolbar.style.display = 'none';
  123. $(container.parentNode).hover(function()
  124. {
  125. toolbar.style.bottom = (container.offsetTop + bs.y + 4) + 'px';
  126. toolbar.style.left = (container.offsetLeft + bs.x) + 'px';
  127. $(toolbar).fadeIn(100);
  128. },
  129. function()
  130. {
  131. $(toolbar).fadeOut(100);
  132. });
  133. }
  134. }
  135. }
  136. DrawioViewer.prototype.countVisibleButtons = function()
  137. {
  138. var counter = 0;
  139. for(var key in this.buttons)
  140. {
  141. var button = this.buttons[key];
  142. if (button.visible)
  143. {
  144. counter++;
  145. }
  146. }
  147. return counter;
  148. }
  149. DrawioViewer.prototype.init = function()
  150. {
  151. this.loadStylesheet();
  152. // Makes the shadow brighter
  153. mxConstants.SHADOWCOLOR = '#000000';
  154. mxConstants.SHADOW_OPACITY = 0.25;
  155. this.graph.setEnabled(false);
  156. this.graph.autoScroll = false;
  157. this.graph.container.style.overflow = 'hidden';
  158. this.graph.container.style.cursor = 'move';
  159. // Panning only enabled in lightbox to allow text selection in viewer
  160. this.graph.setPanning(true);
  161. // Workaround for context trigger starting panning if ignoreCell is true
  162. this.graph.panningHandler.useLeftButtonForPanning = true;
  163. this.graph.panningHandler.usePopupTrigger = false;
  164. this.graph.panningHandler.ignoreCell = true;
  165. this.graph.panningHandler.isForcePanningEvent = function(me)
  166. {
  167. return mxEvent.isLeftMouseButton(me.getEvent());
  168. };
  169. // Folding only enabled in lightbox
  170. this.graph.foldingEnabled = this.lightbox;
  171. // Overrides click handler to ignore graph enabled state
  172. if (this.graph.foldingEnabled)
  173. {
  174. this.graph.cellRenderer.createControlClickHandler = function(state)
  175. {
  176. var graph = state.view.graph;
  177. return function (evt)
  178. {
  179. var collapse = !graph.isCellCollapsed(state.cell);
  180. graph.foldCells(collapse, false, [state.cell], null, evt);
  181. mxEvent.consume(evt);
  182. };
  183. };
  184. }
  185. else
  186. {
  187. // Hides collapse/expand icon if folding is disabled
  188. this.graph.getFoldingImage = function()
  189. {
  190. return null;
  191. };
  192. };
  193. // HTML entities are displayed as plain text in wrapped plain text labels
  194. this.graph.cellRenderer.getLabelValue = function(state)
  195. {
  196. var result = mxCellRenderer.prototype.getLabelValue.apply(this, arguments);
  197. if (state.view.graph.isHtmlLabel(state.cell))
  198. {
  199. if (state.style['html'] != 1)
  200. {
  201. result = mxUtils.htmlEntities(result, false);
  202. }
  203. else
  204. {
  205. result = Graph.sanitizeHtml(result);
  206. }
  207. }
  208. return result;
  209. };
  210. // Enables links if graph is "disabled" (ie. read-only)
  211. this.graph.click = function(me)
  212. {
  213. var cell = me.getCell();
  214. if (cell != null && !me.isConsumed() && (mxEvent.isTouchEvent(me.getEvent()) ||
  215. mxEvent.isLeftMouseButton(me.getEvent())))
  216. {
  217. var href = this.getLinkForCell(cell);
  218. // Test cases:
  219. // 1) the relative link without the Conf base path, with a leading slash, e.g. /download/attachment/....
  220. // 2) the relative link with the Conf base path, with a leading slash, e.g. /confluence/download/attachmentss/...
  221. // 3) the relative link without the conf base path, without a leading slash, e.g. download/attachments/...
  222. // 4) the full absolute path, e.g. https://localhost:1990/confluence/download/attachments/...
  223. // 5) full path without protocol, e.g. //confluence/download/attachments/...
  224. if (href != null)
  225. {
  226. var r = new RegExp('^(?:[a-z]+:)?//', 'i'); // https://stackoverflow.com/questions/10687099/how-to-test-if-a-url-string-is-absolute-or-relative
  227. if (!r.test(href))
  228. {
  229. // relative link
  230. if (href.lastIndexOf('/', 0) !== 0) // http://stackoverflow.com/a/4579228/226469 seems to be the fastest check
  231. {
  232. // Need a leading slash in case we need to prepend the base path
  233. href = '/' + href;
  234. }
  235. // var cp = AJS.Confluence.getContextPath(); // TODO confluence call in a common module
  236. // Originally, links included the base path (but not the host), so there might be cases of the base path
  237. // already being prepended. If the base path has changed, we can't recover those cases
  238. // window.location.href = href.substring(0, cp.length) === cp ? href : cp + href; // prepends the context path if it's not already there
  239. window.location.href = href;
  240. }
  241. else
  242. {
  243. // Test if it's an absolute URL, but on the same domain (i.e. open in same window)
  244. // There's a security setting (unknown which) that seems to stop the IE hack below working in
  245. // IE 11, https://desk.draw.io/browse/DS-175, https://desk.draw.io/browse/DFCS-52
  246. // Worst case is these users will open an absolute same domain link in a window
  247. var link = document.createElement('a');
  248. link.href = href;
  249. link.href = link.href; // hack to populate 'host' under IE
  250. if (link.host === location.host)
  251. {
  252. window.location.href = href;
  253. }
  254. else
  255. {
  256. window.open(href);
  257. }
  258. }
  259. }
  260. me.consume();
  261. }
  262. };
  263. this.graph.setTooltips(!mxClient.IS_TOUCH);
  264. if (this.options.width != null)
  265. {
  266. this.graph.container.style.width = this.options.width + 'px';
  267. }
  268. if (this.options.height != null)
  269. {
  270. this.graph.container.style.height = this.options.height + 'px';
  271. }
  272. // Accumulates the zoom factor while the rendering is taking place
  273. // so that not the complete sequence of zoom steps must be painted
  274. var graph = this.graph;
  275. graph.updateZoomTimeout = null;
  276. graph.cumulativeZoomFactor = 1;
  277. graph.lazyZoom = function(zoomIn)
  278. {
  279. if (this.updateZoomTimeout != null)
  280. {
  281. window.clearTimeout(this.updateZoomTimeout);
  282. }
  283. if (zoomIn)
  284. {
  285. this.cumulativeZoomFactor *= this.zoomFactor;
  286. }
  287. else
  288. {
  289. this.cumulativeZoomFactor /= this.zoomFactor;
  290. }
  291. this.cumulativeZoomFactor = Math.round(this.view.scale * this.cumulativeZoomFactor * 100) / 100 / this.view.scale;
  292. this.updateZoomTimeout = window.setTimeout(mxUtils.bind(this, function()
  293. {
  294. this.zoom(this.cumulativeZoomFactor);
  295. this.cumulativeZoomFactor = 1;
  296. this.updateZoomTimeout = null;
  297. }), 20);
  298. };
  299. if (this.lightbox)
  300. {
  301. mxEvent.addMouseWheelListener(mxUtils.bind(this, function(evt, up)
  302. {
  303. if (!mxClient.IS_MAC || !mxEvent.isControlDown(evt))
  304. {
  305. var source = mxEvent.getSource(evt);
  306. while (source != null)
  307. {
  308. if (source == graph.container)
  309. {
  310. graph.lazyZoom(up);
  311. mxEvent.consume(evt);
  312. return;
  313. }
  314. source = source.parentNode;
  315. }
  316. }
  317. }));
  318. }
  319. };
  320. DrawioViewer.prototype.resetGraphView = function()
  321. {
  322. this.graph.pageBreaksVisible = false;
  323. this.graph.preferPageSize = false;
  324. this.graph.pageVisible = false;
  325. if (!this.lightbox)
  326. {
  327. var update = mxUtils.bind(this, function()
  328. {
  329. this.graph.centerZoom = this.graph.panningHandler.panningEnabled;
  330. // If width and height are specified the height is overridden to match the diagram size
  331. var autoSizeWidth = this.options.width == null;
  332. var autoSizeHeight = this.options.height == null;
  333. var bounds = this.graph.getGraphBounds();
  334. var ratio = bounds.width / bounds.height;
  335. var width = autoSizeWidth ? bounds.width + 2 : this.options.width;
  336. var height = autoSizeHeight ? (width / ratio) + 1 : this.options.height;
  337. this.graph.container.style.width = Math.ceil(width) + 'px';
  338. this.graph.container.style.height = Math.ceil(height) + 'px';
  339. this.graph.container.style.maxWidth = '100%';
  340. if (autoSizeWidth && autoSizeHeight)
  341. {
  342. this.translateOrigin();
  343. // Used for fast restore of initial position in zoom to fit button
  344. this.initialX = this.graph.view.translate.x;
  345. this.initialY = this.graph.view.translate.y;
  346. }
  347. else if (this.options.zoomToFit)
  348. {
  349. this.graph.fit();
  350. }
  351. //set the border after calling updateGraphComponnets() because the call sets it to ''
  352. this.graph.container.style.border = this.options.border ? '1px solid #DDDDDD' : 'none';
  353. this.graph.container.style.backgroundColor = (this.graph.background == null ||
  354. this.graph.background == 'none') ? '#ffffff' : this.graph.background;
  355. });
  356. // Workaround for invisible container is to move the container to the document body for rendering
  357. if (!this.connect && (this.graph.container.clientWidth == 0 || this.graph.container.clientHeight == 0))
  358. {
  359. var previousParent = this.graph.container.parentNode;
  360. var nextSibling = this.graph.container.nextSibling;
  361. var prevPosition = this.graph.container.style.position;
  362. var prevVisible = this.graph.container.style.visible;
  363. // Moves to document body for rendering (needed for text measuring)
  364. this.graph.container.style.position = 'absolute';
  365. this.graph.container.style.visible = 'hidden';
  366. document.body.appendChild(this.graph.container);
  367. // Refresh required in visible DOM to update text bounding boxes
  368. this.graph.refresh();
  369. update();
  370. // Move it back into DOM tree position
  371. if (nextSibling != null)
  372. {
  373. nextSibling.parentNode.insertBefore(this.graph.container, nextSibling);
  374. }
  375. else
  376. {
  377. previousParent.appendChild(this.graph.container);
  378. }
  379. // Restore position CSS
  380. this.graph.container.style.visible = prevVisible;
  381. this.graph.container.style.position = prevPosition;
  382. }
  383. else
  384. {
  385. update();
  386. }
  387. }
  388. else
  389. {
  390. this.graph.container.style.backgroundColor = (this.graph.background == null ||
  391. this.graph.background == 'none') ? '#ffffff' : this.graph.background;
  392. }
  393. };
  394. DrawioViewer.prototype.translateOrigin = function()
  395. {
  396. var bounds = this.graph.getGraphBounds();
  397. this.graph.view.setTranslate(this.originX - Math.floor(bounds.x), this.originY - Math.floor(bounds.y));
  398. };
  399. DrawioViewer.prototype.loadGraph = function(diagramName, ceoId)
  400. {
  401. var spinner = this.createSpinner(this.graph.container);
  402. try
  403. {
  404. mxUtils.get(this.options.loadUrl, mxUtils.bind(this, function(req)
  405. {
  406. spinner.stop();
  407. if (req.getStatus() < 200 || req.getStatus() > 299)
  408. {
  409. this.showWarning(mxResources.get('error') + ' ' + req.getStatus());
  410. this.graph.container.style.border = this.options.border ? '1px solid #DDDDDD' : 'none';
  411. this.graph.container.style.backgroundColor = '#ffffff';
  412. this.graph.container.style.height = '20px';
  413. }
  414. else
  415. {
  416. var json = JSON.parse(req.getText());
  417. this.graphXmlString = json.xml;
  418. var doc = mxUtils.parseXml(json.xml);
  419. this.xmlDoc = doc;
  420. this.filename = json.filename;
  421. this.setGraphXml(doc.documentElement);
  422. this.graphDocument = doc;
  423. }
  424. }),
  425. function()
  426. {
  427. spinner.stop();
  428. });
  429. }
  430. catch (e)
  431. {
  432. spinner.stop();
  433. }
  434. };
  435. DrawioViewer.prototype.loadStylesheet = function()
  436. {
  437. var node = mxUtils.load(this.options.stylePath + '/default.xml').getDocumentElement();
  438. var dec = new mxCodec(node.ownerDocument);
  439. dec.decode(node, this.graph.getStylesheet());
  440. };
  441. DrawioViewer.prototype.renderButtons = function()
  442. {
  443. for (var key in this.buttons)
  444. {
  445. var button = this.buttons[key];
  446. if (button.visible)
  447. {
  448. this.addToolbarButton(this.toolbar, button);
  449. }
  450. }
  451. };
  452. DrawioViewer.prototype.addToolbarButton = function(toolbar, drawioButton)
  453. {
  454. var enabled = typeof drawioButton.enabled === 'undefined' ? true : enabled;
  455. var button = drawioButton.linkButton ? document.createElement('a') : document.createElement('div');
  456. button.className = 'diagramly-reader-toolbar-button';
  457. if (drawioButton.icon != null)
  458. {
  459. var img = document.createElement('img');
  460. img.setAttribute('src', drawioButton.icon);
  461. img.style.verticalAlign = 'middle';
  462. img.style.marginRight = '2px';
  463. button.appendChild(img);
  464. button.title = drawioButton.label;
  465. }
  466. if (!drawioButton.enabled)
  467. {
  468. button.style.opacity = 0.2;
  469. } else
  470. {
  471. if(drawioButton.linkButton)
  472. {
  473. button.href = drawioButton.url;
  474. }
  475. else
  476. {
  477. mxEvent.addListener(button, 'click', function(evt)
  478. {
  479. drawioButton.clickHandler.apply(this, arguments);
  480. });
  481. }
  482. mxEvent.addListener(button, 'mouseover', function(evt)
  483. {
  484. button.className += ' diagramly-reader-toolbar-button-hover';
  485. });
  486. mxEvent.addListener(button, 'mouseout', function(evt)
  487. {
  488. button.className = 'diagramly-reader-toolbar-button';
  489. });
  490. }
  491. toolbar.appendChild(button);
  492. return button;
  493. };
  494. DrawioViewer.prototype.createSpinner = function(container)
  495. {
  496. var opts =
  497. {
  498. lines : 12, // The number of lines to draw
  499. length : 12, // The length of each line
  500. width : 5, // The line thickness
  501. radius : 10, // The radius of the inner circle
  502. rotate : 0, // The rotation offset
  503. color : '#000', // #rgb or #rrggbb
  504. speed : 1, // Rounds per second
  505. trail : 60, // Afterglow percentage
  506. shadow : false, // Whether to render a shadow
  507. hwaccel : false, // Whether to use hardware acceleration
  508. className : 'spinner', // The CSS class to assign to the spinner
  509. zIndex : 2e9 // The z-index (defaults to 2000000000)
  510. };
  511. return new Spinner(opts).spin(container);
  512. };
  513. DrawioViewer.prototype.show = function(container)
  514. {
  515. this.graph = new Graph(container);
  516. this.graph.id = this.id;
  517. this.init();
  518. // Uses the XML document that was loaded for the viewer in the lightbox
  519. if (this.graphDocument != null)
  520. {
  521. this.setGraphXml(this.graphDocument.documentElement);
  522. }
  523. else
  524. {
  525. this.loadGraph(this.diagramName, this.ceoId);
  526. }
  527. if (this.options.viewerToolbar)
  528. {
  529. this.installToolbar();
  530. this.renderButtons();
  531. }
  532. if (this.options.licenseStatus == 'NO_LICENSE')
  533. {
  534. this.showWarning(mxResources.get('drawio.reader.noLicense'));
  535. }
  536. else if (this.options.licenseStatus == 'EVAL_LICENSE')
  537. {
  538. this.showWarning(mxResources.get('drawio.reader.evaluation'));
  539. }
  540. else if (this.options.licenseStatus == 'EVAL_EXPIRED')
  541. {
  542. this.showWarning(mxResources.get('drawio.reader.evaluationExpired'));
  543. }
  544. else if (this.options.licenseStatus == 'VERSION_MISMATCH')
  545. {
  546. this.showWarning(mxResources.get('drawio.reader.versionMismatch', ['https://support.draw.io/pages/viewpage.action?pageId=11829320']));
  547. }
  548. else if (this.options.licenseStatus == 'USER_MISMATCH')
  549. {
  550. this.showWarning(mxResources.get('drawio.reader.userMismatch', ['https://support.draw.io/pages/viewpage.action?pageId=11829323']));
  551. }
  552. };
  553. DrawioViewer.prototype.showWarning = function(msg)
  554. {
  555. var div = document.createElement('div');
  556. div.style.position = 'absolute';
  557. div.style.overflow = 'hidden';
  558. div.style.left = '0px';
  559. div.style.top = '0px';
  560. div.style.right = '0px';
  561. div.style.fontSize = '12px';
  562. div.style.margin = '2px';
  563. mxUtils.setOpacity(div, 50);
  564. div.style.color = 'gray';
  565. div.style.textAlign = 'center';
  566. div.style.whiteSpace = 'nowrap';
  567. span = document.createElement('span');
  568. span.innerHTML = msg;
  569. div.appendChild(span);
  570. this.graph.container.parentNode.appendChild(div);
  571. };
  572. DrawioViewer.prototype.showLightbox = function()
  573. {
  574. console.log('Lightbox feature not implemented.');
  575. };
  576. DrawioViewer.prototype.createButtons = function()
  577. {
  578. var viewer = this;
  579. var buttons = {};
  580. var enableButton = typeof this.options.disableButtons === 'undefined' ? true : !this.options.disableButtons;
  581. var canEdit = this.options.userCanEdit && enableButton;
  582. var canRemove = this.options.userCanRemove && enableButton;
  583. var autoSizeWidth = this.options.width == null;
  584. var autoSizeHeight = this.options.height == null;
  585. buttons[DrawioViewerActions.EDIT] = new DrawioViewerButton(
  586. {
  587. label : mxResources.get('diagramly.reader.edit'),
  588. icon : viewer.options.imagePath + '/edit.png',
  589. url : viewer.options.editUrl,
  590. enabled : canEdit,
  591. linkButton : true
  592. });
  593. buttons[DrawioViewerActions.REMOVE] = new DrawioViewerButton(
  594. {
  595. label : mxResources.get('diagramly.reader.remove'),
  596. icon : viewer.options.imagePath + '/remove.png',
  597. clickHandler : function()
  598. {
  599. if (confirm(mxResources.get('diagramly.reader.confirmDelete')))
  600. {
  601. window.location.href = viewer.options.removeUrl;
  602. }
  603. },
  604. enabled : canRemove
  605. });
  606. buttons[DrawioViewerActions.ACTUAL_SIZE] = new DrawioViewerButton(
  607. {
  608. label : mxResources.get('diagramly.reader.zoomActual'),
  609. icon : viewer.options.imagePath + '/zoomActual.png',
  610. clickHandler : function()
  611. {
  612. viewer.graph.zoomActual();
  613. viewer.translateOrigin();
  614. },
  615. enabled : enableButton
  616. });
  617. buttons[DrawioViewerActions.ZOOM_TO_FIT] = new DrawioViewerButton(
  618. {
  619. label : (this.lightbox) ? mxResources.get('diagramly.reader.zoomActual') : mxResources.get('diagramly.reader.fit'),
  620. icon : (this.lightbox) ? viewer.options.imagePath + '/zoomActual.png' : viewer.options.imagePath + '/zoomFit.gif',
  621. clickHandler : mxUtils.bind(this, function()
  622. {
  623. if (this.lightbox)
  624. {
  625. // NOTE: Maxscale is 1 here so only make smaller but not larger
  626. viewer.graph.fit(8);
  627. viewer.graph.center(true, true, null, 0.42);
  628. }
  629. else
  630. {
  631. if (autoSizeWidth && autoSizeHeight)
  632. {
  633. this.graph.view.scaleAndTranslate(1, this.initialX, this.initialY);
  634. }
  635. else
  636. {
  637. this.graph.fit();
  638. }
  639. }
  640. }),
  641. enabled : enableButton
  642. });
  643. buttons[DrawioViewerActions.ZOOM_OUT] = new DrawioViewerButton(
  644. {
  645. label : mxResources.get('diagramly.reader.zoomOut'),
  646. icon : viewer.options.imagePath + '/zoomOut.gif',
  647. clickHandler : function()
  648. {
  649. viewer.graph.zoomOut();
  650. },
  651. enabled : enableButton
  652. });
  653. buttons[DrawioViewerActions.ZOOM_IN] = new DrawioViewerButton(
  654. {
  655. label : mxResources.get('diagramly.reader.zoomIn'),
  656. icon : viewer.options.imagePath + '/zoomIn.gif',
  657. clickHandler : function()
  658. {
  659. viewer.graph.zoomIn();
  660. },
  661. enabled : enableButton
  662. });
  663. buttons[DrawioViewerActions.EXPAND] = new DrawioViewerButton(
  664. {
  665. label : mxResources.get('diagramly.reader.fullScreen'),
  666. icon : viewer.options.imagePath + '/largeView.png',
  667. clickHandler : mxUtils.bind(this, function()
  668. {
  669. this.showLightbox();
  670. }),
  671. enabled : enableButton
  672. });
  673. buttons[DrawioViewerActions.CLOSE] = new DrawioViewerButton(
  674. {
  675. label : mxResources.get('diagramly.reader.closeFullScreen'),
  676. icon : viewer.options.imagePath + '/closeLargeView.gif',
  677. clickHandler : function()
  678. {
  679. viewer.popupWindow.remove();
  680. },
  681. enabled : enableButton,
  682. visible : false
  683. });
  684. return buttons;
  685. };
  686. DrawioViewerActions =
  687. {
  688. EDIT : 'edit',
  689. REMOVE : 'remove',
  690. ACTUAL_SIZE : 'actualSize',
  691. ZOOM_TO_FIT : 'zoomToFit',
  692. ZOOM_OUT : 'zoomOut',
  693. ZOOM_IN : 'zoomIn',
  694. EXPAND : 'expand',
  695. CLOSE : 'close'
  696. };
  697. function DrawioViewerButton(options)
  698. {
  699. this.label = options.label;
  700. this.clickHandler = options.clickHandler;
  701. this.enabled = typeof options.enabled != 'undefined' ? options.enabled : true;
  702. this.icon = options.icon;
  703. this.visible = typeof options.visible != 'undefined' ? options.visible : true;
  704. this.linkButton = typeof options.linkButton != 'undefined' ? options.linkButton : false;
  705. this.url = options.url;
  706. };
  707. DrawioViewerButton.prototype.label = null;
  708. DrawioViewerButton.prototype.clickHandler = null;
  709. DrawioViewerButton.prototype.enabled = true;
  710. DrawioViewerButton.prototype.icon = null;
  711. DrawioViewerButton.prototype.visible = true;
  712. DrawioViewerButton.prototype.linkButton = false;
  713. DrawioViewerButton.prototype.url = null;