Editor.js 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042
  1. /**
  2. * Copyright (c) 2006-2016, JGraph Ltd
  3. * Copyright (c) 2006-2016, Gaudenz Alder
  4. */
  5. (function()
  6. {
  7. /**
  8. * Specifies the app name. Default is document.title.
  9. */
  10. Editor.prototype.appName = 'draw.io';
  11. /**
  12. * Used in the GraphViewer lightbox.
  13. */
  14. Editor.closeImage = (mxClient.IS_SVG) ? 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAMAAADzN3VRAAAApVBMVEUAAAD////k5OT///8AAAB1dXXMzMz9/f39/f37+/v5+fn+/v7///9iYmJaWlqFhYWnp6ejo6OHh4f////////////////7+/v5+fnx8fH///8AAAD///8bGxv7+/v5+fkoKCghISFDQ0MYGBjh4eHY2Njb29tQUFBvb29HR0c/Pz82NjYrKyu/v78SEhLu7u7s7OzV1dVVVVU7OzsVFRXAv78QEBBzqehMAAAAG3RSTlMAA/7p/vz5xZlrTiPL/v78+/v7+OXd2TYQDs8L70ZbAAABKUlEQVQoz3VS13LCMBBUXHChd8iukDslQChJ/v/TchaG4cXS+OSb1c7trU7V60OpdRz2ZtNZL4zXNlcN8BEtSG6+NxIXkeRPoBuQ1cjvZ31/VJFB10ISli6diYfH8iYO3WUNCcNlB0gTrXOtkxTo0O1aKKiBBMhhv2MNBQKoiA5wxlZo0JDzD3AYKbWacyj3fs01wxey0pyEP+R8pWKWXoqtIZ0DDg5pbki9krEKOa6LVDQsdoXEsi46Zqh69KFz7B1u7Hb2yDV8firXDKBlZ4UFiswKGRhXTS93/ECK7yxnJ3+S3y/ThpO+cfSD017nqa18aasabU0/t7d+tk0/1oMEJ1NaD67iwdF68OabFSLn+eHb0+vjy+uk8br9fdrftH0O2menfd7+AQfYM/lNjoDHAAAAAElFTkSuQmCC' : IMAGE_PATH + '/delete.png';
  15. /**
  16. * Executes the first step for connecting to Google Drive.
  17. */
  18. Editor.prototype.editButtonLink = (urlParams['edit'] != null) ? decodeURIComponent(urlParams['edit']) : null;
  19. /**
  20. *
  21. */
  22. if (urlParams['dev'] == '1')
  23. {
  24. Editor.prototype.editBlankUrl = Editor.prototype.editBlankUrl + '&dev=1';
  25. Editor.prototype.editBlankFallbackUrl = Editor.prototype.editBlankFallbackUrl + '&dev=1';
  26. }
  27. /**
  28. * Adds support for old stylesheets and compressed files
  29. */
  30. var editorSetGraphXml = Editor.prototype.setGraphXml;
  31. Editor.prototype.setGraphXml = function(node)
  32. {
  33. node = (node != null && node.nodeName != 'mxlibrary') ? this.extractGraphModel(node) : null;
  34. if (node != null)
  35. {
  36. // Checks input for parser errors
  37. var errs = node.getElementsByTagName('parsererror');
  38. if (errs != null && errs.length > 0)
  39. {
  40. var elt = errs[0];
  41. var divs = elt.getElementsByTagName('div');
  42. if (divs != null && divs.length > 0)
  43. {
  44. elt = divs[0];
  45. }
  46. throw {message: mxUtils.getTextContent(elt)};
  47. }
  48. else if (node.nodeName == 'mxGraphModel')
  49. {
  50. var style = node.getAttribute('style') || 'default-style2';
  51. // Decodes the style if required
  52. if (urlParams['embed'] != '1' && (style == null || style == ''))
  53. {
  54. var node2 = (this.graph.themes != null) ?
  55. this.graph.themes['default-old'] :
  56. mxUtils.load(STYLE_PATH + '/default-old.xml').getDocumentElement();
  57. if (node2 != null)
  58. {
  59. var dec2 = new mxCodec(node2.ownerDocument);
  60. dec2.decode(node2, this.graph.getStylesheet());
  61. }
  62. }
  63. else if (style != this.graph.currentStyle)
  64. {
  65. var node2 = (this.graph.themes != null) ?
  66. this.graph.themes[style] :
  67. mxUtils.load(STYLE_PATH + '/' + style + '.xml').getDocumentElement()
  68. if (node2 != null)
  69. {
  70. var dec2 = new mxCodec(node2.ownerDocument);
  71. dec2.decode(node2, this.graph.getStylesheet());
  72. }
  73. }
  74. this.graph.currentStyle = style;
  75. this.graph.mathEnabled = (urlParams['math'] == '1' || node.getAttribute('math') == '1');
  76. var bgImg = node.getAttribute('backgroundImage');
  77. if (bgImg != null)
  78. {
  79. bgImg = JSON.parse(bgImg);
  80. this.graph.setBackgroundImage(new mxImage(bgImg.src, bgImg.width, bgImg.height));
  81. }
  82. else
  83. {
  84. this.graph.setBackgroundImage(null);
  85. }
  86. mxClient.NO_FO = (this.graph.mathEnabled) ? true : this.originalNoForeignObject;
  87. this.graph.setShadowVisible(node.getAttribute('shadow') == '1', false);
  88. }
  89. // Calls updateGraphComponents
  90. editorSetGraphXml.apply(this, arguments);
  91. }
  92. else
  93. {
  94. throw {
  95. message: mxResources.get('notADiagramFile') || 'Invalid data',
  96. toString: function() { return this.message; }
  97. };
  98. }
  99. };
  100. /**
  101. * Adds persistent style to file
  102. */
  103. var editorGetGraphXml = Editor.prototype.getGraphXml;
  104. Editor.prototype.getGraphXml = function(ignoreSelection)
  105. {
  106. ignoreSelection = (ignoreSelection != null) ? ignoreSelection : true;
  107. var node = editorGetGraphXml.apply(this, arguments);
  108. // Adds the current style
  109. if (this.graph.currentStyle != null && this.graph.currentStyle != 'default-style2')
  110. {
  111. node.setAttribute('style', this.graph.currentStyle);
  112. }
  113. // Adds the background image
  114. if (this.graph.backgroundImage != null)
  115. {
  116. node.setAttribute('backgroundImage', JSON.stringify(this.graph.backgroundImage));
  117. }
  118. node.setAttribute('math', (this.graph.mathEnabled) ? '1' : '0');
  119. node.setAttribute('shadow', (this.graph.shadowVisible) ? '1' : '0');
  120. return node;
  121. };
  122. /**
  123. * Overrides reset graph.
  124. */
  125. var editorResetGraph = Editor.prototype.resetGraph;
  126. Editor.prototype.resetGraph = function()
  127. {
  128. this.graph.mathEnabled = (urlParams['math'] == '1');
  129. this.graph.view.x0 = null;
  130. this.graph.view.y0 = null;
  131. mxClient.NO_FO = (this.graph.mathEnabled) ? true : this.originalNoForeignObject;
  132. editorResetGraph.apply(this, arguments);
  133. };
  134. /**
  135. * Math support.
  136. */
  137. Editor.prototype.originalNoForeignObject = mxClient.NO_FO;
  138. var editorUpdateGraphComponents = Editor.prototype.updateGraphComponents;
  139. Editor.prototype.updateGraphComponents = function()
  140. {
  141. editorUpdateGraphComponents.apply(this, arguments);
  142. mxClient.NO_FO = (this.graph.mathEnabled && Editor.MathJaxRender != null) ? true : this.originalNoForeignObject;
  143. };
  144. /**
  145. * Initializes math typesetting and loads respective code.
  146. */
  147. Editor.initMath = function(src, config)
  148. {
  149. src = (src != null) ? src : 'https://cdn.mathjax.org/mathjax/2.6-latest/MathJax.js?config=TeX-MML-AM_HTMLorMML';
  150. Editor.mathJaxQueue = [];
  151. Editor.doMathJaxRender = function(container)
  152. {
  153. MathJax.Hub.Queue(['Typeset', MathJax.Hub, container]);
  154. };
  155. // Disables global typesetting and messages on startup, adds queue for
  156. // asynchronous rendering while MathJax is loading
  157. window.MathJax =
  158. {
  159. skipStartupTypeset: true,
  160. showMathMenu: false,
  161. messageStyle: 'none',
  162. AuthorInit: function ()
  163. {
  164. // Specification recommends using SVG over HTML-CSS if browser is known
  165. // Check if too inconsistent with image export and print output
  166. MathJax.Hub.Config(config || {
  167. jax: ['input/TeX', 'input/MathML', 'input/AsciiMath', 'output/HTML-CSS'],
  168. extensions: ['tex2jax.js', 'mml2jax.js', 'asciimath2jax.js'],
  169. TeX: {
  170. extensions: ['AMSmath.js', 'AMSsymbols.js', 'noErrors.js', 'noUndefined.js']
  171. },
  172. // Ignores math in in-place editor
  173. tex2jax: {
  174. ignoreClass: 'mxCellEditor'
  175. },
  176. asciimath2jax: {
  177. ignoreClass: 'mxCellEditor'
  178. }
  179. });
  180. MathJax.Hub.Register.StartupHook('Begin', function()
  181. {
  182. for (var i = 0; i < Editor.mathJaxQueue.length; i++)
  183. {
  184. Editor.doMathJaxRender(Editor.mathJaxQueue[i]);
  185. }
  186. });
  187. }
  188. };
  189. // Adds global enqueue method for async rendering
  190. Editor.MathJaxRender = function(container)
  191. {
  192. // Initial rendering when MathJax finished loading
  193. if (typeof(MathJax) !== 'undefined' && typeof(MathJax.Hub) !== 'undefined')
  194. {
  195. Editor.doMathJaxRender(container);
  196. }
  197. else
  198. {
  199. Editor.mathJaxQueue.push(container);
  200. }
  201. };
  202. // Adds global clear queue method
  203. Editor.MathJaxClear = function()
  204. {
  205. Editor.mathJaxQueue = [];
  206. };
  207. // Updates typeset after changes
  208. var editorInit = Editor.prototype.init;
  209. Editor.prototype.init = function()
  210. {
  211. this.graph.addListener(mxEvent.SIZE, mxUtils.bind(this, function(sender, evt)
  212. {
  213. if (this.graph.mathEnabled)
  214. {
  215. Editor.MathJaxRender(this.graph.container);
  216. }
  217. }));
  218. };
  219. var tags = document.getElementsByTagName('script');
  220. if (tags != null && tags.length > 0)
  221. {
  222. var script = document.createElement('script');
  223. script.type = 'text/javascript';
  224. script.src = src;
  225. tags[0].parentNode.appendChild(script);
  226. }
  227. };
  228. /**
  229. * Adds a shadow filter to the given svg root.
  230. */
  231. Editor.prototype.addSvgShadow = function(svgRoot, group, createOnly)
  232. {
  233. createOnly = (createOnly != null) ? createOnly : false;
  234. var svgDoc = svgRoot.ownerDocument;
  235. var filter = (svgDoc.createElementNS != null) ?
  236. svgDoc.createElementNS(mxConstants.NS_SVG, 'filter') : svgDoc.createElement('filter');
  237. filter.setAttribute('id', this.graph.shadowId);
  238. var blur = (svgDoc.createElementNS != null) ?
  239. svgDoc.createElementNS(mxConstants.NS_SVG, 'feGaussianBlur') : svgDoc.createElement('feGaussianBlur');
  240. blur.setAttribute('in', 'SourceAlpha');
  241. blur.setAttribute('stdDeviation', '1.7');
  242. blur.setAttribute('result', 'blur');
  243. filter.appendChild(blur);
  244. var offset = (svgDoc.createElementNS != null) ?
  245. svgDoc.createElementNS(mxConstants.NS_SVG, 'feOffset') : svgDoc.createElement('feOffset');
  246. offset.setAttribute('in', 'blur');
  247. offset.setAttribute('dx', '3');
  248. offset.setAttribute('dy', '3');
  249. offset.setAttribute('result', 'offsetBlur');
  250. filter.appendChild(offset);
  251. var flood = (svgDoc.createElementNS != null) ?
  252. svgDoc.createElementNS(mxConstants.NS_SVG, 'feFlood') : svgDoc.createElement('feFlood');
  253. flood.setAttribute('flood-color', '#3D4574');
  254. flood.setAttribute('flood-opacity', '0.4');
  255. flood.setAttribute('result', 'offsetColor');
  256. filter.appendChild(flood);
  257. var composite = (svgDoc.createElementNS != null) ?
  258. svgDoc.createElementNS(mxConstants.NS_SVG, 'feComposite') : svgDoc.createElement('feComposite');
  259. composite.setAttribute('in', 'offsetColor');
  260. composite.setAttribute('in2', 'offsetBlur');
  261. composite.setAttribute('operator', 'in');
  262. composite.setAttribute('result', 'offsetBlur');
  263. filter.appendChild(composite);
  264. var feBlend = (svgDoc.createElementNS != null) ?
  265. svgDoc.createElementNS(mxConstants.NS_SVG, 'feBlend') : svgDoc.createElement('feBlend');
  266. feBlend.setAttribute('in', 'SourceGraphic');
  267. feBlend.setAttribute('in2', 'offsetBlur');
  268. filter.appendChild(feBlend);
  269. // Creates defs element if not available
  270. var defs = svgRoot.getElementsByTagName('defs');
  271. var defsElt = null;
  272. if (defs.length == 0)
  273. {
  274. defsElt = (svgDoc.createElementNS != null) ?
  275. svgDoc.createElementNS(mxConstants.NS_SVG, 'defs') : svgDoc.createElement('defs');
  276. if (svgRoot.firstChild != null)
  277. {
  278. svgRoot.insertBefore(defsElt, svgRoot.firstChild);
  279. }
  280. else
  281. {
  282. svgRoot.appendChild(defsElt);
  283. }
  284. }
  285. else
  286. {
  287. defsElt = defs[0];
  288. }
  289. defsElt.appendChild(filter);
  290. if (!createOnly)
  291. {
  292. (group || svgRoot.getElementsByTagName('g')[0]).setAttribute('filter', 'url(#' + this.graph.shadowId + ')');
  293. if (!isNaN(parseInt(svgRoot.getAttribute('width'))))
  294. {
  295. svgRoot.setAttribute('width', parseInt(svgRoot.getAttribute('width')) + 6);
  296. svgRoot.setAttribute('height', parseInt(svgRoot.getAttribute('height')) + 6);
  297. }
  298. }
  299. return filter;
  300. };
  301. /**
  302. * Adds persistence for recent colors
  303. */
  304. if (window.ColorDialog)
  305. {
  306. var colorDialogAddRecentColor = ColorDialog.addRecentColor;
  307. ColorDialog.addRecentColor = function(color, max)
  308. {
  309. colorDialogAddRecentColor.apply(this, arguments);
  310. mxSettings.setRecentColors(ColorDialog.recentColors);
  311. mxSettings.save();
  312. };
  313. var colorDialogResetRecentColors = ColorDialog.resetRecentColors;
  314. ColorDialog.resetRecentColors = function()
  315. {
  316. colorDialogResetRecentColors.apply(this, arguments);
  317. mxSettings.setRecentColors(ColorDialog.recentColors);
  318. mxSettings.save();
  319. };
  320. }
  321. /**
  322. * Global switches for the export dialog.
  323. */
  324. if (window.ExportDialog)
  325. {
  326. ExportDialog.showXmlOption = false;
  327. ExportDialog.showGifOption = false;
  328. ExportDialog.getExportParameter = function(ui, format)
  329. {
  330. return function()
  331. {
  332. // LATER Fix decoding of HTML file in backend (remove argument in getFileData)
  333. return 'xml=' + encodeURIComponent(ui.getFileData(true));
  334. };
  335. };
  336. }
  337. // Overridden to add edit shape option
  338. if (window.StyleFormatPanel != null)
  339. {
  340. var formatInit = Format.prototype.init;
  341. Format.prototype.init = function()
  342. {
  343. formatInit.apply(this, arguments);
  344. var ui = this.editorUi;
  345. ui.editor.addListener('fileLoaded', this.update);
  346. };
  347. var formatRefresh = Format.prototype.refresh;
  348. Format.prototype.refresh = function()
  349. {
  350. var ui = this.editorUi;
  351. if (ui.getCurrentFile() != null || urlParams['embed'] == '1')
  352. {
  353. formatRefresh.apply(this, arguments);
  354. }
  355. else
  356. {
  357. this.clear();
  358. }
  359. };
  360. /**
  361. * Adds autosave and math typesetting options.
  362. */
  363. var diagramFormatPanelAddOptions = DiagramFormatPanel.prototype.addOptions;
  364. DiagramFormatPanel.prototype.addOptions = function(div)
  365. {
  366. div = diagramFormatPanelAddOptions.apply(this, arguments);
  367. var ui = this.editorUi;
  368. var editor = ui.editor;
  369. var graph = editor.graph;
  370. if (graph.isEnabled())
  371. {
  372. var file = ui.getCurrentFile();
  373. if (file != null && file.isAutosaveOptional())
  374. {
  375. var opt = this.createOption(mxResources.get('autosave'), function()
  376. {
  377. return ui.editor.autosave;
  378. }, function(checked)
  379. {
  380. ui.editor.setAutosave(checked);
  381. },
  382. {
  383. install: function(apply)
  384. {
  385. this.listener = function()
  386. {
  387. apply(ui.editor.autosave);
  388. };
  389. ui.editor.addListener('autosaveChanged', this.listener);
  390. },
  391. destroy: function()
  392. {
  393. ui.editor.removeListener(this.listener);
  394. }
  395. });
  396. div.appendChild(opt);
  397. }
  398. }
  399. return div;
  400. };
  401. /**
  402. * Adds predefiend styles.
  403. */
  404. var StyleFormatPanelInit = StyleFormatPanel.prototype.init;
  405. StyleFormatPanel.prototype.init = function()
  406. {
  407. // TODO: Update sstate in Format
  408. var sstate = this.format.createSelectionState();
  409. if (sstate.style.shape != 'image')
  410. {
  411. this.container.appendChild(this.addStyles(this.createPanel()));
  412. }
  413. StyleFormatPanelInit.apply(this, arguments);
  414. };
  415. /**
  416. * Overridden to add copy and paste style.
  417. */
  418. var styleFormatPanelAddStyleOps = StyleFormatPanel.prototype.addStyleOps;
  419. StyleFormatPanel.prototype.addStyleOps = function(div)
  420. {
  421. var btn = mxUtils.button(mxResources.get('copyStyle'), mxUtils.bind(this, function(evt)
  422. {
  423. this.editorUi.actions.get('copyStyle').funct();
  424. }));
  425. btn.setAttribute('title', mxResources.get('copyStyle') + ' (' + this.editorUi.actions.get('copyStyle').shortcut + ')');
  426. btn.style.marginBottom = '2px';
  427. btn.style.width = '100px';
  428. btn.style.marginRight = '2px';
  429. div.appendChild(btn);
  430. var btn = mxUtils.button(mxResources.get('pasteStyle'), mxUtils.bind(this, function(evt)
  431. {
  432. this.editorUi.actions.get('pasteStyle').funct();
  433. }));
  434. btn.setAttribute('title', mxResources.get('pasteStyle') + ' (' + this.editorUi.actions.get('pasteStyle').shortcut + ')');
  435. btn.style.marginBottom = '2px';
  436. btn.style.width = '100px';
  437. div.appendChild(btn);
  438. mxUtils.br(div);
  439. return styleFormatPanelAddStyleOps.apply(this, arguments);
  440. };
  441. /**
  442. * Creates the buttons for the predefined styles.
  443. */
  444. StyleFormatPanel.prototype.addStyles = function(div)
  445. {
  446. var graph = this.editorUi.editor.graph;
  447. var picker = document.createElement('div');
  448. picker.style.whiteSpace = 'normal';
  449. picker.style.paddingLeft = '24px';
  450. picker.style.paddingRight = '20px';
  451. div.style.paddingLeft = '16px';
  452. div.style.paddingBottom = '6px';
  453. div.style.position = 'relative';
  454. div.appendChild(picker);
  455. var stylenames = ['plain-gray', 'plain-blue', 'plain-green', 'plain-orange',
  456. 'plain-yellow', 'plain-red', 'plain-purple', null];
  457. function updateScheme(colorsets)
  458. {
  459. function addButton(colorset)
  460. {
  461. var btn = mxUtils.button('', function(evt)
  462. {
  463. graph.getModel().beginUpdate();
  464. try
  465. {
  466. var cells = graph.getSelectionCells();
  467. for (var i = 0; i < cells.length; i++)
  468. {
  469. var style = graph.getModel().getStyle(cells[i]);
  470. for (var j = 0; j < stylenames.length; j++)
  471. {
  472. style = mxUtils.removeStylename(style, stylenames[j]);
  473. }
  474. if (colorset != null)
  475. {
  476. style = mxUtils.setStyle(style, mxConstants.STYLE_FILLCOLOR, colorset['fill']);
  477. style = mxUtils.setStyle(style, mxConstants.STYLE_STROKECOLOR, colorset['stroke']);
  478. style = mxUtils.setStyle(style, mxConstants.STYLE_GRADIENTCOLOR, colorset['gradient']);
  479. }
  480. else
  481. {
  482. style = mxUtils.setStyle(style, mxConstants.STYLE_FILLCOLOR, '#ffffff');
  483. style = mxUtils.setStyle(style, mxConstants.STYLE_STROKECOLOR, '#000000');
  484. style = mxUtils.setStyle(style, mxConstants.STYLE_GRADIENTCOLOR, null);
  485. }
  486. graph.getModel().setStyle(cells[i], style);
  487. }
  488. }
  489. finally
  490. {
  491. graph.getModel().endUpdate();
  492. }
  493. })
  494. btn.style.width = '36px';
  495. btn.style.height = '30px';
  496. btn.style.margin = '0px 6px 6px 0px';
  497. if (colorset != null)
  498. {
  499. if (colorset['gradient'] != null)
  500. {
  501. if (mxClient.IS_IE && (mxClient.IS_QUIRKS || document.documentMode < 10))
  502. {
  503. btn.style.filter = 'progid:DXImageTransform.Microsoft.Gradient('+
  504. 'StartColorStr=\'' + colorset['fill'] +
  505. '\', EndColorStr=\'' + colorset['gradient'] + '\', GradientType=0)';
  506. }
  507. else
  508. {
  509. btn.style.backgroundImage = 'linear-gradient(' + colorset['fill'] + ' 0px,' +
  510. colorset['gradient'] + ' 100%)';
  511. }
  512. }
  513. else
  514. {
  515. btn.style.backgroundColor = colorset['fill'];
  516. }
  517. btn.style.border = '1px solid ' + colorset['stroke'];
  518. }
  519. else
  520. {
  521. btn.style.backgroundColor = '#ffffff';
  522. btn.style.border = '1px solid #000000';
  523. }
  524. picker.appendChild(btn);
  525. };
  526. picker.innerHTML = '';
  527. for (var i = 0; i < colorsets.length; i++)
  528. {
  529. if (i > 0 && mxUtils.mod(i, 4) == 0)
  530. {
  531. mxUtils.br(picker);
  532. }
  533. addButton(colorsets[i]);
  534. }
  535. };
  536. if (this.editorUi.currentScheme == null)
  537. {
  538. this.editorUi.currentScheme = 0;
  539. }
  540. var schemes = [[null, {fill: '#f5f5f5', stroke: '#666666'},
  541. {fill: '#dae8fc', stroke: '#6c8ebf'}, {fill: '#d5e8d4', stroke: '#82b366'},
  542. {fill: '#ffe6cc', stroke: '#d79b00'}, {fill: '#fff2cc', stroke: '#d6b656'},
  543. {fill: '#f8cecc', stroke: '#b85450'}, {fill: '#e1d5e7', stroke: '#9673a6'}],
  544. [null,
  545. {fill: '#f5f5f5', stroke: '#666666', gradient: '#b3b3b3'},
  546. {fill: '#dae8fc', stroke: '#6c8ebf', gradient: '#7ea6e0'},
  547. {fill: '#d5e8d4', stroke: '#82b366', gradient: '#97d077'},
  548. {fill: '#ffcd28', stroke: '#d79b00', gradient: '#ffa500'},
  549. {fill: '#fff2cc', stroke: '#d6b656', gradient: '#ffd966'},
  550. {fill: '#f8cecc', stroke: '#b85450', gradient: '#ea6b66'},
  551. {fill: '#e6d0de', stroke: '#996185', gradient: '#d5739d'}],
  552. [null, {fill: '#eeeeee', stroke: '#36393d'},
  553. {fill: '#f9f7ed', stroke: '#36393d'}, {fill: '#ffcc99', stroke: '#36393d'},
  554. {fill: '#cce5ff', stroke: '#36393d'}, {fill: '#ffff88', stroke: '#36393d'},
  555. {fill: '#cdeb8b', stroke: '#36393d'}, {fill: '#ffcccc', stroke: '#36393d'}]];
  556. var left = document.createElement('div');
  557. left.style.cssText = 'position:absolute;left:10px;top:8px;bottom:8px;width:20px;margin:4px;opacity:0.5;' +
  558. 'background-repeat:no-repeat;background-position:center center;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAIVBMVEUAAAB2dnZ4eHh3d3d1dXVxcXF2dnZ2dnZ2dnZxcXF2dnYmb3w1AAAACnRSTlMAfCTkhhvb7cQSPH2JPgAAADRJREFUCNdjwACMAmBKaiGYs2oJmLPKAZ3DabU8AMRTXpUKopislqFyVzCAuUZgikkBZjoAcMYLnp53P/UAAAAASUVORK5CYII=);';
  559. div.appendChild(left);
  560. mxEvent.addListener(left, 'click', mxUtils.bind(this, function()
  561. {
  562. this.editorUi.currentScheme = mxUtils.mod(this.editorUi.currentScheme - 1, schemes.length);
  563. updateScheme(schemes[this.editorUi.currentScheme]);
  564. }));
  565. var right = document.createElement('div');
  566. right.style.cssText = 'position:absolute;left:202px;top:8px;bottom:8px;width:20px;margin:4px;opacity:0.5;' +
  567. 'background-repeat:no-repeat;background-position:center center;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAIVBMVEUAAAB2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnYBuwCcAAAACnRSTlMAfCTkhhvb7cQSPH2JPgAAADZJREFUCNdjQAOMAmBKaiGY8loF5rKswsZlrVo8AUiFrTICcbIWK8A5DF1gDoMymMPApIAwHwCS0Qx/U7qCBQAAAABJRU5ErkJggg==);';
  568. div.appendChild(right);
  569. mxEvent.addListener(right, 'click', mxUtils.bind(this, function()
  570. {
  571. this.editorUi.currentScheme = mxUtils.mod(this.editorUi.currentScheme + 1, schemes.length);
  572. updateScheme(schemes[this.editorUi.currentScheme]);
  573. }));
  574. // Hover state
  575. function addHoverState(elt)
  576. {
  577. mxEvent.addListener(elt, 'mouseenter', function()
  578. {
  579. elt.style.opacity = '1';
  580. });
  581. mxEvent.addListener(elt, 'mouseleave', function()
  582. {
  583. elt.style.opacity = '0.5';
  584. });
  585. };
  586. addHoverState(left);
  587. addHoverState(right);
  588. updateScheme(schemes[this.editorUi.currentScheme]);
  589. return div;
  590. };
  591. StyleFormatPanel.prototype.addEditOps = function(div)
  592. {
  593. var ss = this.format.getSelectionState();
  594. var btn = null;
  595. if (this.editorUi.editor.graph.getSelectionCount() == 1)
  596. {
  597. btn = mxUtils.button(mxResources.get('editStyle'), mxUtils.bind(this, function(evt)
  598. {
  599. this.editorUi.actions.get('editStyle').funct();
  600. }));
  601. btn.setAttribute('title', mxResources.get('editStyle') + ' (' + this.editorUi.actions.get('editStyle').shortcut + ')');
  602. btn.style.width = '202px';
  603. btn.style.marginBottom = '2px';
  604. div.appendChild(btn);
  605. }
  606. var graph = this.editorUi.editor.graph;
  607. var state = graph.view.getState(graph.getSelectionCell());
  608. if (graph.getSelectionCount() == 1 && state != null && state.shape != null && state.shape.stencil != null)
  609. {
  610. var btn2 = mxUtils.button(mxResources.get('editShape'), mxUtils.bind(this, function(evt)
  611. {
  612. this.editorUi.actions.get('editShape').funct();
  613. }));
  614. btn2.setAttribute('title', mxResources.get('editShape'));
  615. btn2.style.marginBottom = '2px';
  616. if (btn == null)
  617. {
  618. btn2.style.width = '202px';
  619. }
  620. else
  621. {
  622. btn.style.width = '100px';
  623. btn2.style.width = '100px';
  624. btn2.style.marginLeft = '2px';
  625. }
  626. div.appendChild(btn2);
  627. }
  628. else if (ss.image)
  629. {
  630. var btn2 = mxUtils.button(mxResources.get('editImage'), mxUtils.bind(this, function(evt)
  631. {
  632. this.editorUi.actions.get('image').funct();
  633. }));
  634. btn2.setAttribute('title', mxResources.get('editImage'));
  635. btn2.style.marginBottom = '2px';
  636. if (btn == null)
  637. {
  638. btn2.style.width = '202px';
  639. }
  640. else
  641. {
  642. btn.style.width = '100px';
  643. btn2.style.width = '100px';
  644. btn2.style.marginLeft = '2px';
  645. }
  646. div.appendChild(btn2);
  647. }
  648. return div;
  649. };
  650. }
  651. /**
  652. * Changes the default stylename so that it matches the old named style
  653. * if one was specified in the XML.
  654. */
  655. Graph.prototype.defaultThemeName = 'default-style2';
  656. /**
  657. * Contains the last XML that was pasted.
  658. */
  659. Graph.prototype.lastPasteXml = null;
  660. /**
  661. * Contains the number of times the last XML was pasted.
  662. */
  663. Graph.prototype.pasteCounter = 0;
  664. /**
  665. * Graph Overrides
  666. */
  667. Graph.prototype.defaultScrollbars = urlParams['sb'] != '0';
  668. /**
  669. * Specifies if the page should be visible for new files. Default is true.
  670. */
  671. Graph.prototype.defaultPageVisible = urlParams['pv'] != '0';
  672. /**
  673. * Specifies if the page should be visible for new files. Default is true.
  674. */
  675. Graph.prototype.shadowId = 'dropShadow';
  676. /**
  677. * Enables move of bends/segments without selecting.
  678. */
  679. Graph.prototype.edgeMode = urlParams['edge'] != 'move';
  680. /**
  681. * Adds rack child layout style.
  682. */
  683. var graphInit = Graph.prototype.init;
  684. Graph.prototype.init = function()
  685. {
  686. graphInit.apply(this, arguments);
  687. // Override insert location for current mouse point
  688. var mouseEvent = null;
  689. function setMouseEvent(evt)
  690. {
  691. mouseEvent = evt;
  692. // Workaround for member not found in IE8-
  693. if (mxClient.IS_QUIRKS || document.documentMode == 7 || document.documentMode == 8)
  694. {
  695. mouseEvent = mxUtils.clone(evt);
  696. }
  697. };
  698. mxEvent.addListener(this.container, 'mouseenter', setMouseEvent);
  699. mxEvent.addListener(this.container, 'mousemove', setMouseEvent);
  700. mxEvent.addListener(this.container, 'mouseleave', function(evt)
  701. {
  702. mouseEvent = null;
  703. });
  704. // Extends getInsertPoint to use the current mouse location
  705. this.isMouseInsertPoint = function()
  706. {
  707. return mouseEvent != null;
  708. };
  709. var getInsertPoint = this.getInsertPoint;
  710. this.getInsertPoint = function()
  711. {
  712. if (mouseEvent != null)
  713. {
  714. return this.getPointForEvent(mouseEvent);
  715. }
  716. return getInsertPoint.apply(this, arguments);
  717. };
  718. var layoutManagerGetLayout = this.layoutManager.getLayout;
  719. this.layoutManager.getLayout = function(cell)
  720. {
  721. var state = this.graph.view.getState(cell);
  722. var style = (state != null) ? state.style : this.graph.getCellStyle(cell);
  723. // mxRackContainer may be undefined as it is dynamically loaded at render time
  724. if (typeof(mxRackContainer) != 'undefined' && style['childLayout'] == 'rack')
  725. {
  726. var rackLayout = new mxStackLayout(this.graph, false);
  727. rackLayout.setChildGeometry = function(child, geo)
  728. {
  729. var unitSize = 20;
  730. geo.height = Math.max(geo.height, unitSize);
  731. if (geo.height / unitSize > 1)
  732. {
  733. var mod = geo.height % unitSize;
  734. geo.height += mod > unitSize / 2 ? (unitSize - mod) : -mod;
  735. }
  736. this.graph.getModel().setGeometry(child, geo);
  737. };
  738. rackLayout.fill = true;
  739. rackLayout.unitSize = mxRackContainer.unitSize | 20;
  740. rackLayout.marginLeft = style['marginLeft'] || 0;
  741. rackLayout.marginRight = style['marginRight'] || 0;
  742. rackLayout.marginTop = style['marginTop'] || 0;
  743. rackLayout.marginBottom = style['marginBottom'] || 0;
  744. rackLayout.resizeParent = false;
  745. return rackLayout;
  746. }
  747. return layoutManagerGetLayout.apply(this, arguments);
  748. }
  749. };
  750. /**
  751. * Sets default style (used in editor.get/setGraphXml below)
  752. */
  753. var graphLoadStylesheet = Graph.prototype.loadStylesheet;
  754. Graph.prototype.loadStylesheet = function()
  755. {
  756. graphLoadStylesheet.apply(this, arguments);
  757. this.currentStyle = 'default-style2';
  758. };
  759. /**
  760. * Loads the stylesheet for this graph.
  761. */
  762. Graph.prototype.setShadowVisible = function(value, fireEvent)
  763. {
  764. if (mxClient.IS_SVG)
  765. {
  766. fireEvent = (fireEvent != null) ? fireEvent : true;
  767. this.shadowVisible = value;
  768. if (this.shadowVisible)
  769. {
  770. this.view.getDrawPane().setAttribute('filter', 'url(#' + this.shadowId + ')');
  771. }
  772. else
  773. {
  774. this.view.getDrawPane().removeAttribute('filter');
  775. }
  776. if (fireEvent)
  777. {
  778. this.fireEvent(new mxEventObject('shadowVisibleChanged'));
  779. }
  780. }
  781. };
  782. /**
  783. * Selects first unlocked layer if one exists
  784. */
  785. Graph.prototype.selectUnlockedLayer = function()
  786. {
  787. if (this.defaultParent == null)
  788. {
  789. var childCount = this.model.getChildCount(this.model.root);
  790. var cell = null;
  791. var index = 0;
  792. do
  793. {
  794. cell = this.model.getChildAt(this.model.root, index);
  795. } while (index++ < childCount && mxUtils.getValue(this.getCellStyle(cell), 'locked', '0') == '1')
  796. if (cell != null)
  797. {
  798. this.setDefaultParent(cell);
  799. }
  800. }
  801. };
  802. /**
  803. * Specifies special libraries that are loaded via dynamic JS. Add cases
  804. * where the filename cannot be worked out from the package name. The
  805. * standard scheme for this mapping is stencils/packagename.xml. If there
  806. * are multiple XML files, any JS files or any anomalies in the filename or
  807. * directory that contains the file, then an entry must be added here and
  808. * in EmbedServlet2 for the loading of the shapes to work.
  809. */
  810. // Required to avoid 404 for mockup.xml since naming of mxgraph.mockup.anchor does not contain
  811. // buttons even though it is defined in the mxMockupButtons.js file. This could only be fixed
  812. // with aliases for existing shapes or aliases for basenames, but this is essentially the same.
  813. mxStencilRegistry.libraries['mockup'] = [SHAPES_PATH + '/mockup/mxMockupButtons.js'];
  814. mxStencilRegistry.libraries['arrows2'] = [SHAPES_PATH + '/mxArrows.js'];
  815. mxStencilRegistry.libraries['bpmn'] = [SHAPES_PATH + '/bpmn/mxBpmnShape2.js', STENCIL_PATH + '/bpmn.xml'];
  816. mxStencilRegistry.libraries['er'] = [SHAPES_PATH + '/er/mxER.js'];
  817. mxStencilRegistry.libraries['ios'] = [SHAPES_PATH + '/mockup/mxMockupiOS.js'];
  818. mxStencilRegistry.libraries['rackGeneral'] = [SHAPES_PATH + '/rack/mxRack.js', STENCIL_PATH + '/rack/general.xml'];
  819. mxStencilRegistry.libraries['rackF5'] = [STENCIL_PATH + '/rack/f5.xml'];
  820. mxStencilRegistry.libraries['lean_mapping'] = [SHAPES_PATH + '/mxLeanMap.js', STENCIL_PATH + '/lean_mapping.xml'];
  821. mxStencilRegistry.libraries['basic'] = [SHAPES_PATH + '/mxBasic.js', STENCIL_PATH + '/basic.xml'];
  822. mxStencilRegistry.libraries['ios7icons'] = [STENCIL_PATH + '/ios7/icons.xml'];
  823. mxStencilRegistry.libraries['ios7ui'] = [SHAPES_PATH + '/ios7/mxIOS7Ui.js', STENCIL_PATH + '/ios7/misc.xml'];
  824. mxStencilRegistry.libraries['android'] = [SHAPES_PATH + '/mxAndroid.js', STENCIL_PATH + '/android/android.xml'];
  825. mxStencilRegistry.libraries['electrical/transmission'] = [SHAPES_PATH + '/mxElectrical.js', STENCIL_PATH + '/electrical/transmission.xml'];
  826. mxStencilRegistry.libraries['mockup/buttons'] = [SHAPES_PATH + '/mockup/mxMockupButtons.js'];
  827. mxStencilRegistry.libraries['mockup/containers'] = [SHAPES_PATH + '/mockup/mxMockupContainers.js'];
  828. mxStencilRegistry.libraries['mockup/forms'] = [SHAPES_PATH + '/mockup/mxMockupForms.js'];
  829. mxStencilRegistry.libraries['mockup/graphics'] = [SHAPES_PATH + '/mockup/mxMockupGraphics.js', STENCIL_PATH + '/mockup/misc.xml'];
  830. mxStencilRegistry.libraries['mockup/markup'] = [SHAPES_PATH + '/mockup/mxMockupMarkup.js'];
  831. mxStencilRegistry.libraries['mockup/misc'] = [SHAPES_PATH + '/mockup/mxMockupMisc.js', STENCIL_PATH + '/mockup/misc.xml'];
  832. mxStencilRegistry.libraries['mockup/navigation'] = [SHAPES_PATH + '/mockup/mxMockupNavigation.js', STENCIL_PATH + '/mockup/misc.xml'];
  833. mxStencilRegistry.libraries['mockup/text'] = [SHAPES_PATH + '/mockup/mxMockupText.js'];
  834. mxStencilRegistry.libraries['floorplan'] = [SHAPES_PATH + '/mxFloorplan.js', STENCIL_PATH + '/floorplan.xml'];
  835. mxStencilRegistry.libraries['bootstrap'] = [SHAPES_PATH + '/mxBootstrap.js', STENCIL_PATH + '/bootstrap.xml'];
  836. mxStencilRegistry.libraries['gmdl'] = [SHAPES_PATH + '/mxGmdl.js', STENCIL_PATH + '/gmdl.xml'];
  837. mxStencilRegistry.libraries['cabinets'] = [SHAPES_PATH + '/mxCabinets.js', STENCIL_PATH + '/cabinets.xml'];
  838. mxStencilRegistry.libraries['archimate'] = [SHAPES_PATH + '/mxArchiMate.js'];
  839. mxStencilRegistry.libraries['archimate3'] = [SHAPES_PATH + '/mxArchiMate3.js'];
  840. mxStencilRegistry.libraries['sysml'] = [SHAPES_PATH + '/mxSysML.js'];
  841. mxStencilRegistry.libraries['eip'] = [SHAPES_PATH + '/mxEip.js', STENCIL_PATH + '/eip.xml'];
  842. mxStencilRegistry.libraries['networks'] = [SHAPES_PATH + '/mxNetworks.js', STENCIL_PATH + '/networks.xml'];
  843. mxStencilRegistry.libraries['aws3d'] = [SHAPES_PATH + '/mxAWS3D.js', STENCIL_PATH + '/aws3d.xml'];
  844. mxStencilRegistry.libraries['pid2inst'] = [SHAPES_PATH + '/pid2/mxPidInstruments.js'];
  845. mxStencilRegistry.libraries['pid2misc'] = [SHAPES_PATH + '/pid2/mxPidMisc.js', STENCIL_PATH + '/pid/misc.xml'];
  846. mxStencilRegistry.libraries['pid2valves'] = [SHAPES_PATH + '/pid2/mxPidValves.js'];
  847. mxStencilRegistry.libraries['pidFlowSensors'] = [STENCIL_PATH + '/pid/flow_sensors.xml'];
  848. // Triggers dynamic loading for markers
  849. mxMarker.getPackageForType = function(type)
  850. {
  851. var name = null;
  852. if (type != null && type.length > 0)
  853. {
  854. if (type.substring(0, 2) == 'ER')
  855. {
  856. name = 'mxgraph.er';
  857. }
  858. else if (type.substring(0, 5) == 'sysML')
  859. {
  860. name = 'mxgraph.sysml';
  861. }
  862. }
  863. return name;
  864. };
  865. var mxMarkerCreateMarker = mxMarker.createMarker;
  866. mxMarker.createMarker = function(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled)
  867. {
  868. if (type != null)
  869. {
  870. var f = mxMarker.markers[type];
  871. if (f == null)
  872. {
  873. var name = this.getPackageForType(type);
  874. if (name != null)
  875. {
  876. mxStencilRegistry.getStencil(name);
  877. }
  878. }
  879. }
  880. return mxMarkerCreateMarker.apply(this, arguments);
  881. };
  882. })();