Menus.js 86 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894
  1. /**
  2. * Copyright (c) 2006-2017, JGraph Ltd
  3. * Copyright (c) 2006-2017, Gaudenz Alder
  4. */
  5. (function()
  6. {
  7. // Adds scrollbars for menus that exceed the page height
  8. var mxPopupMenuShowMenu = mxPopupMenu.prototype.showMenu;
  9. mxPopupMenu.prototype.showMenu = function()
  10. {
  11. mxPopupMenuShowMenu.apply(this, arguments);
  12. this.div.style.overflowY = 'auto';
  13. this.div.style.overflowX = 'hidden';
  14. var h0 = Math.max(document.body.clientHeight, document.documentElement.clientHeight);
  15. this.div.style.maxHeight = (h0 - 10) + 'px';
  16. };
  17. Menus.prototype.createHelpLink = function(href)
  18. {
  19. var link = document.createElement('span');
  20. link.setAttribute('title', mxResources.get('help'));
  21. link.style.cssText = 'color:blue;text-decoration:underline;margin-left:8px;cursor:help;';
  22. var icon = document.createElement('img');
  23. mxUtils.setOpacity(icon, 50);
  24. icon.style.height = '16px';
  25. icon.style.width = '16px';
  26. icon.setAttribute('border', '0');
  27. icon.setAttribute('valign', 'bottom');
  28. icon.setAttribute('src', Editor.helpImage);
  29. link.appendChild(icon);
  30. mxEvent.addGestureListeners(link, mxUtils.bind(this, function(evt)
  31. {
  32. if (this.editorUi.menubar != null)
  33. {
  34. this.editorUi.menubar.hideMenu();
  35. }
  36. this.editorUi.openLink(href);
  37. mxEvent.consume(evt);
  38. }));
  39. return link;
  40. };
  41. Menus.prototype.addLinkToItem = function(item, href)
  42. {
  43. if (item != null)
  44. {
  45. item.firstChild.nextSibling.appendChild(this.createHelpLink(href));
  46. }
  47. };
  48. var menusInit = Menus.prototype.init;
  49. Menus.prototype.init = function()
  50. {
  51. menusInit.apply(this, arguments);
  52. var editorUi = this.editorUi;
  53. var graph = editorUi.editor.graph;
  54. var isGraphEnabled = mxUtils.bind(graph, graph.isEnabled);
  55. var googleEnabled = ((urlParams['embed'] != '1' && urlParams['gapi'] != '0') ||
  56. (urlParams['embed'] == '1' && urlParams['gapi'] == '1')) && mxClient.IS_SVG &&
  57. isLocalStorage && (document.documentMode == null || document.documentMode >= 10);
  58. var dropboxEnabled = ((urlParams['embed'] != '1' && urlParams['db'] != '0') || (urlParams['embed'] == '1' && urlParams['db'] == '1')) &&
  59. mxClient.IS_SVG && (document.documentMode == null || document.documentMode > 9);
  60. var oneDriveEnabled = (window.location.hostname == 'www.draw.io' || window.location.hostname == 'test.draw.io' ||
  61. window.location.hostname == 'drive.draw.io' || window.location.hostname == 'legacy.draw.io') &&
  62. (((urlParams['embed'] != '1' && urlParams['od'] != '0') || (urlParams['embed'] == '1' &&
  63. urlParams['od'] == '1')) && !navigator.userAgent.match(/(iPad|iPhone|iPod)/g) &&
  64. (navigator.userAgent.indexOf('MSIE') < 0 || document.documentMode >= 10));
  65. var trelloEnabled = ((urlParams['embed'] != '1' && urlParams['tr'] != '0') || (urlParams['embed'] == '1' && urlParams['tr'] == '1')) &&
  66. mxClient.IS_SVG && (document.documentMode == null || document.documentMode > 9);
  67. if (!mxClient.IS_SVG && !editorUi.isOffline())
  68. {
  69. var img = new Image();
  70. img.src = IMAGE_PATH + '/help.png';
  71. }
  72. editorUi.actions.addAction('new...', function()
  73. {
  74. var compact = editorUi.isOffline();
  75. var dlg = new NewDialog(editorUi, compact);
  76. editorUi.showDialog(dlg.container, (compact) ? 350 : 620, (compact) ? 70 : 440, true, true, function(cancel)
  77. {
  78. if (cancel && editorUi.getCurrentFile() == null)
  79. {
  80. editorUi.showSplash();
  81. }
  82. });
  83. dlg.init();
  84. });
  85. editorUi.actions.put('exportSvg', new Action(mxResources.get('formatSvg') + '...', function()
  86. {
  87. editorUi.showExportDialog(mxResources.get('formatSvg'), true, mxResources.get('export'),
  88. 'https://support.draw.io/display/DO/Exporting+Files',
  89. mxUtils.bind(this, function(scale, transparentBackground, ignoreSelection, addShadow,
  90. editable, embedImages, border, cropImage, currentPage, linkTarget)
  91. {
  92. var val = parseInt(scale);
  93. if (!isNaN(val) && val > 0)
  94. {
  95. editorUi.exportSvg(val / 100, transparentBackground, ignoreSelection, addShadow,
  96. editable, embedImages, border, !cropImage, currentPage, linkTarget);
  97. }
  98. }), true, null, 'svg');
  99. }));
  100. editorUi.actions.put('insertTemplate', new Action(mxResources.get('template') + '...', function()
  101. {
  102. var dlg = new NewDialog(editorUi, null, false, function(xml)
  103. {
  104. editorUi.hideDialog();
  105. if (xml != null)
  106. {
  107. graph.setSelectionCells(editorUi.importXml(xml));
  108. graph.scrollCellToVisible(graph.getSelectionCell());
  109. }
  110. }, null, null, null, null, null, null, null, null, null, null,
  111. false, mxResources.get('insert'));
  112. editorUi.showDialog(dlg.container, 620, 440, true, true);
  113. }));
  114. editorUi.actions.put('exportXml', new Action(mxResources.get('formatXml') + '...', function()
  115. {
  116. var div = document.createElement('div');
  117. div.style.whiteSpace = 'nowrap';
  118. var noPages = editorUi.pages == null || editorUi.pages.length <= 1;
  119. var hd = document.createElement('h3');
  120. mxUtils.write(hd, mxResources.get('formatXml'));
  121. hd.style.cssText = 'width:100%;text-align:center;margin-top:0px;margin-bottom:4px';
  122. div.appendChild(hd);
  123. var selection = editorUi.addCheckbox(div, mxResources.get('selectionOnly'),
  124. false, graph.isSelectionEmpty());
  125. var pages = editorUi.addCheckbox(div, mxResources.get((noPages) ? 'compressed' : 'allPages'), true);
  126. pages.style.marginBottom = '16px';
  127. mxEvent.addListener(selection, 'change', function()
  128. {
  129. if (selection.checked)
  130. {
  131. pages.setAttribute('disabled', 'disabled');
  132. }
  133. else
  134. {
  135. pages.removeAttribute('disabled');
  136. }
  137. });
  138. var dlg = new CustomDialog(editorUi, div, mxUtils.bind(this, function()
  139. {
  140. editorUi.downloadFile('xml', (noPages) ? !pages.checked : null, null,
  141. !selection.checked, (!noPages) ? !pages.checked : null);
  142. }), null, mxResources.get('export'));
  143. editorUi.showDialog(dlg.container, 300, 146, true, true);
  144. }));
  145. editorUi.actions.put('exportUrl', new Action(mxResources.get('url') + '...', function()
  146. {
  147. editorUi.showPublishLinkDialog(mxResources.get('url'), true, null, null,
  148. function(linkTarget, linkColor, allPages, lightbox, editLink, layers)
  149. {
  150. var dlg = new EmbedDialog(editorUi, editorUi.createLink(linkTarget,
  151. linkColor, allPages, lightbox, editLink, layers, null, true));
  152. editorUi.showDialog(dlg.container, 440, 240, true, true);
  153. dlg.init();
  154. });
  155. }));
  156. editorUi.actions.put('exportHtml', new Action(mxResources.get('formatHtmlEmbedded') + '...', function()
  157. {
  158. if (editorUi.spinner.spin(document.body, mxResources.get('loading')))
  159. {
  160. editorUi.getPublicUrl(editorUi.getCurrentFile(), function(url)
  161. {
  162. editorUi.spinner.stop();
  163. editorUi.showHtmlDialog(mxResources.get('export'), null, url, function(publicUrl, zoomEnabled,
  164. initialZoom, linkTarget, linkColor, fit, allPages, layers, lightbox, editLink)
  165. {
  166. editorUi.createHtml(publicUrl, zoomEnabled, initialZoom, linkTarget, linkColor,
  167. fit, allPages, layers, lightbox, editLink, mxUtils.bind(this, function(html, scriptTag)
  168. {
  169. var basename = editorUi.getBaseFilename(allPages);
  170. var result = '<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=5,IE=9" ><![endif]-->\n' +
  171. '<!DOCTYPE html>\n<html>\n<head>\n<title>' + mxUtils.htmlEntities(basename) + '</title>\n' +
  172. '<meta charset="utf-8"/>\n</head>\n<body>' + html + '\n' + scriptTag + '\n</body>\n</html>';
  173. editorUi.saveData(basename + '.html', 'html', result, 'text/html');
  174. }));
  175. });
  176. });
  177. }
  178. }));
  179. editorUi.actions.put('exportPdf', new Action(mxResources.get('formatPdf') + '...', function()
  180. {
  181. if (editorUi.isOffline() || editorUi.printPdfExport)
  182. {
  183. // Export PDF action for chrome OS (same as print with different dialog title)
  184. editorUi.showDialog(new PrintDialog(editorUi, mxResources.get('formatPdf')).container, 360,
  185. (editorUi.pages != null && editorUi.pages.length > 1) ?
  186. 420 : 360, true, true);
  187. }
  188. else
  189. {
  190. var noPages = editorUi.pages == null || editorUi.pages.length <= 1;
  191. var div = document.createElement('div');
  192. div.style.whiteSpace = 'nowrap';
  193. var hd = document.createElement('h3');
  194. mxUtils.write(hd, mxResources.get('formatPdf'));
  195. hd.style.cssText = 'width:100%;text-align:center;margin-top:0px;margin-bottom:4px';
  196. div.appendChild(hd);
  197. var cropEnableFn = function()
  198. {
  199. if (allPages != this && this.checked)
  200. {
  201. crop.removeAttribute('disabled');
  202. }
  203. else
  204. {
  205. crop.setAttribute('disabled', 'disabled');
  206. crop.checked = false;
  207. }
  208. };
  209. var dlgH = 146;
  210. if (editorUi.pdfPageExport && !noPages)
  211. {
  212. var allPages = editorUi.addRadiobox(div, 'pages', mxResources.get('allPages'), true);
  213. var currentPage = editorUi.addRadiobox(div, 'pages', mxResources.get('currentPage', null, 'Current Page'), false);
  214. var selection = editorUi.addRadiobox(div, 'pages', mxResources.get('selectionOnly'), false, graph.isSelectionEmpty());
  215. var crop = editorUi.addCheckbox(div, mxResources.get('crop'), false, true);
  216. mxEvent.addListener(allPages, 'change', cropEnableFn);
  217. mxEvent.addListener(currentPage, 'change', cropEnableFn);
  218. mxEvent.addListener(selection, 'change', cropEnableFn);
  219. dlgH = 205;
  220. }
  221. else
  222. {
  223. var selection = editorUi.addCheckbox(div, mxResources.get('selectionOnly'),
  224. false, graph.isSelectionEmpty());
  225. var crop = editorUi.addCheckbox(div, mxResources.get('crop'),
  226. !graph.pageVisible || !editorUi.pdfPageExport,
  227. !editorUi.pdfPageExport);
  228. // Crop is only enabled if selection only is selected
  229. if (!editorUi.pdfPageExport)
  230. {
  231. mxEvent.addListener(selection, 'change', cropEnableFn);
  232. }
  233. }
  234. var dlg = new CustomDialog(editorUi, div, mxUtils.bind(this, function()
  235. {
  236. editorUi.downloadFile('pdf', null, null, !selection.checked, noPages? true : !allPages.checked, !crop.checked);
  237. }), null, mxResources.get('export'));
  238. editorUi.showDialog(dlg.container, 300, dlgH, true, true);
  239. }
  240. }));
  241. editorUi.actions.addAction('open...', function()
  242. {
  243. editorUi.pickFile();
  244. });
  245. editorUi.actions.addAction('close', function()
  246. {
  247. var currentFile = editorUi.getCurrentFile();
  248. function fn()
  249. {
  250. editorUi.fileLoaded(null);
  251. };
  252. if (currentFile != null && currentFile.isModified())
  253. {
  254. editorUi.confirm(mxResources.get('allChangesLost'), null, fn,
  255. mxResources.get('cancel'), mxResources.get('discardChanges'));
  256. }
  257. else
  258. {
  259. fn();
  260. }
  261. });
  262. editorUi.actions.addAction('editShape...', mxUtils.bind(this, function()
  263. {
  264. var cells = graph.getSelectionCells();
  265. if (graph.getSelectionCount() == 1)
  266. {
  267. var cell = graph.getSelectionCell();
  268. var state = graph.view.getState(cell);
  269. if (state != null && state.shape != null && state.shape.stencil != null)
  270. {
  271. var dlg = new EditShapeDialog(editorUi, cell, mxResources.get('editShape') + ':', 630, 400);
  272. editorUi.showDialog(dlg.container, 640, 480, true, false);
  273. dlg.init();
  274. }
  275. }
  276. }));
  277. editorUi.actions.addAction('revisionHistory...', function()
  278. {
  279. var file = editorUi.getCurrentFile();
  280. if (file == null || !file.isRevisionHistorySupported())
  281. {
  282. editorUi.showError(mxResources.get('error'), mxResources.get('notAvailable'), mxResources.get('ok'));
  283. }
  284. else if (editorUi.spinner.spin(document.body, mxResources.get('loading')))
  285. {
  286. file.getRevisions(mxUtils.bind(this, function(revs)
  287. {
  288. editorUi.spinner.stop();
  289. var dlg = new RevisionDialog(editorUi, revs);
  290. editorUi.showDialog(dlg.container, 640, 480, true, true);
  291. dlg.init();
  292. }), mxUtils.bind(this, function(err)
  293. {
  294. editorUi.handleError(err);
  295. }));
  296. }
  297. });
  298. editorUi.actions.addAction('createRevision', function()
  299. {
  300. editorUi.actions.get('save').funct();
  301. }, null, null, Editor.ctrlKey + '+S');
  302. var action = editorUi.actions.addAction('synchronize', function()
  303. {
  304. editorUi.synchronizeCurrentFile(DrawioFile.SYNC == 'none');
  305. }, null, null, 'Alt+Shift+S');
  306. // Changes the label if synchronization is disabled
  307. if (DrawioFile.SYNC == 'none')
  308. {
  309. action.label = mxResources.get('refresh');
  310. }
  311. editorUi.actions.addAction('upload...', function()
  312. {
  313. var file = editorUi.getCurrentFile();
  314. if (file != null)
  315. {
  316. // Data is pulled from global variable after tab loads
  317. // LATER: Change to use message passing to deal with potential cross-domain
  318. window.drawdata = editorUi.getFileData();
  319. var filename = (file.getTitle() != null) ? file.getTitle() : editorUi.defaultFilename;
  320. editorUi.openLink(window.location.protocol + '//' + window.location.host + '/?create=drawdata&' +
  321. ((editorUi.mode == App.MODE_DROPBOX) ? 'mode=dropbox&' : '') +
  322. 'title=' + encodeURIComponent(filename), null, true);
  323. }
  324. });
  325. if (typeof(MathJax) !== 'undefined')
  326. {
  327. var action = editorUi.actions.addAction('mathematicalTypesetting', function()
  328. {
  329. var change = new ChangePageSetup(editorUi);
  330. change.ignoreColor = true;
  331. change.ignoreImage = true;
  332. change.mathEnabled = !editorUi.isMathEnabled();
  333. graph.model.execute(change);
  334. });
  335. action.setToggleAction(true);
  336. action.setSelectedCallback(function() { return editorUi.isMathEnabled(); });
  337. action.isEnabled = isGraphEnabled;
  338. }
  339. if (isLocalStorage || mxClient.IS_CHROMEAPP)
  340. {
  341. var action = editorUi.actions.addAction('showStartScreen', function()
  342. {
  343. mxSettings.setShowStartScreen(!mxSettings.getShowStartScreen());
  344. mxSettings.save();
  345. });
  346. action.setToggleAction(true);
  347. action.setSelectedCallback(function() { return mxSettings.getShowStartScreen(); });
  348. }
  349. var autosaveAction = editorUi.actions.addAction('autosave', function()
  350. {
  351. editorUi.editor.setAutosave(!editorUi.editor.autosave);
  352. });
  353. autosaveAction.setToggleAction(true);
  354. autosaveAction.setSelectedCallback(function()
  355. {
  356. return autosaveAction.isEnabled() && editorUi.editor.autosave;
  357. });
  358. editorUi.actions.addAction('editGeometry...', function()
  359. {
  360. var cells = graph.getSelectionCells();
  361. var vertices = [];
  362. for (var i = 0; i < cells.length; i++)
  363. {
  364. if (graph.getModel().isVertex(cells[i]))
  365. {
  366. vertices.push(cells[i]);
  367. }
  368. }
  369. if (vertices.length > 0)
  370. {
  371. var dlg = new EditGeometryDialog(editorUi, vertices);
  372. editorUi.showDialog(dlg.container, 200, 250, true, true);
  373. dlg.init();
  374. }
  375. }, null, null, Editor.ctrlKey + '+Shift+M');
  376. var copiedStyles = ['rounded', 'shadow', 'dashed', 'dashPattern', 'fontFamily', 'fontSize', 'fontColor', 'fontStyle',
  377. 'align', 'verticalAlign', 'strokeColor', 'strokeWidth', 'fillColor', 'gradientColor', 'swimlaneFillColor',
  378. 'textOpacity', 'gradientDirection', 'glass', 'labelBackgroundColor', 'labelBorderColor', 'opacity',
  379. 'spacing', 'spacingTop', 'spacingLeft', 'spacingBottom', 'spacingRight', 'endFill', 'endArrow',
  380. 'endSize', 'targetPerimeterSpacing', 'startFill', 'startArrow', 'startSize', 'sourcePerimeterSpacing',
  381. 'arcSize'];
  382. editorUi.actions.addAction('copyStyle', function()
  383. {
  384. var state = graph.view.getState(graph.getSelectionCell());
  385. if (graph.isEnabled() && state != null)
  386. {
  387. editorUi.copiedStyle = mxUtils.clone(state.style);
  388. // Handles special case for value "none"
  389. var cellStyle = graph.getModel().getStyle(state.cell);
  390. var tokens = (cellStyle != null) ? cellStyle.split(';') : [];
  391. for (var j = 0; j < tokens.length; j++)
  392. {
  393. var tmp = tokens[j];
  394. var pos = tmp.indexOf('=');
  395. if (pos >= 0)
  396. {
  397. var key = tmp.substring(0, pos);
  398. var value = tmp.substring(pos + 1);
  399. if (editorUi.copiedStyle[key] == null && value == 'none')
  400. {
  401. editorUi.copiedStyle[key] = 'none';
  402. }
  403. }
  404. }
  405. }
  406. }, null, null, Editor.ctrlKey + '+Shift+C');
  407. editorUi.actions.addAction('pasteStyle', function()
  408. {
  409. if (graph.isEnabled() && !graph.isSelectionEmpty() && editorUi.copiedStyle != null)
  410. {
  411. graph.getModel().beginUpdate();
  412. try
  413. {
  414. var cells = graph.getSelectionCells();
  415. for (var i = 0; i < cells.length; i++)
  416. {
  417. var state = graph.view.getState(cells[i]);
  418. for (var j = 0; j < copiedStyles.length; j++)
  419. {
  420. var key = copiedStyles[j];
  421. var value = editorUi.copiedStyle[key];
  422. if (state.style[key] != value)
  423. {
  424. graph.setCellStyles(key, value, [cells[i]]);
  425. }
  426. }
  427. }
  428. }
  429. finally
  430. {
  431. graph.getModel().endUpdate();
  432. }
  433. }
  434. }, null, null, Editor.ctrlKey + '+Shift+V');
  435. editorUi.actions.put('pageBackgroundImage', new Action(mxResources.get('backgroundImage') + '...', function()
  436. {
  437. if (!editorUi.isOffline())
  438. {
  439. var apply = function(image)
  440. {
  441. editorUi.setBackgroundImage(image);
  442. };
  443. var dlg = new BackgroundImageDialog(editorUi, apply);
  444. editorUi.showDialog(dlg.container, 320, 170, true, true);
  445. dlg.init();
  446. }
  447. }));
  448. editorUi.actions.put('exportPng', new Action(mxResources.get('formatPng') + '...', function()
  449. {
  450. if (editorUi.isExportToCanvas())
  451. {
  452. // TODO: Enable include option if CRC is fixed
  453. editorUi.showExportDialog(mxResources.get('image'), false, mxResources.get('export'),
  454. 'https://support.draw.io/display/DO/Exporting+Files',
  455. mxUtils.bind(this, function(scale, transparentBackground, ignoreSelection,
  456. addShadow, editable, embedImages, border, cropImage, currentPage)
  457. {
  458. var val = parseInt(scale);
  459. if (!isNaN(val) && val > 0)
  460. {
  461. editorUi.exportImage(val / 100, transparentBackground, ignoreSelection,
  462. addShadow, editable, border, !cropImage, currentPage);
  463. }
  464. }), true, false, 'png');
  465. }
  466. else if (!editorUi.isOffline() && (!mxClient.IS_IOS || !navigator.standalone))
  467. {
  468. editorUi.showRemoteExportDialog(mxResources.get('export'), null, mxUtils.bind(this, function(ignoreSelection, editable, transparent)
  469. {
  470. editorUi.downloadFile((editable) ? 'xmlpng' : 'png', null, null, ignoreSelection, null, null, transparent);
  471. }));
  472. }
  473. }));
  474. editorUi.actions.put('exportJpg', new Action(mxResources.get('formatJpg') + '...', function()
  475. {
  476. if (editorUi.isExportToCanvas())
  477. {
  478. editorUi.showExportDialog(mxResources.get('image'), false, mxResources.get('export'),
  479. 'https://support.draw.io/display/DO/Exporting+Files',
  480. mxUtils.bind(this, function(scale, transparentBackground, ignoreSelection,
  481. addShadow, editable, embedImages, border, cropImage, currentPage)
  482. {
  483. var val = parseInt(scale);
  484. if (!isNaN(val) && val > 0)
  485. {
  486. editorUi.exportImage(val / 100, false, ignoreSelection,
  487. addShadow, false, border, !cropImage, false, 'jpeg');
  488. }
  489. }), true, false, 'jpeg');
  490. }
  491. else if (!editorUi.isOffline() && (!mxClient.IS_IOS || !navigator.standalone))
  492. {
  493. editorUi.showRemoteExportDialog(mxResources.get('export'), null, mxUtils.bind(this, function(ignoreSelection, editable)
  494. {
  495. editorUi.downloadFile('jpeg', null, null, ignoreSelection);
  496. }), true);
  497. }
  498. }));
  499. action = editorUi.actions.put('shadowVisible', new Action(mxResources.get('shadow'), function()
  500. {
  501. graph.setShadowVisible(!graph.shadowVisible);
  502. }));
  503. action.setToggleAction(true);
  504. action.setSelectedCallback(function() { return graph.shadowVisible; });
  505. var showingAbout = false;
  506. editorUi.actions.put('about', new Action(mxResources.get('aboutDrawio') + '...', function()
  507. {
  508. if (!showingAbout)
  509. {
  510. editorUi.showDialog(new AboutDialog(editorUi).container, 220, 300, true, true, function()
  511. {
  512. showingAbout = false;
  513. });
  514. showingAbout = true;
  515. }
  516. }, null, null, 'F1'));
  517. editorUi.actions.addAction('userManual...', function()
  518. {
  519. editorUi.openLink('https://support.draw.io/display/DO/Draw.io+Online+User+Manual');
  520. });
  521. editorUi.actions.addAction('support...', function()
  522. {
  523. editorUi.openLink('https://about.draw.io/support/');
  524. });
  525. editorUi.actions.addAction('exportOptionsDisabled...', function()
  526. {
  527. editorUi.handleError({message: mxResources.get('exportOptionsDisabledDetails')},
  528. mxResources.get('exportOptionsDisabled'));
  529. });
  530. editorUi.actions.addAction('keyboardShortcuts...', function()
  531. {
  532. if (mxClient.IS_CHROMEAPP || EditorUi.isElectronApp)
  533. {
  534. editorUi.openLink('https://www.draw.io/shortcuts.svg');
  535. }
  536. else if (mxClient.IS_SVG)
  537. {
  538. editorUi.openLink('shortcuts.svg');
  539. }
  540. else
  541. {
  542. editorUi.openLink('https://www.draw.io/?lightbox=1#Uhttps%3A%2F%2Fwww.draw.io%2Fshortcuts.svg');
  543. }
  544. });
  545. editorUi.actions.addAction('feedback...', function()
  546. {
  547. var dlg = new FeedbackDialog(editorUi);
  548. editorUi.showDialog(dlg.container, 610, 360, true, true);
  549. dlg.init();
  550. });
  551. editorUi.actions.addAction('quickStart...', function()
  552. {
  553. editorUi.openLink('https://www.youtube.com/watch?v=Z0D96ZikMkc');
  554. });
  555. action = editorUi.actions.addAction('tags...', mxUtils.bind(this, function()
  556. {
  557. if (this.tagsWindow == null)
  558. {
  559. this.tagsWindow = new TagsWindow(editorUi, document.body.offsetWidth - 380, 230, 300, 120);
  560. this.tagsWindow.window.addListener('show', function()
  561. {
  562. editorUi.fireEvent(new mxEventObject('tags'));
  563. });
  564. this.tagsWindow.window.addListener('hide', function()
  565. {
  566. editorUi.fireEvent(new mxEventObject('tags'));
  567. });
  568. this.tagsWindow.window.setVisible(true);
  569. editorUi.fireEvent(new mxEventObject('tags'));
  570. }
  571. else
  572. {
  573. this.tagsWindow.window.setVisible(!this.tagsWindow.window.isVisible());
  574. }
  575. }));
  576. action.setToggleAction(true);
  577. action.setSelectedCallback(mxUtils.bind(this, function() { return this.tagsWindow != null && this.tagsWindow.window.isVisible(); }));
  578. action = editorUi.actions.addAction('find...', mxUtils.bind(this, function()
  579. {
  580. if (this.findWindow == null)
  581. {
  582. this.findWindow = new FindWindow(editorUi, document.body.offsetWidth - 300, 110, 240, 140);
  583. this.findWindow.window.addListener('show', function()
  584. {
  585. editorUi.fireEvent(new mxEventObject('find'));
  586. });
  587. this.findWindow.window.addListener('hide', function()
  588. {
  589. editorUi.fireEvent(new mxEventObject('find'));
  590. });
  591. this.findWindow.window.setVisible(true);
  592. editorUi.fireEvent(new mxEventObject('find'));
  593. }
  594. else
  595. {
  596. this.findWindow.window.setVisible(!this.findWindow.window.isVisible());
  597. }
  598. }));
  599. action.setToggleAction(true);
  600. action.setSelectedCallback(mxUtils.bind(this, function() { return this.findWindow != null && this.findWindow.window.isVisible(); }));
  601. editorUi.actions.put('exportVsdx', new Action(mxResources.get('formatVsdx') + ' (beta)...', function()
  602. {
  603. editorUi.exportVisio();
  604. }));
  605. // Adds language menu to options only if localStorage is available for
  606. // storing the choice. We do not want to use cookies for older browsers.
  607. // Note that the URL param lang=XX is available for setting the language
  608. // in older browsers. URL param has precedence over the saved setting.
  609. if (mxClient.IS_CHROMEAPP || (isLocalStorage && urlParams['offline'] != '1'))
  610. {
  611. this.put('language', new Menu(mxUtils.bind(this, function(menu, parent)
  612. {
  613. var addLangItem = mxUtils.bind(this, function (id)
  614. {
  615. var lang = (id == '') ? mxResources.get('automatic') : mxLanguageMap[id];
  616. var item = null;
  617. if (lang != '')
  618. {
  619. item = menu.addItem(lang, null, mxUtils.bind(this, function()
  620. {
  621. mxSettings.setLanguage(id);
  622. mxSettings.save();
  623. // Shows dialog in new language
  624. mxClient.language = id;
  625. mxResources.loadDefaultBundle = false;
  626. mxResources.add(RESOURCE_BASE);
  627. editorUi.alert(mxResources.get('restartForChangeRequired'));
  628. }), parent);
  629. if (id == mxLanguage || (id == '' && mxLanguage == null))
  630. {
  631. menu.addCheckmark(item, Editor.checkmarkImage);
  632. }
  633. }
  634. return item;
  635. });
  636. var item = addLangItem('');
  637. menu.addSeparator(parent);
  638. // LATER: Sort menu by language name
  639. for(var langId in mxLanguageMap)
  640. {
  641. addLangItem(langId);
  642. }
  643. })));
  644. // Extends the menubar with the language menu
  645. if (uiTheme != 'atlas')
  646. {
  647. var menusCreateMenuBar = Menus.prototype.createMenubar;
  648. Menus.prototype.createMenubar = function(container)
  649. {
  650. var menubar = menusCreateMenuBar.apply(this, arguments);
  651. if (menubar != null)
  652. {
  653. var langMenu = this.get('language');
  654. if (langMenu != null)
  655. {
  656. var elt = menubar.addMenu('', langMenu.funct);
  657. elt.setAttribute('title', mxResources.get('language'));
  658. elt.style.width = '16px';
  659. elt.style.paddingTop = '2px';
  660. elt.style.paddingLeft = '4px';
  661. elt.style.zIndex = '1';
  662. elt.style.position = 'absolute';
  663. elt.style.top = '2px';
  664. elt.style.right = '17px';
  665. elt.style.display = 'block';
  666. elt.style.cursor = 'pointer';
  667. if (!mxClient.IS_VML)
  668. {
  669. var icon = document.createElement('div');
  670. icon.style.backgroundImage = 'url(' + Editor.globeImage + ')';
  671. icon.style.backgroundPosition = 'center center';
  672. icon.style.backgroundRepeat = 'no-repeat';
  673. icon.style.backgroundSize = '19px 19px';
  674. icon.style.position = 'absolute';
  675. icon.style.height = '19px';
  676. icon.style.width = '19px';
  677. icon.style.marginTop = '2px';
  678. icon.style.zIndex = '1';
  679. elt.appendChild(icon);
  680. mxUtils.setOpacity(elt, 40);
  681. if (uiTheme == 'dark')
  682. {
  683. elt.style.filter = 'invert(100%)';
  684. }
  685. }
  686. else
  687. {
  688. elt.innerHTML = '<div class="geIcon geSprite geSprite-globe"/>';
  689. }
  690. document.body.appendChild(elt);
  691. }
  692. }
  693. return menubar;
  694. };
  695. }
  696. }
  697. this.put('help', new Menu(mxUtils.bind(this, function(menu, parent)
  698. {
  699. if (!mxClient.IS_CHROMEAPP && editorUi.isOffline())
  700. {
  701. this.addMenuItems(menu, ['about'], parent);
  702. }
  703. else
  704. {
  705. // No translation for menu item since help is english only
  706. var item = menu.addItem('Search:', null, null, parent, null, null, false);
  707. item.style.backgroundColor = (uiTheme == 'dark') ? '#505759' : 'whiteSmoke';
  708. item.style.cursor = 'default';
  709. var input = document.createElement('input');
  710. input.setAttribute('type', 'text');
  711. input.setAttribute('size', '25');
  712. input.style.marginLeft = '8px';
  713. mxEvent.addListener(input, 'keydown', mxUtils.bind(this, function(e)
  714. {
  715. var term = mxUtils.trim(input.value);
  716. if (e.keyCode == 13 && term.length > 0)
  717. {
  718. this.editorUi.openLink('https://desk.draw.io/support/search/solutions?term=' +
  719. encodeURIComponent(term));
  720. input.value = '';
  721. EditorUi.logEvent({category: 'Help', action: 'search', label: term});
  722. if (this.editorUi.menubar != null)
  723. {
  724. window.setTimeout(mxUtils.bind(this, function()
  725. {
  726. this.editorUi.menubar.hideMenu();
  727. }), 0);
  728. }
  729. }
  730. else if (e.keyCode == 27)
  731. {
  732. input.value = '';
  733. }
  734. }));
  735. item.firstChild.nextSibling.appendChild(input);
  736. mxEvent.addGestureListeners(input, function(evt)
  737. {
  738. if (document.activeElement != input)
  739. {
  740. input.focus();
  741. }
  742. mxEvent.consume(evt);
  743. }, function(evt)
  744. {
  745. mxEvent.consume(evt);
  746. }, function(evt)
  747. {
  748. mxEvent.consume(evt);
  749. });
  750. window.setTimeout(function()
  751. {
  752. input.focus();
  753. }, 0);
  754. this.addMenuItems(menu, ['-', 'quickStart', 'userManual', 'keyboardShortcuts', '-'], parent);
  755. if (!mxClient.IS_CHROMEAPP)
  756. {
  757. this.addMenuItems(menu, ['feedback'], parent);
  758. }
  759. this.addMenuItems(menu, ['support', '-'], parent);
  760. if (!editorUi.isOffline() && !EditorUi.isElectronApp &&
  761. !navigator.standalone && urlParams['embed'] != '1')
  762. {
  763. this.addMenuItems(menu, ['downloadDesktop'], parent);
  764. }
  765. if (!navigator.standalone && urlParams['embed'] != '1')
  766. {
  767. this.addMenuItems(menu, ['useOffline'], parent);
  768. }
  769. this.addMenuItems(menu, ['-', 'about'], parent);
  770. }
  771. if (urlParams['test'] == '1')
  772. {
  773. menu.addSeparator(parent);
  774. this.addSubmenu('testDevelop', menu, parent);
  775. }
  776. if (urlParams['ruler'] == '1')
  777. {
  778. mxResources.parse('rulerInch=Ruler unit: Inches');
  779. editorUi.actions.addAction('rulerInch', mxUtils.bind(this, function()
  780. {
  781. editorUi.vRuler.setUnit(mxRuler.prototype.INCHES);
  782. editorUi.hRuler.setUnit(mxRuler.prototype.INCHES);
  783. editorUi.vRuler.drawRuler(true);
  784. editorUi.hRuler.drawRuler(true);
  785. }));
  786. mxResources.parse('rulerCM=Ruler unit: CMs');
  787. editorUi.actions.addAction('rulerCM', mxUtils.bind(this, function()
  788. {
  789. editorUi.vRuler.setUnit(mxRuler.prototype.CENTIMETER);
  790. editorUi.hRuler.setUnit(mxRuler.prototype.CENTIMETER);
  791. editorUi.vRuler.drawRuler(true);
  792. editorUi.hRuler.drawRuler(true);
  793. }));
  794. mxResources.parse('rulerPixel=Ruler unit: Pixels');
  795. editorUi.actions.addAction('rulerPixel', mxUtils.bind(this, function()
  796. {
  797. editorUi.vRuler.setUnit(mxRuler.prototype.PIXELS);
  798. editorUi.hRuler.setUnit(mxRuler.prototype.PIXELS);
  799. editorUi.vRuler.drawRuler(true);
  800. editorUi.hRuler.drawRuler(true);
  801. }));
  802. this.addMenuItems(menu, ['-', 'rulerInch', 'rulerCM', 'rulerPixel'], parent);
  803. }
  804. })));
  805. // Only visible in test mode
  806. if (urlParams['test'] == '1')
  807. {
  808. mxResources.parse('testDevelop=Develop');
  809. mxResources.parse('showBoundingBox=Show bounding box');
  810. mxResources.parse('createSidebarEntry=Create Sidebar Entry');
  811. mxResources.parse('testCheckFile=Check File');
  812. mxResources.parse('testDiff=Diff');
  813. mxResources.parse('testInspect=Inspect');
  814. mxResources.parse('testShowConsole=Show Console');
  815. mxResources.parse('testXmlImageExport=XML Image Export');
  816. mxResources.parse('testDownloadRtModel=Export RT model');
  817. mxResources.parse('testImportRtModel=Import RT model');
  818. editorUi.actions.addAction('createSidebarEntry', mxUtils.bind(this, function()
  819. {
  820. if (!graph.isSelectionEmpty())
  821. {
  822. editorUi.showTextDialog('Create Sidebar Entry', 'sb.createVertexTemplateFromData(\'' +
  823. graph.compress(mxUtils.getXml(graph.encodeCells(graph.getSelectionCells()))) +
  824. '\', width, height, \'Title\');');
  825. }
  826. }));
  827. editorUi.actions.addAction('showBoundingBox', mxUtils.bind(this, function()
  828. {
  829. var b = graph.getGraphBounds();
  830. var tr = graph.view.translate;
  831. var s = graph.view.scale;
  832. graph.insertVertex(graph.getDefaultParent(), null, '',
  833. b.x / s - tr.x, b.y / s - tr.y, b.width / s, b.height / s,
  834. 'fillColor=none;strokeColor=red;');
  835. }));
  836. editorUi.actions.addAction('testCheckFile', mxUtils.bind(this, function()
  837. {
  838. var xml = (editorUi.pages != null && editorUi.getCurrentFile() != null) ?
  839. editorUi.getCurrentFile().getAnonymizedXmlForPages(editorUi.pages) : '';
  840. var dlg = new TextareaDialog(editorUi, 'Paste Data:', xml,
  841. function(newValue)
  842. {
  843. if (newValue.length > 0)
  844. {
  845. try
  846. {
  847. if (newValue.charAt(0) != '<')
  848. {
  849. newValue = graph.decompress(newValue);
  850. console.log('xml', newValue);
  851. }
  852. var doc = mxUtils.parseXml(newValue);
  853. var pages = editorUi.getPagesForNode(doc.documentElement, 'mxGraphModel');
  854. if (pages != null && pages.length > 0)
  855. {
  856. var checksum = editorUi.getHashValueForPages(pages);
  857. console.log('checksum', pages, checksum);
  858. }
  859. else
  860. {
  861. // Checks for duplicates
  862. var all = doc.getElementsByTagName('*');
  863. var allIds = {};
  864. var dups = {};
  865. for (var i = 0; i < all.length; i++)
  866. {
  867. var el = all[i];
  868. if (el.id != null)
  869. {
  870. if (allIds[el.id] == null)
  871. {
  872. allIds[el.id] = el.id;
  873. }
  874. else
  875. {
  876. dups[el.id] = el.id;
  877. }
  878. }
  879. }
  880. if (Object.keys(dups).length > 0)
  881. {
  882. console.log('duplicates', dups);
  883. }
  884. else
  885. {
  886. console.log('no duplicates');
  887. }
  888. }
  889. }
  890. catch (e)
  891. {
  892. editorUi.handleError(e);
  893. console.error(e);
  894. }
  895. }
  896. });
  897. dlg.textarea.style.width = '600px';
  898. dlg.textarea.style.height = '380px';
  899. editorUi.showDialog(dlg.container, 620, 460, true, true);
  900. dlg.init();
  901. }));
  902. editorUi.actions.addAction('testDiff', mxUtils.bind(this, function()
  903. {
  904. if (editorUi.pages != null)
  905. {
  906. var dlg = new TextareaDialog(editorUi, 'Paste Data:', '',
  907. function(newValue)
  908. {
  909. if (newValue.length > 0)
  910. {
  911. try
  912. {
  913. console.log(JSON.stringify(editorUi.diffPages(editorUi.pages,
  914. editorUi.getPagesForNode(mxUtils.parseXml(newValue).
  915. documentElement)), null, 2));
  916. }
  917. catch (e)
  918. {
  919. editorUi.handleError(e);
  920. console.error(e);
  921. }
  922. }
  923. });
  924. dlg.textarea.style.width = '600px';
  925. dlg.textarea.style.height = '380px';
  926. editorUi.showDialog(dlg.container, 620, 460, true, true);
  927. dlg.init();
  928. }
  929. else
  930. {
  931. editorUi.alert('No pages');
  932. }
  933. }));
  934. editorUi.actions.addAction('testInspect', mxUtils.bind(this, function()
  935. {
  936. console.log(editorUi, graph.getModel());
  937. }));
  938. editorUi.actions.addAction('testXmlImageExport', mxUtils.bind(this, function()
  939. {
  940. var bg = '#ffffff';
  941. var scale = 1;
  942. var b = 1;
  943. var imgExport = new mxImageExport();
  944. var bounds = graph.getGraphBounds();
  945. var vs = graph.view.scale;
  946. // New image export
  947. var xmlDoc = mxUtils.createXmlDocument();
  948. var root = xmlDoc.createElement('output');
  949. xmlDoc.appendChild(root);
  950. // Renders graph. Offset will be multiplied with state's scale when painting state.
  951. var xmlCanvas = new mxXmlCanvas2D(root);
  952. xmlCanvas.translate(Math.floor((b / scale - bounds.x) / vs), Math.floor((b / scale - bounds.y) / vs));
  953. xmlCanvas.scale(scale / vs);
  954. var stateCounter = 0;
  955. var canvasSave = xmlCanvas.save;
  956. xmlCanvas.save = function()
  957. {
  958. stateCounter++;
  959. canvasSave.apply(this, arguments);
  960. };
  961. var canvasRestore = xmlCanvas.restore;
  962. xmlCanvas.restore = function()
  963. {
  964. stateCounter--;
  965. canvasRestore.apply(this, arguments);
  966. };
  967. var exportDrawShape = imgExport.drawShape;
  968. imgExport.drawShape = function(state)
  969. {
  970. mxLog.debug('entering shape', state, stateCounter);
  971. exportDrawShape.apply(this, arguments);
  972. mxLog.debug('leaving shape', state, stateCounter);
  973. };
  974. imgExport.drawState(graph.getView().getState(graph.model.root), xmlCanvas);
  975. // Puts request data together
  976. var w = Math.ceil(bounds.width * scale / vs + 2 * b);
  977. var h = Math.ceil(bounds.height * scale / vs + 2 * b);
  978. mxLog.show();
  979. mxLog.debug(mxUtils.getXml(root));
  980. mxLog.debug('stateCounter', stateCounter);
  981. }));
  982. editorUi.actions.addAction('testDownloadRtModel...', mxUtils.bind(this, function()
  983. {
  984. if (editorUi.drive == null)
  985. {
  986. editorUi.handleError({message: mxResources.get('serviceUnavailableOrBlocked')});
  987. }
  988. else
  989. {
  990. editorUi.drive.execute(mxUtils.bind(this, function()
  991. {
  992. var fileId =prompt('File ID', '');
  993. if (fileId != null && fileId.length > 0 &&
  994. editorUi.spinner.spin(document.body, mxResources.get('export')))
  995. {
  996. // LATER: Download full model dump with history
  997. var req = new mxXmlRequest('https://www.googleapis.com/drive/v2/files/' +
  998. fileId + '/realtime?supportsTeamDrives=true', null, 'GET');
  999. // Adds auth token
  1000. req.setRequestHeaders = function(request)
  1001. {
  1002. mxXmlRequest.prototype.setRequestHeaders.apply(this, arguments);
  1003. var token = gapi.auth.getToken().access_token;
  1004. request.setRequestHeader('authorization', 'Bearer ' + token);
  1005. };
  1006. req.send(function(req)
  1007. {
  1008. editorUi.spinner.stop();
  1009. if (req.getStatus() >= 200 && req.getStatus() <= 299)
  1010. {
  1011. editorUi.saveLocalFile(req.getText(), 'json-' + fileId +'.txt', 'text/plain');
  1012. }
  1013. else
  1014. {
  1015. editorUi.handleError({message: mxResources.get('fileNotFound')},
  1016. mxResources.get('errorLoadingFile'));
  1017. }
  1018. });
  1019. }
  1020. }));
  1021. }
  1022. }));
  1023. editorUi.actions.addAction('testShowConsole', function()
  1024. {
  1025. if (!mxLog.isVisible())
  1026. {
  1027. mxLog.show();
  1028. }
  1029. else
  1030. {
  1031. mxLog.window.fit();
  1032. }
  1033. mxLog.window.div.style.zIndex = mxPopupMenu.prototype.zIndex - 1;
  1034. });
  1035. this.put('testDevelop', new Menu(mxUtils.bind(this, function(menu, parent)
  1036. {
  1037. this.addMenuItems(menu, ['createSidebarEntry', 'showBoundingBox', '-',
  1038. 'testCheckFile', 'testDiff', '-', 'testInspect', '-',
  1039. 'testXmlImageExport', '-', 'testDownloadRtModel'], parent);
  1040. menu.addItem(mxResources.get('testImportRtModel') + '...', null, function()
  1041. {
  1042. var input = document.createElement('input');
  1043. input.setAttribute('type', 'file');
  1044. mxEvent.addListener(input, 'change', mxUtils.bind(this, function()
  1045. {
  1046. if (input.files != null)
  1047. {
  1048. var reader = new FileReader();
  1049. reader.onload = mxUtils.bind(this, function(e)
  1050. {
  1051. try
  1052. {
  1053. editorUi.openLocalFile(mxUtils.getXml(editorUi.drive.convertJsonToXml(
  1054. JSON.parse(e.target.result).data)), input.files[0].name, true);
  1055. }
  1056. catch (err)
  1057. {
  1058. editorUi.handleError(err, mxResources.get('errorLoadingFile'));
  1059. }
  1060. });
  1061. reader.readAsText(input.files[0]);
  1062. }
  1063. }));
  1064. input.click();
  1065. }, parent);
  1066. this.addMenuItems(menu, ['-', 'testShowConsole'], parent);
  1067. })));
  1068. }
  1069. editorUi.actions.addAction('shapes...', function()
  1070. {
  1071. if (mxClient.IS_CHROMEAPP || !editorUi.isOffline())
  1072. {
  1073. editorUi.showDialog(new MoreShapesDialog(editorUi, true).container, 640, (isLocalStorage) ?
  1074. ((mxClient.IS_IOS) ? 480 : 460) : 440, true, true);
  1075. }
  1076. else
  1077. {
  1078. editorUi.showDialog(new MoreShapesDialog(editorUi, false).container, 360, (isLocalStorage) ?
  1079. ((mxClient.IS_IOS) ? 300 : 280) : 260, true, true);
  1080. }
  1081. });
  1082. editorUi.actions.addAction('createShape...', function()
  1083. {
  1084. var file = editorUi.getCurrentFile();
  1085. if (graph.isEnabled())
  1086. {
  1087. var cell = new mxCell('', new mxGeometry(0, 0, 120, 120), editorUi.defaultCustomShapeStyle);
  1088. cell.vertex = true;
  1089. var dlg = new EditShapeDialog(editorUi, cell, mxResources.get('editShape') + ':', 630, 400);
  1090. editorUi.showDialog(dlg.container, 640, 480, true, false);
  1091. dlg.init();
  1092. }
  1093. });
  1094. editorUi.actions.put('embedHtml', new Action(mxResources.get('html') + '...', function()
  1095. {
  1096. if (editorUi.spinner.spin(document.body, mxResources.get('loading')))
  1097. {
  1098. editorUi.getPublicUrl(editorUi.getCurrentFile(), function(url)
  1099. {
  1100. editorUi.spinner.stop();
  1101. editorUi.showHtmlDialog(mxResources.get('create'), 'https://desk.draw.io/support/solutions/articles/16000042542',
  1102. url, function(publicUrl, zoomEnabled, initialZoom, linkTarget, linkColor, fit, allPages, layers, lightbox, editLink)
  1103. {
  1104. editorUi.createHtml(publicUrl, zoomEnabled, initialZoom, linkTarget, linkColor,
  1105. fit, allPages, layers, lightbox, editLink, mxUtils.bind(this, function(html, scriptTag)
  1106. {
  1107. var dlg = new EmbedDialog(editorUi, html + '\n' + scriptTag, null, null, function()
  1108. {
  1109. var wnd = window.open();
  1110. var doc = wnd.document;
  1111. if (document.compatMode === 'CSS1Compat')
  1112. {
  1113. doc.writeln('<!DOCTYPE html>');
  1114. }
  1115. doc.writeln('<html>');
  1116. doc.writeln('<head><title>' + encodeURIComponent(mxResources.get('preview')) +
  1117. '</title><meta charset="utf-8"></head>');
  1118. doc.writeln('<body>');
  1119. doc.writeln(html);
  1120. var direct = mxClient.IS_IE || mxClient.IS_EDGE || document.documentMode != null;
  1121. if (direct)
  1122. {
  1123. doc.writeln(scriptTag);
  1124. }
  1125. doc.writeln('</body>');
  1126. doc.writeln('</html>');
  1127. doc.close();
  1128. // Adds script tag after closing page and delay to fix timing issues
  1129. if (!direct)
  1130. {
  1131. var info = wnd.document.createElement('div');
  1132. info.marginLeft = '26px';
  1133. info.marginTop = '26px';
  1134. mxUtils.write(info, mxResources.get('updatingDocument'));
  1135. var img = wnd.document.createElement('img');
  1136. img.setAttribute('src', window.location.protocol + '//' + window.location.hostname +
  1137. '/' + IMAGE_PATH + '/spin.gif');
  1138. img.style.marginLeft = '6px';
  1139. info.appendChild(img);
  1140. wnd.document.body.insertBefore(info, wnd.document.body.firstChild);
  1141. window.setTimeout(function()
  1142. {
  1143. var script = document.createElement('script');
  1144. script.type = 'text/javascript';
  1145. script.src = /<script.*?src="(.*?)"/.exec(scriptTag)[1];
  1146. doc.body.appendChild(script);
  1147. info.parentNode.removeChild(info);
  1148. }, 20);
  1149. }
  1150. });
  1151. editorUi.showDialog(dlg.container, 440, 240, true, true);
  1152. dlg.init();
  1153. }));
  1154. });
  1155. });
  1156. }
  1157. }));
  1158. editorUi.actions.put('liveImage', new Action('Live image...', function()
  1159. {
  1160. if (editorUi.spinner.spin(document.body, mxResources.get('loading')))
  1161. {
  1162. editorUi.getPublicUrl(editorUi.getCurrentFile(), function(url)
  1163. {
  1164. editorUi.spinner.stop();
  1165. if (url != null)
  1166. {
  1167. var encUrl = encodeURIComponent(url);
  1168. var dlg = new EmbedDialog(editorUi, EXPORT_URL + '?format=png&url=' + encUrl, 0);
  1169. editorUi.showDialog(dlg.container, 440, 240, true, true);
  1170. dlg.init();
  1171. }
  1172. else
  1173. {
  1174. editorUi.handleError({message: mxResources.get('invalidPublicUrl')});
  1175. }
  1176. });
  1177. }
  1178. }));
  1179. editorUi.actions.put('embedImage', new Action(mxResources.get('image') + '...', function()
  1180. {
  1181. editorUi.showEmbedImageDialog(function(fit, shadow, retina, lightbox, editLink, layers)
  1182. {
  1183. if (editorUi.spinner.spin(document.body, mxResources.get('loading')))
  1184. {
  1185. editorUi.createEmbedImage(fit, shadow, retina, lightbox, editLink, layers, function(result)
  1186. {
  1187. editorUi.spinner.stop();
  1188. var dlg = new EmbedDialog(editorUi, result);
  1189. editorUi.showDialog(dlg.container, 440, 240, true, true);
  1190. dlg.init();
  1191. }, function(err)
  1192. {
  1193. editorUi.spinner.stop();
  1194. editorUi.handleError(err);
  1195. });
  1196. }
  1197. }, mxResources.get('image'), mxResources.get('retina'), editorUi.isExportToCanvas());
  1198. }));
  1199. editorUi.actions.put('embedSvg', new Action(mxResources.get('formatSvg') + '...', function()
  1200. {
  1201. editorUi.showEmbedImageDialog(function(fit, shadow, image, lightbox, editLink, layers)
  1202. {
  1203. if (editorUi.spinner.spin(document.body, mxResources.get('loading')))
  1204. {
  1205. editorUi.createEmbedSvg(fit, shadow, image, lightbox, editLink, layers, function(result)
  1206. {
  1207. editorUi.spinner.stop();
  1208. var dlg = new EmbedDialog(editorUi, result);
  1209. editorUi.showDialog(dlg.container, 440, 240, true, true);
  1210. dlg.init();
  1211. }, function(err)
  1212. {
  1213. editorUi.spinner.stop();
  1214. editorUi.handleError(err);
  1215. });
  1216. }
  1217. }, mxResources.get('formatSvg'), mxResources.get('image'),
  1218. true, 'https://desk.draw.io/support/solutions/articles/16000042548');
  1219. }));
  1220. editorUi.actions.put('embedIframe', new Action(mxResources.get('iframe') + '...', function()
  1221. {
  1222. var bounds = graph.getGraphBounds();
  1223. editorUi.showPublishLinkDialog(mxResources.get('iframe'), null, '100%',
  1224. (Math.ceil((bounds.y + bounds.height - graph.view.translate.y) / graph.view.scale) + 2),
  1225. function(linkTarget, linkColor, allPages, lightbox, editLink, layers, width, height)
  1226. {
  1227. if (editorUi.spinner.spin(document.body, mxResources.get('loading')))
  1228. {
  1229. editorUi.getPublicUrl(editorUi.getCurrentFile(), function(url)
  1230. {
  1231. editorUi.spinner.stop();
  1232. var dlg = new EmbedDialog(editorUi, '<iframe frameborder="0" style="width:' + width +
  1233. ';height:' + height + ';" src="' + editorUi.createLink(linkTarget, linkColor,
  1234. allPages, lightbox, editLink, layers, url) + '"></iframe>');
  1235. editorUi.showDialog(dlg.container, 440, 240, true, true);
  1236. dlg.init();
  1237. });
  1238. }
  1239. }, true);
  1240. }));
  1241. editorUi.actions.put('publishLink', new Action(mxResources.get('link') + '...', function()
  1242. {
  1243. editorUi.showPublishLinkDialog(null, null, null, null,
  1244. function(linkTarget, linkColor, allPages, lightbox, editLink, layers)
  1245. {
  1246. if (editorUi.spinner.spin(document.body, mxResources.get('loading')))
  1247. {
  1248. editorUi.getPublicUrl(editorUi.getCurrentFile(), function(url)
  1249. {
  1250. editorUi.spinner.stop();
  1251. var dlg = new EmbedDialog(editorUi, editorUi.createLink(linkTarget,
  1252. linkColor, allPages, lightbox, editLink, layers, url));
  1253. editorUi.showDialog(dlg.container, 440, 240, true, true);
  1254. dlg.init();
  1255. });
  1256. }
  1257. });
  1258. }));
  1259. editorUi.actions.addAction('googleDocs...', function()
  1260. {
  1261. editorUi.openLink('http://docsaddon.draw.io');
  1262. });
  1263. editorUi.actions.addAction('googleSlides...', function()
  1264. {
  1265. editorUi.openLink('https://slidesaddon.draw.io');
  1266. });
  1267. editorUi.actions.addAction('googleSites...', function()
  1268. {
  1269. if (editorUi.spinner.spin(document.body, mxResources.get('loading')))
  1270. {
  1271. editorUi.getPublicUrl(editorUi.getCurrentFile(), function(url)
  1272. {
  1273. editorUi.spinner.stop();
  1274. var dlg = new GoogleSitesDialog(editorUi, url);
  1275. editorUi.showDialog(dlg.container, 420, 256, true, true);
  1276. dlg.init();
  1277. });
  1278. }
  1279. });
  1280. // Adds plugins menu item only if localStorage is available for storing the plugins
  1281. if (isLocalStorage || mxClient.IS_CHROMEAPP)
  1282. {
  1283. var action = editorUi.actions.addAction('scratchpad', function()
  1284. {
  1285. editorUi.toggleScratchpad();
  1286. });
  1287. action.setToggleAction(true);
  1288. action.setSelectedCallback(function() { return editorUi.scratchpad != null; });
  1289. editorUi.actions.addAction('plugins...', function()
  1290. {
  1291. editorUi.showDialog(new PluginsDialog(editorUi).container, 360, 170, true, false);
  1292. });
  1293. }
  1294. var action = editorUi.actions.addAction('search', function()
  1295. {
  1296. var visible = editorUi.sidebar.isEntryVisible('search');
  1297. editorUi.sidebar.showPalette('search', !visible);
  1298. if (isLocalStorage)
  1299. {
  1300. mxSettings.settings.search = !visible;
  1301. mxSettings.save();
  1302. }
  1303. });
  1304. action.setToggleAction(true);
  1305. action.setSelectedCallback(function() { return editorUi.sidebar.isEntryVisible('search'); });
  1306. if (urlParams['embed'] == '1')
  1307. {
  1308. editorUi.actions.get('save').funct = function(exit)
  1309. {
  1310. if (graph.isEditing())
  1311. {
  1312. graph.stopEditing();
  1313. }
  1314. var data = (urlParams['pages'] != '0' || (editorUi.pages != null && editorUi.pages.length > 1)) ?
  1315. editorUi.getFileData(true) : mxUtils.getXml(editorUi.editor.getGraphXml());
  1316. if (urlParams['proto'] == 'json')
  1317. {
  1318. var msg = editorUi.createLoadMessage('save');
  1319. msg.xml = data;
  1320. if (exit)
  1321. {
  1322. msg.exit = true;
  1323. }
  1324. data = JSON.stringify(msg);
  1325. }
  1326. var parent = window.opener || window.parent;
  1327. parent.postMessage(data, '*');
  1328. if (urlParams['modified'] != '0' && urlParams['keepmodified'] != '1')
  1329. {
  1330. editorUi.editor.modified = false;
  1331. editorUi.editor.setStatus('');
  1332. }
  1333. //Add support to saving files if embedded mode is running with files
  1334. var file = editorUi.getCurrentFile();
  1335. if (file != null)
  1336. {
  1337. editorUi.saveFile();
  1338. }
  1339. };
  1340. editorUi.actions.addAction('saveAndExit', function()
  1341. {
  1342. editorUi.actions.get('save').funct(true);
  1343. });
  1344. editorUi.actions.addAction('exit', function()
  1345. {
  1346. var fn = function()
  1347. {
  1348. editorUi.editor.modified = false;
  1349. var msg = (urlParams['proto'] == 'json') ? JSON.stringify({event: 'exit',
  1350. modified: editorUi.editor.modified}) : '';
  1351. var parent = window.opener || window.parent;
  1352. parent.postMessage(msg, '*');
  1353. }
  1354. if (!editorUi.editor.modified)
  1355. {
  1356. fn();
  1357. }
  1358. else
  1359. {
  1360. editorUi.confirm(mxResources.get('allChangesLost'), null, fn,
  1361. mxResources.get('cancel'), mxResources.get('discardChanges'));
  1362. }
  1363. });
  1364. }
  1365. this.put('exportAs', new Menu(mxUtils.bind(this, function(menu, parent)
  1366. {
  1367. if (editorUi.isExportToCanvas())
  1368. {
  1369. this.addMenuItems(menu, ['exportPng'], parent);
  1370. if (editorUi.jpgSupported)
  1371. {
  1372. this.addMenuItems(menu, ['exportJpg'], parent);
  1373. }
  1374. }
  1375. // Disabled for standalone mode in iOS because new tab cannot be closed
  1376. else if (!editorUi.isOffline() && (!mxClient.IS_IOS || !navigator.standalone))
  1377. {
  1378. this.addMenuItems(menu, ['exportPng', 'exportJpg'], parent);
  1379. }
  1380. this.addMenuItems(menu, ['exportSvg', '-'], parent);
  1381. // Redirects export to PDF to print in Chrome App
  1382. if (editorUi.isOffline() || editorUi.printPdfExport)
  1383. {
  1384. this.addMenuItems(menu, ['exportPdf'], parent);
  1385. }
  1386. // Disabled for standalone mode in iOS because new tab cannot be closed
  1387. else if (!editorUi.isOffline() && (!mxClient.IS_IOS || !navigator.standalone))
  1388. {
  1389. this.addMenuItems(menu, ['exportPdf'], parent);
  1390. }
  1391. if (!mxClient.IS_IE && (typeof(VsdxExport) !== 'undefined' || !editorUi.isOffline()))
  1392. {
  1393. this.addMenuItems(menu, ['exportVsdx'], parent);
  1394. }
  1395. this.addMenuItems(menu, ['-', 'exportHtml', 'exportXml', 'exportUrl'], parent);
  1396. if (!editorUi.isOffline())
  1397. {
  1398. menu.addSeparator(parent);
  1399. this.addMenuItem(menu, 'export', parent).firstChild.nextSibling.innerHTML = mxResources.get('advanced') + '...';
  1400. }
  1401. })));
  1402. this.put('importFrom', new Menu(mxUtils.bind(this, function(menu, parent)
  1403. {
  1404. var doImportFile = mxUtils.bind(this, function(data, mime, filename)
  1405. {
  1406. // Gets insert location
  1407. var view = graph.view;
  1408. var bds = graph.getGraphBounds();
  1409. var x = graph.snap(Math.ceil(Math.max(0, bds.x / view.scale - view.translate.x) + 4 * graph.gridSize));
  1410. var y = graph.snap(Math.ceil(Math.max(0, (bds.y + bds.height) / view.scale - view.translate.y) + 4 * graph.gridSize));
  1411. if (data.substring(0, 11) == 'data:image/')
  1412. {
  1413. editorUi.loadImage(data, mxUtils.bind(this, function(img)
  1414. {
  1415. var resizeImages = true;
  1416. var doInsert = mxUtils.bind(this, function()
  1417. {
  1418. editorUi.resizeImage(img, data, mxUtils.bind(this, function(data2, w2, h2)
  1419. {
  1420. var s = (resizeImages) ? Math.min(1, Math.min(editorUi.maxImageSize / w2, editorUi.maxImageSize / h2)) : 1;
  1421. editorUi.importFile(data, mime, x, y, Math.round(w2 * s), Math.round(h2 * s), filename, function(cells)
  1422. {
  1423. editorUi.spinner.stop();
  1424. graph.setSelectionCells(cells);
  1425. graph.scrollCellToVisible(graph.getSelectionCell());
  1426. });
  1427. }), resizeImages);
  1428. });
  1429. if (data.length > editorUi.resampleThreshold)
  1430. {
  1431. editorUi.confirmImageResize(function(doResize)
  1432. {
  1433. resizeImages = doResize;
  1434. doInsert();
  1435. });
  1436. }
  1437. else
  1438. {
  1439. doInsert();
  1440. }
  1441. }), mxUtils.bind(this, function()
  1442. {
  1443. editorUi.handleError({message: mxResources.get('cannotOpenFile')});
  1444. }));
  1445. }
  1446. else
  1447. {
  1448. editorUi.importFile(data, mime, x, y, 0, 0, filename, function(cells)
  1449. {
  1450. editorUi.spinner.stop();
  1451. graph.setSelectionCells(cells);
  1452. graph.scrollCellToVisible(graph.getSelectionCell());
  1453. });
  1454. }
  1455. });
  1456. var getMimeType = mxUtils.bind(this, function(filename)
  1457. {
  1458. var mime = 'text/xml';
  1459. if (/\.png$/i.test(filename))
  1460. {
  1461. mime = 'image/png';
  1462. }
  1463. else if (/\.jpe?g$/i.test(filename))
  1464. {
  1465. mime = 'image/jpg';
  1466. }
  1467. else if (/\.gif$/i.test(filename))
  1468. {
  1469. mime = 'image/gif';
  1470. }
  1471. return mime;
  1472. });
  1473. function pickFileFromService(service)
  1474. {
  1475. // Drive requires special arguments for libraries and bypassing realtime
  1476. service.pickFile(function(id)
  1477. {
  1478. if (editorUi.spinner.spin(document.body, mxResources.get('loading')))
  1479. {
  1480. // NOTE The third argument in getFile says denyConvert to match
  1481. // the existing signature in the original DriveClient which has
  1482. // as slightly different semantic, but works the same way.
  1483. service.getFile(id, function(file)
  1484. {
  1485. var mime = getMimeType(file.getTitle());
  1486. // Imports SVG as images
  1487. if (/\.svg$/i.test(file.getTitle()) && !editorUi.editor.isDataSvg(file.getData()))
  1488. {
  1489. file.setData(editorUi.createSvgDataUri(file.getData()));
  1490. mime = 'image/svg+xml';
  1491. }
  1492. doImportFile(file.getData(), mime, file.getTitle());
  1493. },
  1494. function(resp)
  1495. {
  1496. editorUi.handleError(resp, (resp != null) ? mxResources.get('errorLoadingFile') : null);
  1497. }, service == editorUi.drive);
  1498. }
  1499. }, true);
  1500. };
  1501. if (typeof(google) != 'undefined' && typeof(google.picker) != 'undefined')
  1502. {
  1503. if (editorUi.drive != null)
  1504. {
  1505. // Requires special arguments for libraries and realtime
  1506. menu.addItem(mxResources.get('googleDrive') + '...', null, function()
  1507. {
  1508. pickFileFromService(editorUi.drive);
  1509. }, parent);
  1510. }
  1511. else if (googleEnabled)
  1512. {
  1513. menu.addItem(mxResources.get('googleDrive') + ' (' + mxResources.get('loading') + '...)', null, function()
  1514. {
  1515. // do nothing
  1516. }, parent, null, false);
  1517. }
  1518. }
  1519. if (editorUi.oneDrive != null)
  1520. {
  1521. menu.addItem(mxResources.get('oneDrive') + '...', null, function()
  1522. {
  1523. pickFileFromService(editorUi.oneDrive);
  1524. }, parent);
  1525. }
  1526. else if (oneDriveEnabled)
  1527. {
  1528. menu.addItem(mxResources.get('oneDrive') + ' (' + mxResources.get('loading') + '...)', null, function()
  1529. {
  1530. // do nothing
  1531. }, parent, null, false);
  1532. }
  1533. if (editorUi.dropbox != null)
  1534. {
  1535. menu.addItem(mxResources.get('dropbox') + '...', null, function()
  1536. {
  1537. pickFileFromService(editorUi.dropbox);
  1538. }, parent);
  1539. }
  1540. else if (dropboxEnabled)
  1541. {
  1542. menu.addItem(mxResources.get('dropbox') + ' (' + mxResources.get('loading') + '...)', null, function()
  1543. {
  1544. // do nothing
  1545. }, parent, null, false);
  1546. }
  1547. if (editorUi.gitHub != null)
  1548. {
  1549. menu.addItem(mxResources.get('github') + '...', null, function()
  1550. {
  1551. pickFileFromService(editorUi.gitHub);
  1552. }, parent);
  1553. }
  1554. if (editorUi.trello != null)
  1555. {
  1556. menu.addItem(mxResources.get('trello') + '...', null, function()
  1557. {
  1558. pickFileFromService(editorUi.trello);
  1559. }, parent);
  1560. }
  1561. else if (trelloEnabled)
  1562. {
  1563. menu.addItem(mxResources.get('trello') + ' (' + mxResources.get('loading') + '...)', null, function()
  1564. {
  1565. // do nothing
  1566. }, parent, null, false);
  1567. }
  1568. menu.addSeparator(parent);
  1569. if (isLocalStorage && urlParams['browser'] != '0')
  1570. {
  1571. menu.addItem(mxResources.get('browser') + '...', null, function()
  1572. {
  1573. editorUi.importLocalFile(false);
  1574. }, parent);
  1575. }
  1576. menu.addItem(mxResources.get('device') + '...', null, function()
  1577. {
  1578. editorUi.importLocalFile(true);
  1579. }, parent);
  1580. if (!editorUi.isOffline())
  1581. {
  1582. menu.addSeparator(parent);
  1583. menu.addItem(mxResources.get('url') + '...', null, function()
  1584. {
  1585. var dlg = new FilenameDialog(editorUi, '', mxResources.get('import'), function(fileUrl)
  1586. {
  1587. if (fileUrl != null && fileUrl.length > 0 && editorUi.spinner.spin(document.body, mxResources.get('loading')))
  1588. {
  1589. var mime = (/(\.png)($|\?)/i.test(fileUrl)) ? 'image/png' : 'text/xml';
  1590. // Uses proxy to avoid CORS issues
  1591. editorUi.loadUrl(PROXY_URL + '?url=' + encodeURIComponent(fileUrl), function(data)
  1592. {
  1593. doImportFile(data, mime, fileUrl);
  1594. },
  1595. function ()
  1596. {
  1597. editorUi.spinner.stop();
  1598. editorUi.handleError(null, mxResources.get('errorLoadingFile'));
  1599. }, mime == 'image/png');
  1600. }
  1601. }, mxResources.get('url'));
  1602. editorUi.showDialog(dlg.container, 300, 80, true, true);
  1603. dlg.init();
  1604. }, parent);
  1605. }
  1606. }))).isEnabled = isGraphEnabled;
  1607. this.put('theme', new Menu(mxUtils.bind(this, function(menu, parent)
  1608. {
  1609. var theme = mxSettings.getUi();
  1610. var item = menu.addItem(mxResources.get('automatic'), null, function()
  1611. {
  1612. mxSettings.setUi('');
  1613. mxSettings.save();
  1614. editorUi.alert(mxResources.get('restartForChangeRequired'));
  1615. }, parent);
  1616. if (theme != 'kennedy' && theme != 'atlas' &&
  1617. theme != 'dark' && theme != 'min')
  1618. {
  1619. menu.addCheckmark(item, Editor.checkmarkImage);
  1620. }
  1621. menu.addSeparator(parent);
  1622. item = menu.addItem(mxResources.get('kennedy'), null, function()
  1623. {
  1624. mxSettings.setUi('kennedy');
  1625. mxSettings.save();
  1626. editorUi.alert(mxResources.get('restartForChangeRequired'));
  1627. }, parent);
  1628. if (theme == 'kennedy')
  1629. {
  1630. menu.addCheckmark(item, Editor.checkmarkImage);
  1631. }
  1632. item = menu.addItem(mxResources.get('minimal'), null, function()
  1633. {
  1634. mxSettings.setUi('min');
  1635. mxSettings.save();
  1636. editorUi.alert(mxResources.get('restartForChangeRequired'));
  1637. }, parent);
  1638. if (theme == 'min')
  1639. {
  1640. menu.addCheckmark(item, Editor.checkmarkImage);
  1641. }
  1642. item = menu.addItem(mxResources.get('atlas'), null, function()
  1643. {
  1644. mxSettings.setUi('atlas');
  1645. mxSettings.save();
  1646. editorUi.alert(mxResources.get('restartForChangeRequired'));
  1647. }, parent);
  1648. if (theme == 'atlas')
  1649. {
  1650. menu.addCheckmark(item, Editor.checkmarkImage);
  1651. }
  1652. item = menu.addItem(mxResources.get('dark'), null, function()
  1653. {
  1654. mxSettings.setUi('dark');
  1655. mxSettings.save();
  1656. editorUi.alert(mxResources.get('restartForChangeRequired'));
  1657. }, parent);
  1658. if (theme == 'dark')
  1659. {
  1660. menu.addCheckmark(item, Editor.checkmarkImage);
  1661. }
  1662. })));
  1663. var renameAction = this.editorUi.actions.addAction('rename...', mxUtils.bind(this, function()
  1664. {
  1665. var file = this.editorUi.getCurrentFile();
  1666. if (file != null)
  1667. {
  1668. var filename = (file.getTitle() != null) ? file.getTitle() : this.editorUi.defaultFilename;
  1669. var dlg = new FilenameDialog(this.editorUi, filename, mxResources.get('rename'), mxUtils.bind(this, function(title)
  1670. {
  1671. if (title != null && title.length > 0 && file != null && this.editorUi.spinner.spin(document.body, mxResources.get('renaming')))
  1672. {
  1673. // Delete old file, save new file in dropbox if autosize is enabled
  1674. file.rename(title, mxUtils.bind(this, function(resp)
  1675. {
  1676. this.editorUi.spinner.stop();
  1677. }),
  1678. mxUtils.bind(this, function(resp)
  1679. {
  1680. this.editorUi.handleError(resp, (resp != null) ? mxResources.get('errorRenamingFile') : null);
  1681. }));
  1682. }
  1683. }), (file.constructor == DriveFile || file.constructor == StorageFile) ?
  1684. mxResources.get('diagramName') : null, function(name)
  1685. {
  1686. if (name != null && name.length > 0)
  1687. {
  1688. return true;
  1689. }
  1690. editorUi.showError(mxResources.get('error'), mxResources.get('invalidName'), mxResources.get('ok'));
  1691. return false;
  1692. });
  1693. this.editorUi.showDialog(dlg.container, 300, 80, true, true);
  1694. dlg.init();
  1695. }
  1696. }));
  1697. renameAction.isEnabled = function()
  1698. {
  1699. return this.enabled && isGraphEnabled.apply(this, arguments);
  1700. }
  1701. renameAction.visible = urlParams['embed'] != '1';
  1702. editorUi.actions.addAction('makeCopy...', mxUtils.bind(this, function()
  1703. {
  1704. var file = editorUi.getCurrentFile();
  1705. if (file != null)
  1706. {
  1707. var title = editorUi.getCopyFilename(file);
  1708. if (file.constructor == DriveFile)
  1709. {
  1710. var dlg = new CreateDialog(editorUi, title, mxUtils.bind(this, function(newTitle, mode)
  1711. {
  1712. // Mode is "download" if Create button is pressed, means use Google Drive
  1713. if (mode == 'download')
  1714. {
  1715. mode = App.MODE_GOOGLE;
  1716. }
  1717. if (newTitle != null && newTitle.length > 0)
  1718. {
  1719. if (mode == App.MODE_GOOGLE)
  1720. {
  1721. if (editorUi.spinner.spin(document.body, mxResources.get('saving')))
  1722. {
  1723. // Saveas does not update the file descriptor in Google Drive
  1724. file.saveAs(newTitle, mxUtils.bind(this, function(resp)
  1725. {
  1726. // Replaces file descriptor in-place and saves
  1727. file.desc = resp;
  1728. // Makes sure the latest XML is in the file
  1729. file.save(false, mxUtils.bind(this, function()
  1730. {
  1731. editorUi.spinner.stop();
  1732. file.setModified(false);
  1733. file.addAllSavedStatus();
  1734. }), mxUtils.bind(this, function(resp)
  1735. {
  1736. editorUi.handleError(resp);
  1737. }));
  1738. }), mxUtils.bind(this, function(resp)
  1739. {
  1740. editorUi.handleError(resp);
  1741. }));
  1742. }
  1743. }
  1744. else
  1745. {
  1746. editorUi.createFile(newTitle, editorUi.getFileData(true), null, mode);
  1747. }
  1748. }
  1749. }), mxUtils.bind(this, function()
  1750. {
  1751. editorUi.hideDialog();
  1752. }), mxResources.get('makeCopy'), mxResources.get('create'), null,
  1753. null, null, null, true);
  1754. editorUi.showDialog(dlg.container, 420, 380, true, true);
  1755. dlg.init();
  1756. }
  1757. else
  1758. {
  1759. // Creates a copy with no predefined storage
  1760. editorUi.editor.editAsNew(this.editorUi.getFileData(true), title);
  1761. }
  1762. }
  1763. }));
  1764. editorUi.actions.addAction('moveToFolder...', mxUtils.bind(this, function()
  1765. {
  1766. var file = editorUi.getCurrentFile();
  1767. if (file.getMode() == App.MODE_GOOGLE || file.getMode() == App.MODE_ONEDRIVE)
  1768. {
  1769. editorUi.pickFolder(file.getMode(), mxUtils.bind(this, function(folderId)
  1770. {
  1771. if (editorUi.spinner.spin(document.body, mxResources.get('moving')))
  1772. {
  1773. file.move(folderId, mxUtils.bind(this, function(resp)
  1774. {
  1775. editorUi.spinner.stop();
  1776. }), mxUtils.bind(this, function(resp)
  1777. {
  1778. editorUi.handleError(resp);
  1779. }));
  1780. }
  1781. }), null, true);
  1782. }
  1783. }));
  1784. this.put('publish', new Menu(mxUtils.bind(this, function(menu, parent)
  1785. {
  1786. this.addMenuItems(menu, ['publishLink'], parent);
  1787. })));
  1788. editorUi.actions.put('useOffline', new Action(mxResources.get('useOffline') + '...', function()
  1789. {
  1790. editorUi.openLink('https://app.draw.io/')
  1791. }));
  1792. editorUi.actions.put('downloadDesktop', new Action(mxResources.get('downloadDesktop') + '...', function()
  1793. {
  1794. editorUi.openLink('https://get.draw.io/')
  1795. }));
  1796. this.editorUi.actions.addAction('share...', mxUtils.bind(this, function()
  1797. {
  1798. var file = this.editorUi.getCurrentFile();
  1799. if (file != null)
  1800. {
  1801. this.editorUi.drive.showPermissions(file.getId());
  1802. }
  1803. }));
  1804. this.put('embed', new Menu(mxUtils.bind(this, function(menu, parent)
  1805. {
  1806. if (urlParams['test'] == '1')
  1807. {
  1808. this.addMenuItems(menu, ['liveImage', '-'], parent);
  1809. }
  1810. this.addMenuItems(menu, ['embedImage', 'embedSvg', '-', 'embedHtml'], parent);
  1811. if (!navigator.standalone && !editorUi.isOffline())
  1812. {
  1813. this.addMenuItems(menu, ['embedIframe'], parent);
  1814. }
  1815. if (!editorUi.isOffline())
  1816. {
  1817. this.addMenuItems(menu, ['-', 'googleDocs', 'googleSlides', 'googleSites'], parent);
  1818. }
  1819. })));
  1820. var addInsertItem = function(menu, parent, title, method)
  1821. {
  1822. if (method != 'plantUml' || (EditorUi.enablePlantUml && !editorUi.isOffline()))
  1823. {
  1824. menu.addItem(title, null, mxUtils.bind(this, function()
  1825. {
  1826. if (method == 'fromText' || method == 'formatSql' || method == 'plantUml')
  1827. {
  1828. var dlg = new ParseDialog(editorUi, title, method);
  1829. editorUi.showDialog(dlg.container, 620, 420, true, false);
  1830. editorUi.dialog.container.style.overflow = 'auto';
  1831. dlg.init();
  1832. }
  1833. else
  1834. {
  1835. var dlg = new CreateGraphDialog(editorUi, title, method);
  1836. editorUi.showDialog(dlg.container, 620, 420, true, false);
  1837. // Executed after dialog is added to dom
  1838. dlg.init();
  1839. }
  1840. }), parent);
  1841. }
  1842. };
  1843. var insertVertex = function(value, w, h, style)
  1844. {
  1845. var pt = (graph.isMouseInsertPoint()) ? graph.getInsertPoint() : graph.getFreeInsertPoint();
  1846. var cell = new mxCell(value, new mxGeometry(pt.x, pt.y, w, h), style);
  1847. cell.vertex = true;
  1848. graph.getModel().beginUpdate();
  1849. try
  1850. {
  1851. cell = graph.addCell(cell);
  1852. graph.fireEvent(new mxEventObject('cellsInserted', 'cells', [cell]));
  1853. }
  1854. finally
  1855. {
  1856. graph.getModel().endUpdate();
  1857. }
  1858. graph.scrollCellToVisible(cell);
  1859. graph.setSelectionCell(cell);
  1860. graph.container.focus();
  1861. if (graph.editAfterInsert)
  1862. {
  1863. graph.startEditing(cell);
  1864. }
  1865. return cell;
  1866. };
  1867. editorUi.actions.put('exportSvg', new Action(mxResources.get('formatSvg') + '...', function()
  1868. {
  1869. editorUi.showExportDialog(mxResources.get('formatSvg'), true, mxResources.get('export'),
  1870. 'https://support.draw.io/display/DO/Exporting+Files',
  1871. mxUtils.bind(this, function(scale, transparentBackground, ignoreSelection, addShadow,
  1872. editable, embedImages, border, cropImage, currentPage, linkTarget)
  1873. {
  1874. var val = parseInt(scale);
  1875. if (!isNaN(val) && val > 0)
  1876. {
  1877. editorUi.exportSvg(val / 100, transparentBackground, ignoreSelection, addShadow,
  1878. editable, embedImages, border, !cropImage, currentPage, linkTarget);
  1879. }
  1880. }), true, null, 'svg');
  1881. }));
  1882. editorUi.actions.put('insertText', new Action(mxResources.get('text'), function()
  1883. {
  1884. if (graph.isEnabled() && !graph.isCellLocked(graph.getDefaultParent()))
  1885. {
  1886. graph.startEditingAtCell(insertVertex('Text', 40, 20, 'text;html=1;resizable=0;autosize=1;' +
  1887. 'align=center;verticalAlign=middle;points=[];fillColor=none;strokeColor=none;rounded=0;'));
  1888. }
  1889. }), null, null, Editor.ctrlKey + '+Shift+X').isEnabled = isGraphEnabled;
  1890. editorUi.actions.put('insertRectangle', new Action(mxResources.get('rectangle'), function()
  1891. {
  1892. if (graph.isEnabled() && !graph.isCellLocked(graph.getDefaultParent()))
  1893. {
  1894. insertVertex('', 120, 60, 'whiteSpace=wrap;html=1;');
  1895. }
  1896. }), null, null, Editor.ctrlKey + '+K').isEnabled = isGraphEnabled;
  1897. editorUi.actions.put('insertEllipse', new Action(mxResources.get('ellipse'), function()
  1898. {
  1899. if (graph.isEnabled() && !graph.isCellLocked(graph.getDefaultParent()))
  1900. {
  1901. insertVertex('', 80, 80, 'ellipse;whiteSpace=wrap;html=1;');
  1902. }
  1903. }), null, null, Editor.ctrlKey + '+Shift+K').isEnabled = isGraphEnabled;
  1904. editorUi.actions.put('insertRhombus', new Action(mxResources.get('rhombus'), function()
  1905. {
  1906. if (graph.isEnabled() && !graph.isCellLocked(graph.getDefaultParent()))
  1907. {
  1908. insertVertex('', 80, 80, 'rhombus;whiteSpace=wrap;html=1;');
  1909. }
  1910. })).isEnabled = isGraphEnabled;
  1911. var addInsertMenuItems = mxUtils.bind(this, function(menu, parent, methods)
  1912. {
  1913. for (var i = 0; i < methods.length; i++)
  1914. {
  1915. if (methods[i] == '-')
  1916. {
  1917. menu.addSeparator(parent);
  1918. }
  1919. else
  1920. {
  1921. addInsertItem(menu, parent, mxResources.get(methods[i]) + '...', methods[i]);
  1922. }
  1923. }
  1924. });
  1925. this.put('insert', new Menu(mxUtils.bind(this, function(menu, parent)
  1926. {
  1927. this.addMenuItems(menu, ['insertRectangle', 'insertEllipse', 'insertRhombus', '-',
  1928. 'insertText', 'insertLink', '-', 'insertImage'], parent);
  1929. if (editorUi.insertTemplateEnabled && !editorUi.isOffline())
  1930. {
  1931. this.addMenuItems(menu, ['insertTemplate', '-'], parent);
  1932. }
  1933. this.addSubmenu('insertLayout', menu, parent, mxResources.get('layout'));
  1934. menu.addSeparator(parent);
  1935. addInsertMenuItems(menu, parent, ['fromText', 'plantUml', '-', 'formatSql']);
  1936. menu.addItem(mxResources.get('csv') + '...', null, function()
  1937. {
  1938. editorUi.showImportCsvDialog();
  1939. }, parent);
  1940. })));
  1941. this.put('insertLayout', new Menu(mxUtils.bind(this, function(menu, parent)
  1942. {
  1943. addInsertMenuItems(menu, parent, ['horizontalFlow', 'verticalFlow', '-', 'horizontalTree',
  1944. 'verticalTree', 'radialTree', '-', 'organic', 'circle']);
  1945. })));
  1946. this.put('openRecent', new Menu(function(menu, parent)
  1947. {
  1948. var recent = editorUi.getRecent();
  1949. if (recent != null)
  1950. {
  1951. for (var i = 0; i < recent.length; i++)
  1952. {
  1953. (function(entry)
  1954. {
  1955. var modeKey = entry.mode;
  1956. // Google and oneDrive use different keys
  1957. if (modeKey == App.MODE_GOOGLE)
  1958. {
  1959. modeKey = 'googleDrive';
  1960. }
  1961. else if (modeKey == App.MODE_ONEDRIVE)
  1962. {
  1963. modeKey = 'oneDrive';
  1964. }
  1965. menu.addItem(entry.title + ' (' + mxResources.get(modeKey) + ')', null, function()
  1966. {
  1967. editorUi.loadFile(entry.id);
  1968. }, parent);
  1969. })(recent[i]);
  1970. }
  1971. menu.addSeparator(parent);
  1972. }
  1973. menu.addItem(mxResources.get('reset'), null, function()
  1974. {
  1975. editorUi.resetRecent();
  1976. }, parent);
  1977. }));
  1978. this.put('openFrom', new Menu(function(menu, parent)
  1979. {
  1980. if (editorUi.drive != null)
  1981. {
  1982. menu.addItem(mxResources.get('googleDrive') + '...', null, function()
  1983. {
  1984. editorUi.pickFile(App.MODE_GOOGLE);
  1985. }, parent);
  1986. }
  1987. else if (googleEnabled)
  1988. {
  1989. menu.addItem(mxResources.get('googleDrive') + ' (' + mxResources.get('loading') + '...)', null, function()
  1990. {
  1991. // do nothing
  1992. }, parent, null, false);
  1993. }
  1994. if (editorUi.oneDrive != null)
  1995. {
  1996. menu.addItem(mxResources.get('oneDrive') + '...', null, function()
  1997. {
  1998. editorUi.pickFile(App.MODE_ONEDRIVE);
  1999. }, parent);
  2000. }
  2001. else if (oneDriveEnabled)
  2002. {
  2003. menu.addItem(mxResources.get('oneDrive') + ' (' + mxResources.get('loading') + '...)', null, function()
  2004. {
  2005. // do nothing
  2006. }, parent, null, false);
  2007. }
  2008. if (editorUi.dropbox != null)
  2009. {
  2010. menu.addItem(mxResources.get('dropbox') + '...', null, function()
  2011. {
  2012. editorUi.pickFile(App.MODE_DROPBOX);
  2013. }, parent);
  2014. }
  2015. else if (dropboxEnabled)
  2016. {
  2017. menu.addItem(mxResources.get('dropbox') + ' (' + mxResources.get('loading') + '...)', null, function()
  2018. {
  2019. // do nothing
  2020. }, parent, null, false);
  2021. }
  2022. if (editorUi.gitHub != null)
  2023. {
  2024. menu.addItem(mxResources.get('github') + '...', null, function()
  2025. {
  2026. editorUi.pickFile(App.MODE_GITHUB);
  2027. }, parent);
  2028. }
  2029. if (editorUi.trello != null)
  2030. {
  2031. menu.addItem(mxResources.get('trello') + '...', null, function()
  2032. {
  2033. editorUi.pickFile(App.MODE_TRELLO);
  2034. }, parent);
  2035. }
  2036. else if (trelloEnabled)
  2037. {
  2038. menu.addItem(mxResources.get('trello') + ' (' + mxResources.get('loading') + '...)', null, function()
  2039. {
  2040. // do nothing
  2041. }, parent, null, false);
  2042. }
  2043. menu.addSeparator(parent);
  2044. if (isLocalStorage && urlParams['browser'] != '0')
  2045. {
  2046. menu.addItem(mxResources.get('browser') + '...', null, function()
  2047. {
  2048. editorUi.pickFile(App.MODE_BROWSER);
  2049. }, parent);
  2050. }
  2051. //if (!mxClient.IS_IOS)
  2052. {
  2053. menu.addItem(mxResources.get('device') + '...', null, function()
  2054. {
  2055. editorUi.pickFile(App.MODE_DEVICE);
  2056. }, parent);
  2057. }
  2058. if (!editorUi.isOffline())
  2059. {
  2060. menu.addSeparator(parent);
  2061. menu.addItem(mxResources.get('url') + '...', null, function()
  2062. {
  2063. var dlg = new FilenameDialog(editorUi, '', mxResources.get('open'), function(fileUrl)
  2064. {
  2065. if (fileUrl != null && fileUrl.length > 0)
  2066. {
  2067. if (editorUi.getCurrentFile() == null)
  2068. {
  2069. window.location.hash = '#U' + encodeURIComponent(fileUrl);
  2070. }
  2071. else
  2072. {
  2073. window.openWindow(((mxClient.IS_CHROMEAPP) ?
  2074. 'https://www.draw.io/' : 'https://' + location.host + '/') +
  2075. window.location.search + '#U' + encodeURIComponent(fileUrl));
  2076. }
  2077. }
  2078. }, mxResources.get('url'));
  2079. editorUi.showDialog(dlg.container, 300, 80, true, true);
  2080. dlg.init();
  2081. }, parent);
  2082. }
  2083. }));
  2084. if (Editor.enableCustomLibraries)
  2085. {
  2086. this.put('newLibrary', new Menu(function(menu, parent)
  2087. {
  2088. if (typeof(google) != 'undefined' && typeof(google.picker) != 'undefined')
  2089. {
  2090. if (editorUi.drive != null)
  2091. {
  2092. menu.addItem(mxResources.get('googleDrive') + '...', null, function()
  2093. {
  2094. editorUi.showLibraryDialog(null, null, null, null, App.MODE_GOOGLE);
  2095. }, parent);
  2096. }
  2097. else if (googleEnabled)
  2098. {
  2099. menu.addItem(mxResources.get('googleDrive') + ' (' + mxResources.get('loading') + '...)', null, function()
  2100. {
  2101. // do nothing
  2102. }, parent, null, false);
  2103. }
  2104. }
  2105. if (editorUi.oneDrive != null)
  2106. {
  2107. menu.addItem(mxResources.get('oneDrive') + '...', null, function()
  2108. {
  2109. editorUi.showLibraryDialog(null, null, null, null, App.MODE_ONEDRIVE);
  2110. }, parent);
  2111. }
  2112. else if (oneDriveEnabled)
  2113. {
  2114. menu.addItem(mxResources.get('oneDrive') + ' (' + mxResources.get('loading') + '...)', null, function()
  2115. {
  2116. // do nothing
  2117. }, parent, null, false);
  2118. }
  2119. if (editorUi.dropbox != null)
  2120. {
  2121. menu.addItem(mxResources.get('dropbox') + '...', null, function()
  2122. {
  2123. editorUi.showLibraryDialog(null, null, null, null, App.MODE_DROPBOX);
  2124. }, parent);
  2125. }
  2126. else if (dropboxEnabled)
  2127. {
  2128. menu.addItem(mxResources.get('dropbox') + ' (' + mxResources.get('loading') + '...)', null, function()
  2129. {
  2130. // do nothing
  2131. }, parent, null, false);
  2132. }
  2133. if (editorUi.gitHub != null)
  2134. {
  2135. menu.addItem(mxResources.get('github') + '...', null, function()
  2136. {
  2137. editorUi.showLibraryDialog(null, null, null, null, App.MODE_GITHUB);
  2138. }, parent);
  2139. }
  2140. if (editorUi.trello != null)
  2141. {
  2142. menu.addItem(mxResources.get('trello') + '...', null, function()
  2143. {
  2144. editorUi.showLibraryDialog(null, null, null, null, App.MODE_TRELLO);
  2145. }, parent);
  2146. }
  2147. else if (trelloEnabled)
  2148. {
  2149. menu.addItem(mxResources.get('trello') + ' (' + mxResources.get('loading') + '...)', null, function()
  2150. {
  2151. // do nothing
  2152. }, parent, null, false);
  2153. }
  2154. menu.addSeparator(parent);
  2155. if (isLocalStorage && urlParams['browser'] != '0')
  2156. {
  2157. menu.addItem(mxResources.get('browser') + '...', null, function()
  2158. {
  2159. editorUi.showLibraryDialog(null, null, null, null, App.MODE_BROWSER);
  2160. }, parent);
  2161. }
  2162. //if (!mxClient.IS_IOS)
  2163. {
  2164. menu.addItem(mxResources.get('device') + '...', null, function()
  2165. {
  2166. editorUi.showLibraryDialog(null, null, null, null, App.MODE_DEVICE);
  2167. }, parent);
  2168. }
  2169. }));
  2170. this.put('openLibraryFrom', new Menu(function(menu, parent)
  2171. {
  2172. if (typeof(google) != 'undefined' && typeof(google.picker) != 'undefined')
  2173. {
  2174. if (editorUi.drive != null)
  2175. {
  2176. menu.addItem(mxResources.get('googleDrive') + '...', null, function()
  2177. {
  2178. editorUi.pickLibrary(App.MODE_GOOGLE);
  2179. }, parent);
  2180. }
  2181. else if (googleEnabled)
  2182. {
  2183. menu.addItem(mxResources.get('googleDrive') + ' (' + mxResources.get('loading') + '...)', null, function()
  2184. {
  2185. // do nothing
  2186. }, parent, null, false);
  2187. }
  2188. }
  2189. if (editorUi.oneDrive != null)
  2190. {
  2191. menu.addItem(mxResources.get('oneDrive') + '...', null, function()
  2192. {
  2193. editorUi.pickLibrary(App.MODE_ONEDRIVE);
  2194. }, parent);
  2195. }
  2196. else if (oneDriveEnabled)
  2197. {
  2198. menu.addItem(mxResources.get('oneDrive') + ' (' + mxResources.get('loading') + '...)', null, function()
  2199. {
  2200. // do nothing
  2201. }, parent, null, false);
  2202. }
  2203. if (editorUi.dropbox != null)
  2204. {
  2205. menu.addItem(mxResources.get('dropbox') + '...', null, function()
  2206. {
  2207. editorUi.pickLibrary(App.MODE_DROPBOX);
  2208. }, parent);
  2209. }
  2210. else if (dropboxEnabled)
  2211. {
  2212. menu.addItem(mxResources.get('dropbox') + ' (' + mxResources.get('loading') + '...)', null, function()
  2213. {
  2214. // do nothing
  2215. }, parent, null, false);
  2216. }
  2217. if (editorUi.gitHub != null)
  2218. {
  2219. menu.addItem(mxResources.get('github') + '...', null, function()
  2220. {
  2221. editorUi.pickLibrary(App.MODE_GITHUB);
  2222. }, parent);
  2223. }
  2224. if (editorUi.trello != null)
  2225. {
  2226. menu.addItem(mxResources.get('trello') + '...', null, function()
  2227. {
  2228. editorUi.pickLibrary(App.MODE_TRELLO);
  2229. }, parent);
  2230. }
  2231. else if (trelloEnabled)
  2232. {
  2233. menu.addItem(mxResources.get('trello') + ' (' + mxResources.get('loading') + '...)', null, function()
  2234. {
  2235. // do nothing
  2236. }, parent, null, false);
  2237. }
  2238. menu.addSeparator(parent);
  2239. if (isLocalStorage && urlParams['browser'] != '0')
  2240. {
  2241. menu.addItem(mxResources.get('browser') + '...', null, function()
  2242. {
  2243. editorUi.pickLibrary(App.MODE_BROWSER);
  2244. }, parent);
  2245. }
  2246. //if (!mxClient.IS_IOS)
  2247. {
  2248. menu.addItem(mxResources.get('device') + '...', null, function()
  2249. {
  2250. editorUi.pickLibrary(App.MODE_DEVICE);
  2251. }, parent);
  2252. }
  2253. if (!editorUi.isOffline())
  2254. {
  2255. menu.addSeparator(parent);
  2256. menu.addItem(mxResources.get('url') + '...', null, function()
  2257. {
  2258. var dlg = new FilenameDialog(editorUi, '', mxResources.get('open'), function(fileUrl)
  2259. {
  2260. if (fileUrl != null && fileUrl.length > 0 && editorUi.spinner.spin(document.body, mxResources.get('loading')))
  2261. {
  2262. var realUrl = fileUrl;
  2263. if (!editorUi.isCorsEnabledForUrl(fileUrl))
  2264. {
  2265. realUrl = PROXY_URL + '?url=' + encodeURIComponent(fileUrl);
  2266. }
  2267. // Uses proxy to avoid CORS issues
  2268. mxUtils.get(realUrl, function(req)
  2269. {
  2270. if (req.getStatus() >= 200 && req.getStatus() <= 299)
  2271. {
  2272. editorUi.spinner.stop();
  2273. try
  2274. {
  2275. editorUi.loadLibrary(new UrlLibrary(this, req.getText(), fileUrl));
  2276. }
  2277. catch (e)
  2278. {
  2279. editorUi.handleError(e, mxResources.get('errorLoadingFile'));
  2280. }
  2281. }
  2282. else
  2283. {
  2284. editorUi.spinner.stop();
  2285. editorUi.handleError(null, mxResources.get('errorLoadingFile'));
  2286. }
  2287. }, function()
  2288. {
  2289. editorUi.spinner.stop();
  2290. editorUi.handleError(null, mxResources.get('errorLoadingFile'));
  2291. });
  2292. }
  2293. }, mxResources.get('url'));
  2294. editorUi.showDialog(dlg.container, 300, 80, true, true);
  2295. dlg.init();
  2296. }, parent);
  2297. }
  2298. }));
  2299. }
  2300. // Overrides edit menu to add find and editGeometry
  2301. this.put('edit', new Menu(mxUtils.bind(this, function(menu, parent)
  2302. {
  2303. this.addMenuItems(menu, ['undo', 'redo', '-', 'cut', 'copy', 'paste', 'delete', '-', 'duplicate', '-',
  2304. 'find', '-',
  2305. 'editData', 'editTooltip', '-', 'editStyle', 'editGeometry', '-',
  2306. 'edit', '-', 'editLink', 'openLink', '-',
  2307. 'selectVertices', 'selectEdges', 'selectAll', 'selectNone', '-', 'lockUnlock']);
  2308. })));
  2309. // Overrides view menu to add search and scratchpad
  2310. this.put('view', new Menu(mxUtils.bind(this, function(menu, parent)
  2311. {
  2312. this.addMenuItems(menu, ((this.editorUi.format != null) ? ['formatPanel'] : []).
  2313. concat(['outline', 'layers', '-']));
  2314. this.addMenuItems(menu, ['-', 'search'], parent);
  2315. if (isLocalStorage || mxClient.IS_CHROMEAPP)
  2316. {
  2317. var item = this.addMenuItem(menu, 'scratchpad', parent);
  2318. if (!editorUi.isOffline() || mxClient.IS_CHROMEAPP)
  2319. {
  2320. this.addLinkToItem(item, 'https://desk.draw.io/support/solutions/articles/16000042367');
  2321. }
  2322. }
  2323. this.addMenuItems(menu, ['shapes', '-', 'pageView', 'pageScale', '-',
  2324. 'scrollbars', 'tooltips', '-',
  2325. 'grid', 'guides'], parent);
  2326. if (mxClient.IS_SVG && (document.documentMode == null || document.documentMode > 9))
  2327. {
  2328. this.addMenuItem(menu, 'shadowVisible', parent);
  2329. }
  2330. this.addMenuItems(menu, ['-', 'connectionArrows', 'connectionPoints', '-',
  2331. 'resetView', 'zoomIn', 'zoomOut'], parent);
  2332. })));
  2333. this.put('extras', new Menu(mxUtils.bind(this, function(menu, parent)
  2334. {
  2335. if (urlParams['embed'] != '1')
  2336. {
  2337. this.addSubmenu('theme', menu, parent);
  2338. menu.addSeparator(parent);
  2339. }
  2340. this.addMenuItems(menu, ['copyConnect', 'collapseExpand', '-'], parent);
  2341. if (typeof(MathJax) !== 'undefined')
  2342. {
  2343. var item = this.addMenuItem(menu, 'mathematicalTypesetting', parent);
  2344. this.addLinkToItem(item, 'https://desk.draw.io/support/solutions/articles/16000032875');
  2345. }
  2346. if (urlParams['embed'] != '1')
  2347. {
  2348. this.addMenuItems(menu, ['autosave'], parent);
  2349. }
  2350. this.addMenuItems(menu, ['-', 'createShape', 'editDiagram'], parent);
  2351. menu.addSeparator(parent);
  2352. if (urlParams['embed'] != '1' && (isLocalStorage || mxClient.IS_CHROMEAPP))
  2353. {
  2354. this.addMenuItems(menu, ['showStartScreen'], parent);
  2355. }
  2356. if (!editorUi.isOfflineApp() && isLocalStorage)
  2357. {
  2358. this.addMenuItem(menu, 'plugins', parent);
  2359. }
  2360. menu.addSeparator(parent);
  2361. this.addMenuItem(menu, 'tags', parent);
  2362. // Adds trailing separator in case new plugin entries are added
  2363. menu.addSeparator(parent);
  2364. if (urlParams['newTempDlg'] == '1')
  2365. {
  2366. editorUi.actions.addAction('templates', function()
  2367. {
  2368. var tempDlg = new TemplatesDialog();
  2369. editorUi.showDialog(tempDlg.container, tempDlg.width, tempDlg.height, true, false, null, false, true);
  2370. tempDlg.init(editorUi, function(xml){console.log(xml)}, null,
  2371. null, null, "user", function(callback, username)
  2372. {
  2373. setTimeout(function(){
  2374. username? callback([
  2375. {url: '123', title: 'Test 1Test 1Test 1Test 1Test 1Test 1Test 11Test 1Test 11Test 1Test 1dgdsgdfg fdg dfgdfg dfg dfg'},
  2376. {url: '123', title: 'Test 2', imgUrl: 'https://www.google.com.eg/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png'},
  2377. {url: '123', title: 'Test 3', changedBy: 'Ashraf Teleb', lastModifiedOn: 'Yesterday'},
  2378. {url: '123', title: 'Test 4'},
  2379. {url: '123', title: 'Test 5'},
  2380. {url: '123', title: 'Test 6'}
  2381. ]) : callback([
  2382. {url: '123', title: 'Test 4', imgUrl: 'https://images.pexels.com/photos/459225/pexels-photo-459225.jpeg'},
  2383. {url: '123', title: 'Test 5'},
  2384. {url: '123', title: 'Test 6'},
  2385. {url: '123', title: 'Test 1Test 1Test 1Test 1Test 1Test 1Test 11Test 1Test 11Test 1Test 1dgdsgdfg fdg dfgdfg dfg dfg'},
  2386. {url: '123', title: 'Test 2', imgUrl: 'https://www.google.com.eg/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png'},
  2387. {url: '123', title: 'Test 3', changedBy: 'Ashraf Teleb', lastModifiedOn: 'Yesterday'}
  2388. ]);
  2389. console.log(username);
  2390. }, 1000);
  2391. }, function(str, callback, username)
  2392. {
  2393. setTimeout(function(){
  2394. callback(username? [
  2395. {url: '123', title: str +'Test 1Test 1Test 1Test 1Test 1Test 1Test 1'},
  2396. {url: '123', title: str +'Test 2'},
  2397. {url: '123', title: str +'Test 3'},
  2398. {url: '123', title: str +'Test 4'},
  2399. {url: '123', title: str +'Test 5'},
  2400. {url: '123', title: str +'Test 6'}
  2401. ]: [
  2402. {url: '123', title: str +'Test 5'},
  2403. {url: '123', title: str +'Test 6'},
  2404. {url: '123', title: str +'Test 1Test 1Test 1Test 1Test 1Test 1Test 1'},
  2405. {url: '123', title: str +'Test 2'},
  2406. {url: '123', title: str +'Test 3'},
  2407. {url: '123', title: str +'Test 4'}
  2408. ]);
  2409. }, 2000);
  2410. }, null);
  2411. });
  2412. this.addMenuItem(menu, 'templates', parent);
  2413. }
  2414. })));
  2415. this.put('file', new Menu(mxUtils.bind(this, function(menu, parent)
  2416. {
  2417. if (urlParams['embed'] == '1')
  2418. {
  2419. this.addSubmenu('importFrom', menu, parent);
  2420. this.addSubmenu('exportAs', menu, parent);
  2421. this.addSubmenu('embed', menu, parent);
  2422. if (urlParams['libraries'] == '1')
  2423. {
  2424. this.addMenuItems(menu, ['-'], parent);
  2425. this.addSubmenu('newLibrary', menu, parent);
  2426. this.addSubmenu('openLibraryFrom', menu, parent);
  2427. }
  2428. this.addMenuItems(menu, ['-', 'pageSetup', 'print', '-', 'rename', 'save'], parent);
  2429. if (urlParams['saveAndExit'] == '1')
  2430. {
  2431. this.addMenuItems(menu, ['saveAndExit'], parent);
  2432. }
  2433. this.addMenuItems(menu, ['exit'], parent);
  2434. }
  2435. else
  2436. {
  2437. var file = this.editorUi.getCurrentFile();
  2438. if (file != null && file.constructor == DriveFile)
  2439. {
  2440. if (file.isRestricted())
  2441. {
  2442. this.addMenuItems(menu, ['exportOptionsDisabled'], parent);
  2443. }
  2444. this.addMenuItems(menu, ['save', '-', 'share'], parent);
  2445. var item = this.addMenuItem(menu, 'synchronize', parent);
  2446. if (!editorUi.isOffline() || mxClient.IS_CHROMEAPP)
  2447. {
  2448. this.addLinkToItem(item, 'https://desk.draw.io/support/solutions/articles/16000087947');
  2449. }
  2450. menu.addSeparator(parent);
  2451. }
  2452. else
  2453. {
  2454. this.addMenuItems(menu, ['new'], parent);
  2455. }
  2456. this.addSubmenu('openFrom', menu, parent);
  2457. if (isLocalStorage)
  2458. {
  2459. this.addSubmenu('openRecent', menu, parent);
  2460. }
  2461. if (file != null && file.constructor == DriveFile)
  2462. {
  2463. this.addMenuItems(menu, ['new', '-', 'rename', 'makeCopy', 'moveToFolder'], parent);
  2464. }
  2465. else
  2466. {
  2467. if (!mxClient.IS_CHROMEAPP && !EditorUi.isElectronApp &&
  2468. file != null && file.constructor != LocalFile)
  2469. {
  2470. menu.addSeparator(parent);
  2471. var item = this.addMenuItem(menu, 'synchronize', parent);
  2472. if (!editorUi.isOffline() || mxClient.IS_CHROMEAPP)
  2473. {
  2474. this.addLinkToItem(item, 'https://desk.draw.io/support/solutions/articles/16000087947');
  2475. }
  2476. }
  2477. this.addMenuItems(menu, ['-', 'save', 'saveAs'], parent);
  2478. this.addMenuItems(menu, ['-', 'rename'], parent);
  2479. if (editorUi.isOfflineApp())
  2480. {
  2481. if (navigator.onLine && urlParams['stealth'] != '1')
  2482. {
  2483. this.addMenuItems(menu, ['upload'], parent);
  2484. }
  2485. }
  2486. else
  2487. {
  2488. this.addMenuItems(menu, ['makeCopy'], parent);
  2489. if (file != null && file.constructor == OneDriveFile)
  2490. {
  2491. this.addMenuItems(menu, ['moveToFolder'], parent);
  2492. }
  2493. }
  2494. }
  2495. menu.addSeparator(parent);
  2496. this.addSubmenu('importFrom', menu, parent);
  2497. this.addSubmenu('exportAs', menu, parent);
  2498. menu.addSeparator(parent);
  2499. this.addSubmenu('embed', menu, parent);
  2500. this.addSubmenu('publish', menu, parent);
  2501. menu.addSeparator(parent);
  2502. this.addSubmenu('newLibrary', menu, parent);
  2503. this.addSubmenu('openLibraryFrom', menu, parent);
  2504. if (file != null && file.isRevisionHistorySupported())
  2505. {
  2506. this.addMenuItems(menu, ['-', 'revisionHistory'], parent);
  2507. }
  2508. this.addMenuItems(menu, ['-', 'pageSetup'], parent);
  2509. // Cannot use print in standalone mode on iOS as we cannot open new windows
  2510. if (!mxClient.IS_IOS || !navigator.standalone)
  2511. {
  2512. this.addMenuItems(menu, ['print'], parent);
  2513. }
  2514. this.addMenuItems(menu, ['-', 'close']);
  2515. }
  2516. })));
  2517. };
  2518. })();